Python TCP Server接受连接和广播命令

发布于 2021-01-29 14:59:10

我一直在使用多个Raspberry Pi,Python和一些按钮/开关进行游戏。我的游戏需要一个中央服务器,该服务器向多个客户端发出命令。

我不是编程新手,而是Python和较低级网络通信的新手,在过去两天里,我一直迷失在如何精确编写服务器代码方面。

客户端程序是一个简单的socket.connect,然后等待发送数据。那里没有问题。

我很难确定确切的编写方式以及如何使服务器正常工作。

这是我目前的服务器代码:

import socket, time, sys
import threading

TCP_IP = ''
TCP_PORT = 8888
BUFFER_SIZE = 1024
CLIENTS = {}
clientCount = 0

def listener():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((TCP_IP,TCP_PORT))
    s.listen(5)
    while True:
        conn, addr = s.accept()
        print("new connection from:"+ str(addr))
        #print(len(CLIENTS))
        global clientCount
        clientCount = clientCount+1
        print (clientCount)
        # register client
        CLIENTS[conn.fileno()] = conn


def broadcast():
     for client in CLIENTS.values():
            client.send('this is a broadcats msg')

if __name__ == '__main__':
    listener()

    while clientCount > 0:
        broadcast()
        print(len(CLIENTS)) #print out the number of connected clients every 5s
        time.sleep(5)

这是所需的流程:1.服务器启动并等待第一个或更多连接。我相信这个“​​服务器”应该在后台线程上运行吗?2.如果connectionCount > 0启动主程序循环,则3.现在,主程序循环应仅显示已连接客户端的数量,并每5秒向所有客户端广播一条消息。

我有大约5个版本的服务器。我曾尝试过async,select.select和几种线程方法,但无法完全确定我寻求的行为。我应该将服务器置于后台线程中吗?如果是这样,如何广播到所有连接?

我唯一没有尝试过的就是Twisted,那是因为我无法在Windows中安装它……所以我暂时不考虑optino。如果有人在哪里进行指导,我将不胜感激!

更新资料

好的,根据@Armans的建议,我已经更新了代码,以便有一个服务器类,但它仍然执行相同的操作。

class server():

    def __init__(self):
        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
            CLIENTS[client_socket.fileno()] = client_socket
            threading.Thread(target=self.handler, args=(client_socket, addr)).start()



    def handler(self, client_socket, addr):
        while 1:
            data = client_socket.recv(BUFFER_SIZE)
            print ('Data : ' + repr(data) + "\n")
            data = data.decode("UTF-8")


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

if __name__ == '__main__':
    s = server() #create new server listening for connections

    while clientCount > 0:
        s.broadcast('msg here')
        print(len(CLIENTS)) #print out the number of connected clients every 5s
        time.sleep(5)

我可以连接多个客户端,并且控制台显示以下内容:

Connected with 10.0.0.194:38406
1
Connected with 10.0.0.169:36460
2

但是“ while clientCount”循环中的代码永远不会运行。这是我被困住一段时间的区域,因此,如果您还有更多想法,我将乐意为您提供任何想法!

关注者
0
被浏览
89
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    终于成功了!非常感谢@Arman为我指出正确的穿线方向。我终于感觉到我知道一切正常!

    这是我完整的服务器和客户端代码。希望这可以通过master> client
    setup帮助其他人。_broadcast()函数正在工作,因为您会看到它现在只广播静态msg,但这应该是一个简单的更新。

    如果有人对代码清除有任何建议,请使用该代码作为示例的python最佳实践,我希望听到并了解更多。再次感谢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)
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看