Python TCP Server Accepting Connections and Broadcasting Commands

后端 未结 2 1532
萌比男神i
萌比男神i 2020-12-20 09:22

I\'ve been working on a game using a number of Raspberry Pis, Python, and some buttons/switches. My game requires a central server that issues commands to multiple clients.

相关标签:
2条回答
  • 2020-12-20 09:42

    Finally got it working! Much thanks to @Arman for pointing me in the right direction with the threading. I finally feel like I understand how everything is working!

    Here is my complete Server & Client code. Hopefully this helps someone else with a master > client setup. The _broadcast() function is working as you will see it just broadcasts a static msg at the moment but that should be an easy update.

    If anyone has any advice on code cleanup, python best practices using this code as the sample I would love to hear and learn more. Thanks again SE!

    ##Client
    
    import socket
    import sys
    import json
    
    #vars
    connected = False
    
    #connect to server
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect(('10.0.0.158',8888))
    connected = True
    
    while connected == True:
        #wait for server commands to do things, now we will just display things
        data = client_socket.recv(1024)     
        cmd = json.loads(data) #we now only expect json    
        if(cmd['type'] == 'bet'):
            bet = cmd['value']
            print('betting is: '+bet)
        elif (cmd['type'] == 'result'):        
            print('winner is: '+str(cmd['winner']))
            print('payout is: '+str(cmd['payout']))
    
    
    ##Server
    
    import socket, time, sys
    import threading
    import pprint
    
    TCP_IP = ''
    TCP_PORT = 8888
    BUFFER_SIZE = 1024
    
    clientCount = 0
    
    class server():
    
        def __init__(self):
            self.CLIENTS = []        
    
    
        def startServer(self):
            try:
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.bind((TCP_IP,TCP_PORT))
                s.listen(10)
                while 1:
                    client_socket, addr = s.accept()
                    print ('Connected with ' + addr[0] + ':' + str(addr[1]))
                    global clientCount
                    clientCount = clientCount+1
                    print (clientCount)
                    # register client
                    self.CLIENTS.append(client_socket)
                    threading.Thread(target=self.playerHandler, args=(client_socket,)).start()
                s.close()
            except socket.error as msg:
                print ('Could Not Start Server Thread. Error Code : ') #+ str(msg[0]) + ' Message ' + msg[1]
                sys.exit()
    
    
       #client handler :one of these loops is running for each thread/player   
        def playerHandler(self, client_socket):
            #send welcome msg to new client
            client_socket.send(bytes('{"type": "bet","value": "1"}', 'UTF-8'))
            while 1:
                data = client_socket.recv(BUFFER_SIZE)
                if not data: 
                    break
                #print ('Data : ' + repr(data) + "\n")
                #data = data.decode("UTF-8")
                # broadcast
                for client in self.CLIENTS.values():
                    client.send(data)
    
             # the connection is closed: unregister
            self.CLIENTS.remove(client_socket)
            #client_socket.close() #do we close the socket when the program ends? or for ea client thead?
    
        def broadcast(self, message):
    
            for c in self.CLIENTS:
                c.send(message.encode("utf-8"))
    
        def _broadcast(self):        
            for sock in self.CLIENTS:           
                try :
                    self._send(sock)
                except socket.error:                
                    sock.close()  # closing the socket connection
                    self.CLIENTS.remove(sock)  # removing the socket from the active connections list
    
        def _send(self, sock):        
            # Packs the message with 4 leading bytes representing the message length
            #msg = struct.pack('>I', len(msg)) + msg
            # Sends the packed message
            sock.send(bytes('{"type": "bet","value": "1"}', 'UTF-8'))
    
    
    if __name__ == '__main__':
        s = server() #create new server listening for connections
        threading.Thread(target=s.startServer).start()
    
        while 1:       
            s._broadcast()
            pprint.pprint(s.CLIENTS)
            print(len(s.CLIENTS)) #print out the number of connected clients every 5s
            time.sleep(5) 
    
    0 讨论(0)
  • 2020-12-20 09:50

    I have a multithread approach here :

    s.listen(10)
        while 1:
            client_socket, addr = s.accept()
            print ('Connected with ' + addr[0] + ':' + str(addr[1]))
            threading.Thread(target=self.handler, args=(client_socket, addr)).start()        
    
    
    def handler(self, client_socket, addr):
        while 1:
            data = client_socket.recv(BUFF)
            print ('Data : ' + repr(data) + "\n")
            data = data.decode("UTF-8")
    

    I strongly recommend you two write a class for Server and Client, for each client create a Client object and connect it to Server, and store each connected Client (its socket and a name for example) to a dictionary as you did, then you want to broadcast a message you can go through all connected Clients in Server and broadcast message you want like this:

    def broadcast(self, client_socket, message):
            for c in self.clients:
                c.send(message.encode("utf-8"))
    

    Update

    Because you have a thread that runs main you need another thread for running server , I suggest you write a start method for server and call it in a thread :

    def start(self):
        # all server starts stuff comes here as define socket 
        self.s.listen(10)
        while 1:
            client_socket, addr = self.s.accept()
            print ('Connected with ' + addr[0] + ':' + str(addr[1]))
            threading.Thread(target=self.handler, args=(client_socket, addr)).start()
    

    now in main section or main file after create server object run the start thread :

    a = server()
    threading.Thread(target=a.start).start()
    
    0 讨论(0)
提交回复
热议问题