I have been doing some development on this project. achieving multiple connections for the client to the sever. However i am now trying to implement the admin connections through a different port number. Which will not conflict the operation to the client. I changed it so that it calls the function which then calls the operations for which the client or admin which then plays the game or admin controls. how do i call the port number to that function so it runs that code? which calls the game or admin controls? (new to coding) however i feel i need to call them at the bottom of the script....
`# Server
import socket
import math
import random
import re
import threading
#TCP_IP = '127.0.0.1'
#TCP_PORT = 4001
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#s.bind((TCP_IP, TCP_PORT))
#s.listen(5)
#print("Waiting...")
#connection check
def handle_ClientPort(port): # porting for client through threading
s.bind(("127.0.0.1",port))
s.listen(5)
while True:
(c,a) = s.accept()
t = threading.Thread(target = handle_client, args = (c,a))
t.start()
def handle_AdminPort(port): #proting for adminm connection through threading
s.bind(("127.0.0.1",port))
s.listen(5)
while True:
(c,a) = s.accept()
t = threading.Thread(target = Admin_client, args = (c,a))
t.start()
def handle_Admin(c,a): #function for admin controls
while True:
text = c.recv(80).decode()
if text == 'Who':
c.send("who has workd".encode())
elif text == 'Hello':
c.send('Admin-Greetings'.encode())
else:
c.send('please use the correct admin commands'.encode())
return
def handle_client(c,a): #This works(game)
def within(vaule,goal,n):
if abs(goal - vaule)<= n:
return True
else:
return False
while True:
rmd = random.randrange(0,30)
print('The random number is',rmd) # radom number
hello = c.recv(78).decode()
if hello == "Hello\r\n":
c.send('Greetings\r\n'.encode())
else:
c.send('ERROR\r\n'.encode())
game = c.recv(80).decode()
if game == "Game\r\n":
c.send('Ready\r\n'.encode())
else:
c.send('ERROR\r\n'.encode()) # change this
# hand shake communcation works
while True:
geuss = re.findall('\d+',c.recv(80).decode())
print(geuss)
geuss1 = int(''.join(map(str,geuss)))
print(geuss1)
checker = within(geuss1,rmd,2)
if geuss1 == rmd:
c.send("Correct\r\n".encode())
c.close()
return
elif checker == True:
c.send("Close\r\n".encode())
else:
c.send("Far\r\n".encode())
c.close()
return
admin = 4001
client = 4000
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM,)
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM,)
Related
I am getting a headache from trying to figure out where the problem is. I have a basic client and a server, the client sends a request and the server replies with an answer, the problem is, that the server does not send what is expected from him.
I would really appreciate anyone that can help me, thank you very much.
Here is the code:
client code:
def main():
import socket
my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_socket.connect(('127.0.0.1',8000))
info = input(r"Enter what you want to send to the server: ")
while info != "exit":
my_socket.send(info.encode('ascii'))
if info != "EXIT":
data_from_server = my_socket.recv(2).decode('ascii')
data_from_server = my_socket.recv(int(data_from_server))
print(data_from_server.decode('ascii'))
info = input("Enter what you want to send to the server: ")
else:
info = "exit"
my_socket.close()
if __name__ == '__main__':
main()
Here is the server code:
import socket
import sys
import time
from random import randrange
SERVER_NAME = "010101"
def number_of_elements(str):
num = 0
for e in str:
num += 1
return num
def main():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0',8000))
while True:
server_socket.listen(1)
client_socket, client_adresss = server_socket.accept()
client_request = client_socket.recv(4)
while client_request != b'EXIT':
if client_request == b'TIME':
num_of_chars = number_of_elements(time.ctime())
client_socket.send(str(num_of_chars).encode('ascii'))
client_socket.send(time.ctime().encode('ascii'))
elif client_request == b'NAME':
num_of_chars = number_of_elements(SERVER_NAME)
client_socket.send(str(num_of_chars).encode('ascii'))
client_socket.send(SERVER_NAME.encode('ascii'))
elif client_request == b'RAND':
num = 2
client_socket.send(str(num).encode('ascii'))
random_num = randrange(11)
client_socket.send(str(random_num).encode('ascii'))
else:
s = str(len("Incorrect Command"))
client_socket.send(s.encode('ascii'))
client_socket.send(b"Incorrect Command")
try:
client_request = client_socket.recv(4)
except:
client_request = b"EXIT"
client_socket.close()
server_socket.close()
if __name__ == '__main__':
main()
Here's an example
This call:
client_request = client_socket.recv(4)
Means you are asking for 4 bytes. But the socket library can, and will deliver less than that based on the behavior of TCP. And your code is not checking the number of bytes actually received.
Code your server as if it was only going to receive 1 byte at a time. And/or be prepared to invoke recv multiple times and to accumulate the number of bytes into a sequential buffer until the expected number has been received.
So I have made some code that follows. It is suppose to let a server and a client communicate... but it doesn't work.
Can someone explain why, or better yet fix my code???
Server.
import time
import socket
from threading import Thread
global sS
sS = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sS.bind(('', 2347))
sSconAddresses = []
sSconData = []
print(" Server : Running ... ")
sS.listen(10)
while True:
try:
cOn, aDr = sS.accept()
sSconAddresses.insert(0, str(aDr))
sSconData.insert(0, str(cOn))
time.sleep(0.3)
except:
time.sleep(0.1)
pass
def ConHandler():
for _ in sSconData:
PacketData = _.recv(700)
if not PacketData:
_.close()
else:
stringData = PacketData.decode('utf-8')
print(stringData)
sS.sendto(PacketData, _)
ConHandlerThread = Thread(target=ConHandler)
ConHandlerThread.daemon = True
ConHandlerThread.start()
Client.
import threading, time
import socket, sys
import os
global cS
cS = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cS.connect(('PRIVATE', 2347))
Server = ('PRIVATE', 2347)
while True:
PacketData = input(" Client> ")
ByteData = PacketData.encode('utf-8')
cS.sendto(ByteData, Server)
It doesn't return any errors so I am confused why it doesn't work.
First of all, in your server-side code, you're having a while True before starting your thread, so it can't work.
Then, if you succeed starting your thread by moving the code, its for will see an empty list, so it will not loop, and just exit right here.
Starting from your code, here's something that works:
The client:
import socket
def main():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('127.0.0.1', 2345))
while True:
packetdata = input(" Client> ")
bytedata = packetdata.encode()
client_socket.send(bytedata)
print(client_socket.recv(700).decode())
if __name__ == '__main__':
main()
The server:
import socket
from threading import Thread
from queue import Queue
def client_handler(client_socket):
while True:
data = client_socket.recv(700)
print(data)
client_socket.send("Server {}".format(data.decode()).encode())
def conn_handler(conn_queue):
while True:
conn, address = conn_queue.get()
print("Handler getting a connection from {}".format(address))
client_thread = Thread(target=client_handler, args=(conn,))
client_thread.daemon = True
client_thread.start()
def main():
print("Server: Running ...")
conn_queue = Queue()
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('', 2345))
server_socket.listen(10)
con_handler_thread = Thread(target=conn_handler, args=(conn_queue,))
con_handler_thread.daemon = True
con_handler_thread.start()
while True:
conn_queue.put(server_socket.accept())
if __name__ == '__main__':
main()
Note that this is suboptimal, starting one thread per client is not the way to go. The best way to handle this kind of situation is to keep everything in a single thread and use a select-like function to know what to do. However select is a bit limited too (like 1024 connections max, hardcoded in the libc), so the way to go is to use epoll / kqueue / whatever better than poll / select, and there's a module for this: https://docs.python.org/3/library/select.html
Yet using the select module is still the old, manual, cubersome way to express your needs, you should take a look at the coroutine based API of asyncio which enable a clear way to express the intention.
The asyncio equivalent may look like:
import asyncio
async def client():
reader, writer = await asyncio.open_connection('127.0.0.1', 8888)
while True:
message = input("Client> ")
writer.write(message.encode())
data = await reader.read(100)
print('Received: {}'.format(data.decode()))
loop = asyncio.get_event_loop()
loop.run_until_complete(client())
And, server side:
import asyncio
async def handle_client(reader, writer):
while True:
data = await reader.read(100)
if not data:
return
message = data.decode()
addr = writer.get_extra_info('peername')
print("Received %r from %r" % (message, addr))
print("Send: %r" % message)
writer.write(data)
await writer.drain()
loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_client, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)
print('Serving on {}'.format(server.sockets[0].getsockname()))
loop.run_forever()
I'm trying to create a simple chat application using sockets (python). Where a client can send a message to server and server simply broadcast the message to all other clients except the one who has sent it.
Client has two threads, which are running forever
send: Send simply sends the cleints message to server.
receive: Receive the message from the server.
Server also has two threads, which are running forever
accept_cleint: To accept the incoming connection from the client.
broadcast_usr: Accepts the message from the client and just broadcast it to all other clients.
But I'm getting erroneous output (Please refer the below image). All threads suppose to be active all the times but Some times client can send message sometimes it can not. Say for example Tracey sends 'hi' 4 times but its not broadcasted, When John says 'bye' 2 times then 1 time its message gets braodcasted. It seems like there is some thread synchronization problem at sever, I'm not sure. Please tell me what's wrong.
Below is the code.
chat_client.py
import socket, threading
def send():
while True:
msg = raw_input('\nMe > ')
cli_sock.send(msg)
def receive():
while True:
sen_name = cli_sock.recv(1024)
data = cli_sock.recv(1024)
print('\n' + str(sen_name) + ' > ' + str(data))
if __name__ == "__main__":
# socket
cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect
HOST = 'localhost'
PORT = 5023
cli_sock.connect((HOST, PORT))
print('Connected to remote host...')
uname = raw_input('Enter your name to enter the chat > ')
cli_sock.send(uname)
thread_send = threading.Thread(target = send)
thread_send.start()
thread_receive = threading.Thread(target = receive)
thread_receive.start()
chat_server.py
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
uname = cli_sock.recv(1024)
CONNECTION_LIST.append((uname, cli_sock))
print('%s is now connected' %uname)
def broadcast_usr():
while True:
for i in range(len(CONNECTION_LIST)):
try:
data = CONNECTION_LIST[i][1].recv(1024)
if data:
b_usr(CONNECTION_LIST[i][1], CONNECTION_LIST[i][0], data)
except Exception as x:
print(x.message)
break
def b_usr(cs_sock, sen_name, msg):
for i in range(len(CONNECTION_LIST)):
if (CONNECTION_LIST[i][1] != cs_sock):
CONNECTION_LIST[i][1].send(sen_name)
CONNECTION_LIST[i][1].send(msg)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5023
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
thread_bs = threading.Thread(target = broadcast_usr)
thread_bs.start()
Ok I lied in my comment earlier, sorry. The issue is actually in the broadcast_usr() function on the server. It is blocking in the recv() method and preventing all but the currently selected user from talking at a single time as it progresses through the for loop. To fix this, I changed the server.py program to spawn a new broadcast_usr thread for each client connection that it accepts. I hope this helps.
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
uname = cli_sock.recv(1024)
CONNECTION_LIST.append((uname, cli_sock))
print('%s is now connected' %uname)
thread_client = threading.Thread(target = broadcast_usr, args=[uname, cli_sock])
thread_client.start()
def broadcast_usr(uname, cli_sock):
while True:
try:
data = cli_sock.recv(1024)
if data:
print "{0} spoke".format(uname)
b_usr(cli_sock, uname, data)
except Exception as x:
print(x.message)
break
def b_usr(cs_sock, sen_name, msg):
for client in CONNECTION_LIST:
if client[1] != cs_sock:
client[1].send(sen_name)
client[1].send(msg)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5023
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
#thread_bs = threading.Thread(target = broadcast_usr)
#thread_bs.start()
I tried to get around the bug you said #Atinesh. The client will be asked a username once and this 'uname' will be included in the data to be sent. See what I did to the 'send' function.
For easier visualization, I added a '\t' to all received messages.
import socket, threading
def send(uname):
while True:
msg = raw_input('\nMe > ')
data = uname + '>' + msg
cli_sock.send(data)
def receive():
while True:
data = cli_sock.recv(1024)
print('\t'+ str(data))
if __name__ == "__main__":
# socket
cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect
HOST = 'localhost'
PORT = 5023
uname = raw_input('Enter your name to enter the chat > ')
cli_sock.connect((HOST, PORT))
print('Connected to remote host...')
thread_send = threading.Thread(target = send,args=[uname])
thread_send.start()
thread_receive = threading.Thread(target = receive)
thread_receive.start()
You also have to modify your server code accordingly.
server.py
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
CONNECTION_LIST.append(cli_sock)
thread_client = threading.Thread(target = broadcast_usr, args=[cli_sock])
thread_client.start()
def broadcast_usr(cli_sock):
while True:
try:
data = cli_sock.recv(1024)
if data:
b_usr(cli_sock, data)
except Exception as x:
print(x.message)
break
def b_usr(cs_sock, msg):
for client in CONNECTION_LIST:
if client != cs_sock:
client.send(msg)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5023
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
The things that changed in the server side are: the user who connected and the user who spoke is not seen anymore. I don't know if it would mean that much if your purpose is to connect clients. Maybe if you want to strictly monitor clients via the server, there could be another way.
My list contains IP addresses and port numbers of connected clients to my program. The admin threads role is to send each currently connected clients IP address and port number to an admin client in this string format - eg '172.0.0.1 1234'. Could I have some advise on how to send each each address so that it only shows currently connected addresses and port numbers on the admin client program.
addressList is a global variable list
Here is my code-
Server
import threading
import socket
import math
import random
import ssl
addressList = []
def within(guess,goal,n):
absValue = abs(guess - goal)
if absValue <= n:
return True
else:
return False
def HandleAdmin(adminSocket,):
global addressList
(c,a) = adminSocket.accept()
ts = ssl.wrap_socket(c, certfile="5cc515_server.crt",
keyfile="5cc515_server.key",
server_side=True,
cert_reqs=ssl.CERT_REQUIRED,
ca_certs="5cc515-root-ca.cer")
if ts.recv(80).decode() == 'Hello\r\n':
ts.send('Admin-Greetings\r\n'.encode())
if ts.recv(80).decode() == 'Who\r\n':
for addr in addressList:
ts.send(addr).encode()
ts.close()
return
def HandleClient(c,a):
global addressList
address, port = a
address = str(address) + ' ' + str(port)
addressList.append(address)
scoreCount = 0
guess = 0
if(c.recv(80).decode()) == 'Hello\r\n':
c.send('Greetings\r\n'.encode())
goal = random.randrange(1,21)
while guess!= goal:
guess =c.recv(80).decode()
guess = int(guess[7:len(guess)-2])
if guess == goal:
c.send('Correct\r\n'.encode())
elif within(guess, goal, 2) == True:
c.send('Close\r\n'.encode())
else:
c.send('Far\r\n'.encode())
c.close()
return
clientSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clientSocket.bind(("127.0.0.1",4000))
clientSocket.listen(5)
adminSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
adminSocket.bind(("127.0.0.1",4001))
adminSocket.listen(5)
handleAdminThread = threading.Thread(target = HandleAdmin,
args = (adminSocket,))
handleAdminThread.start()
while True:
(c,a) = clientSocket.accept()
clientThread = threading.Thread(target = HandleClient, args = (c,a))
clientThread.start()
Admin Client
import ssl
import socket
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ts = ssl.wrap_socket(s, certfile="100298750.crt",
keyfile="100298750.key",
ca_certs="5cc515-root-ca.cer")
ts.connect(('127.0.0.1', 4001))
ts.send("Hello\r\n".encode())
addressList = []
if ts.recv(80).decode() == "Admin-Greetings\r\n":
print("The players currently playing are:\n\n")
ts.send("Who\r\n".encode())
while True:
print(ts.recv(80).decode())
In your HandleClient function, c.close() means the client has disconnected.
So, to let your admin know they did, you have to remove that address from the 'addressList' (since when you send "Who\r\n" your addressList list is referred to).
So, after c.close() you should write:
addressList.remove(address)
I am writing a echo server and client in Python, that implements a simple number guessing game. I know how to multiplex using select, that's fine. The other server I wrote achieves this. But now I am writing a new server (which is fairly similar), however it accepts connections from two ports rather than one, one port for player client, and one for admin which I will use eventually for the who command, returning all connected players.
My problem is, that after sending the initial greetings message, the clients receive feedback from the server on the first send, recv. But after that I cannot send any more messages to server (nothing gets sent from the clients), I have been searching and playing around for hours, to no avail. Any help would be appreciated. Thanks!
# MULTIPLEX SERVER
import socket, select, time, random, ssl, sys, os
# VARS
EXP = 1
HOST = '127.0.0.1'
PORT_P = 4000
PORT_A = 4001
BUFFSZ = 1024
BKLOG = 5
GREETS = 'Greetings'
INPUTS = []
OUTPUTS = []
CLIENT_ADDRS = {}
CLIENT_ANS = {}
CLIENTS = ""
_adm_rtnMSG = 'Admin_Greetings'
# Function to determine how far the player is
# from the chosen random number
def Within(value, target):
diff = abs(target - value)
if diff > 3:
return 'Not even close, youth!'
else:
return 'Ooh, not to far: ' + str(diff) + ' away, keep trying...'
# END_FUNCTION
print('Server up and running...\n')
try:
for p in PORT_P, PORT_A:
INPUTS.append(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
INPUTS[-1].setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
INPUTS[-1].bind((HOST, p))
INPUTS[-1].listen(BKLOG)
except socket.error(value, message):
if INPUTS[-1]:
INPUTS[-1].close()
INPUTS = INPUTS[:-1]
print('Failure to open socket: ' + message)
sys.exit(1)
while True:
READ_IO, WRITE_IO, ERROR = select.select(INPUTS, OUTPUTS, INPUTS)
for r in READ_IO:
for p in INPUTS:
if r is p:
(acpt_sock, addr) = p.accept()
print('Connection established with ', acpt_sock.getsockname())
CLIENT_ADDRS[acpt_sock] = addr
CLIENT_ANS[acpt_sock] = random.randrange(1, 20)
else:
data = acpt_sock.recv(BUFFSZ).decode()
acpt_sock.setblocking(0)
if data:
if 'Hello' in data:
print(CLIENT_ADDRS[acpt_sock], ' random number is: ', CLIENT_ANS[acpt_sock])
acpt_sock.send(b'Greetings\nGuess a random number between 1 & 20')
# drop elif here for admin cmd
elif 'Hi' in data:
acpt_sock.send(_adm_rtnMSG.encode())
else:
if int(data) == CLIENT_ANS[acpt_sock]:
acpt_sock.send(b'That was correct, Well done!')
else:
acpt_sock.send(str(Within(int(data), CLIENT_ANS[acpt_sock])).encode())
else:
print('Closing Connection # ', addr)
INPUTS.remove(acpt_sock)
acpt_sock.close()
del CLIENT_ADDRS[acpt_sock]
# PLAYER CLIENT
import socket
import re
# INIT VARS
HOST = '127.0.0.1'
PORT = 4000
INITSTR = 'Hello'
BUFF = 1024
# Set up socket
sender = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sender.connect((HOST, PORT))
sender.send(bytes((INITSTR), "ascii"))
print("Kirby Prompt FTW!\nConnected to Server via", HOST, "::", PORT, '\n')
rtnMSG = sender.recv(BUFF).decode()
print(rtnMSG)
# Simple loop to keep client alive
# to send and receive data from the server
while 'correct' not in rtnMSG:
_guess = input("(>',')> ")
sender.send(bytes((_guess), "ascii"))
rtnMSG = sender.recv(BUFF).decode()
print(rtnMSG)
sender.close()
# ADMIN CLIENT
import socket
import re
import ssl
# INIT VARS
HOST = '127.0.0.1'
PORT = 4001
INITSTR = 'Hi'
BUFF = 1024
# Set up socket
adm_sender = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
adm_sender.connect((HOST, PORT))
adm_sender.send(bytes((INITSTR), "ascii"))
print("Connected to Server as Admin via", HOST, "::", PORT, '\n')
rtnMSG = adm_sender.recv(BUFF).decode()
print(rtnMSG)
while True:
cmd = input('$ ')
adm_sender.send(bytes((cmd), "ascii"))
rtnMSG = adm_sender.recv(BUFF).decode()
print(rtnMSG)
adm_sender.close()