So I am working on an iPhone app that requires a socket to handle multiple clients for online gaming. I have tried Twisted, and with much effort, I have failed to get a bunch of info to be sent at once, which is why I am now going to attempt socket.
My question is, using the code below, how would you be able to have multiple clients connected? I've tried lists, but I just can't figure out the format for that. How can this be accomplished where multiple clients are connected at once and I am able to send a message to a specific client?
Thank you!
#!/usr/bin/python # This is server.py file import socket # Import socket module s = socket.socket() # Create a socket object host = socket.gethostname() # Get local machine name port = 50000 # Reserve a port for your service. print 'Server started!' print 'Waiting for clients...' s.bind((host, port)) # Bind to the port s.listen(5) # Now wait for client connection. c, addr = s.accept() # Establish connection with client. print 'Got connection from', addr while True: msg = c.recv(1024) print addr, ' >> ', msg msg = raw_input('SERVER >> ') c.send(msg); #c.close() # Close the connection 127 Answers
Based on your question:
My question is, using the code below, how would you be able to have multiple clients connected? I've tried lists, but I just can't figure out the format for that. How can this be accomplished where multiple clients are connected at once and I am able to send a message to a specific client?
Using the code you gave, you can do this:
#!/usr/bin/python # This is server.py file import socket # Import socket module import thread def on_new_client(clientsocket,addr): while True: msg = clientsocket.recv(1024) #do some checks and if msg == someWeirdSignal: break: print addr, ' >> ', msg msg = raw_input('SERVER >> ') #Maybe some code to compute the last digit of PI, play game or anything else can go here and when you are done. clientsocket.send(msg) clientsocket.close() s = socket.socket() # Create a socket object host = socket.gethostname() # Get local machine name port = 50000 # Reserve a port for your service. print 'Server started!' print 'Waiting for clients...' s.bind((host, port)) # Bind to the port s.listen(5) # Now wait for client connection. print 'Got connection from', addr while True: c, addr = s.accept() # Establish connection with client. thread.start_new_thread(on_new_client,(c,addr)) #Note it's (addr,) not (addr) because second parameter is a tuple #Edit: (c,addr) #that's how you pass arguments to functions when creating new threads using thread module. s.close() As Eli Bendersky mentioned, you can use processes instead of threads, you can also check python threading module or other async sockets framework. Note: checks are left for you to implement how you want and this is just a basic framework.
accept can continuously provide new client connections. However, note that it, and other socket calls are usually blocking. Therefore you have a few options at this point:
- Open new threads to handle clients, while the main thread goes back to accepting new clients
- As above but with processes, instead of threads
- Use asynchronous socket frameworks like Twisted, or a plethora of others
Here is the example from the SocketServer documentation which would make an excellent starting point
import SocketServer class MyTCPHandler(SocketServer.BaseRequestHandler): """ The RequestHandler class for our server. It is instantiated once per connection to the server, and must override the handle() method to implement communication to the client. """ def handle(self): # self.request is the TCP socket connected to the client self.data = self.request.recv(1024).strip() print "{} wrote:".format(self.client_address[0]) print self.data # just send back the same data, but upper-cased self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "localhost", 9999 # Create the server, binding to localhost on port 9999 server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler) # Activate the server; this will keep running until you # interrupt the program with Ctrl-C server.serve_forever() Try it from a terminal like this
$ telnet localhost 9999 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello HELLOConnection closed by foreign host. $ telnet localhost 9999 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Sausage SAUSAGEConnection closed by foreign host. You'll probably need to use A Forking or Threading Mixin too
3This program will open 26 sockets where you would be able to connect a lot of TCP clients to it.
#!usr/bin/python from thread import * import socket import sys def clientthread(conn): buffer="" while True: data = conn.recv(8192) buffer+=data print buffer #conn.sendall(reply) conn.close() def main(): try: host = '192.168.1.3' port = 6666 tot_socket = 26 list_sock = [] for i in range(tot_socket): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) s.bind((host, port+i)) s.listen(10) list_sock.append(s) print "[*] Server listening on %s %d" %(host, (port+i)) while 1: for j in range(len(list_sock)): conn, addr = list_sock[j].accept() print '[*] Connected with ' + addr[0] + ':' + str(addr[1]) start_new_thread(clientthread ,(conn,)) s.close() except KeyboardInterrupt as msg: sys.exit(0) if __name__ == "__main__": main() 0def get_clients(): first_run = True startMainMenu = False while True: if first_run: global done done = False Thread(target=animate, args=("Waiting For Connection",)).start() Client, address = objSocket.accept() global menuIsOn if menuIsOn: menuIsOn = False # will stop main menu startMainMenu = True done = True # Get Current Directory in Client Machine current_client_directory = Client.recv(1024).decode("utf-8", errors="ignore") # beep on connection beep() print(f"{bcolors.OKBLUE}\n***** Incoming Connection *****{bcolors.OKGREEN}") print('* Connected to: ' + address[0] + ':' + str(address[1])) try: get_client_info(Client, first_run) except Exception as e: print("Error data received is not a json!") print(e) now = datetime.now() current_time = now.strftime("%D %H:%M:%S") print("* Current Time =", current_time) print("* Current Folder in Client: " + current_client_directory + bcolors.WARNING) connections.append(Client) addresses.append(address) if first_run: Thread(target=threaded_main_menu, daemon=True).start() first_run = False else: print(f"{bcolors.OKBLUE}* Hit Enter To Continue.{bcolors.WARNING}\n#>", end="") if startMainMenu == True: Thread(target=threaded_main_menu, daemon=True).start() startMainMenu = False 1You can use use PySock, a python library that make writing multi-client servers extremally easy. You can download it from PyPi, for windows : pip install PySock and for Linux : pip3 install PySock. They have very good boiler plate code on PyPi introduction page. You can check it out here or go to GitHub repo for more insights about versions. There are some great features it provide that is client-client communication without any extra effort, you can make these these communication E2E encrypted.
#!/usr/bin/python import sys import os import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) port = 50000 try: s.bind((socket.gethostname() , port)) except socket.error as msg: print(str(msg)) s.listen(10) conn, addr = s.accept() print 'Got connection from'+addr[0]+':'+str(addr[1])) while 1: msg = s.recv(1024) print +addr[0]+, ' >> ', msg msg = raw_input('SERVER >>'),host s.send(msg) s.close()