I have to make a multi-client chat room with TCPServer provided by serversocket module in Python. How do i make this into a multi-client server and send the message to all other client?
I have try to modify the existing code from the example
...python
import socket
import threading
import socketserver
clientList = []
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
clientList.append(self.client_address)
print(clientList)
print("Client List Length : ",len(clientList))
while True:
data = str(self.request.recv(1024), 'ascii')
if(data.upper() == "EXIT"):
break
cur_thread = threading.current_thread()
response = bytes(data, 'utf_8')
#self.request.sendall(response)
for cl in range(1,len(clientList)):
print("sending to : ",clientList[cl])
self.request.sendto(response,clientList[cl])
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def passtime():
pass
if __name__ == "__main__":
HOST, PORT = "localhost", 50007
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
while server_thread:
passtime()
print("Server loop running in thread:", server_thread.name)
...
I have a problem with :
self.request.sendto(request,clientList[cl])
Only send the request back to the sending client and not the targeted client in the client list.
Edit: I found a Solution, here is it:
import socket
import threading
import socketserver
import sys
import select
clientList = []
inbox = []
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
clients = []
msgSend = 0
def setup(self):
clientList.append(self.client_address)
self.clients = list(dict.fromkeys(clientList))
print(self.clients)
print("Client List Length : ",len(self.clients))
def handle(self):
while True:
r,w,e = select.select([self.request],[],[],0.01)
for rs in r:
if rs == self.request:
data = str(self.request.recv(1024),"ascii")
if data:
inbox.append(data)
else:
if self.msgSend < len(inbox):
for elem in range(self.msgSend, len(inbox)):
print("server send :",inbox[elem])
self.request.sendall(bytes(inbox[elem],'utf-8'))
self.msgSend += 1
if self.msgSend < len(inbox):
for elem in range(self.msgSend, len(inbox)):
print("server send :",inbox[elem])
self.request.sendall(bytes(inbox[elem],'utf-8'))
self.msgSend += 1
def finish(self):
for l in range(len(clientList)):
if self.client_address == clientList[l]:
clientList.remove(l)
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def passtime():
pass
if __name__ == "__main__":
HOST, PORT = "localhost", 50007
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
while server_thread:
passtime()
sys.exit()
I use an inbox method from here and using select.select
I am able to check if there is input to be read.
I found a Solution, here is it:
import socket
import threading
import socketserver
import sys
import select
clientList = []
inbox = []
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
clients = []
msgSend = 0
def setup(self):
clientList.append(self.client_address)
self.clients = list(dict.fromkeys(clientList))
print(self.clients)
print("Client List Length : ",len(self.clients))
def handle(self):
while True:
r,w,e = select.select([self.request],[],[],0.01)
for rs in r:
if rs == self.request:
data = str(self.request.recv(1024),"ascii")
if data:
inbox.append(data)
else:
if self.msgSend < len(inbox):
for elem in range(self.msgSend, len(inbox)):
print("server send :",inbox[elem])
self.request.sendall(bytes(inbox[elem],'utf-8'))
self.msgSend += 1
if self.msgSend < len(inbox):
for elem in range(self.msgSend, len(inbox)):
print("server send :",inbox[elem])
self.request.sendall(bytes(inbox[elem],'utf-8'))
self.msgSend += 1
def finish(self):
for l in range(len(clientList)):
if self.client_address == clientList[l]:
clientList.remove(l)
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def passtime():
pass
if __name__ == "__main__":
HOST, PORT = "localhost", 50007
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
while server_thread:
passtime()
sys.exit()
I use an inbox method from here and using select.select
I am able to check if there is input to be read.