我一直在使用多个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秒向所有客户端广播一条消息。
connectionCount > 0
我有大约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”循环中的代码永远不会运行。这是我被困住一段时间的区域,因此,如果您还有更多想法,我将乐意为您提供任何想法!
终于成功了!非常感谢@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)