Python TCP Server 接受连接和广播命令 [英] Python TCP Server Accepting Connections and Broadcasting Commands

查看:29
本文介绍了Python TCP Server 接受连接和广播命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

我对编程并不陌生,而是对 Python 和较低级别的网络通信不熟悉,并且在过去 2 天里一直迷失在如何准确地编写我的服务器代码的杂草中.

I'm not new to programming but new to Python and lower-er level network communication and have been lost in the weeds for the past 2 days on how exactly to write my server code.

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

The client program is a simple socket.connect and then waits for data to be sent. No problems there.

我很难确定到底如何编写以及如何使服务器工作.

I have had a tough time determining exactly how to write and how to make work the server.

目前我的服务器代码如下所示:

Here's what my server code looks like at the moment:

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 秒向所有客户端广播一条消息.

Here's the desired flow: 1. Server starts and waits for first connection or more. I believe this "Server" should be running on a background thread? 2. If connectionCount > 0 start the main program loop 3. For now the main program loop should just display the number of connected clients and broadcast a message to all of them every 5 seconds.

我有这个服务器的大约 5 个版本.我尝试过异步、select.select 和几种线程方法,但不能完全确定我寻求的行为.我应该将服务器放在后台线程中吗?如果是,如何广播到所有连接?

I have about 5 versions of this server. I have tried async, select.select, and several threaded approaches but can't quite nail down the behavior I seek. Should I be putting the server in a background thread? If so how to broadcast to all the connections?

我唯一没有尝试过的是 Twisted,那是因为我无法在 Windows 中安装它......所以我暂时排除了 optino.如果有人有关于该去哪里的指示,我将不胜感激!

The only thing I haven't tried is Twisted and that is because I could not get it installed in Windows... so I'm ruling that optino out for the moment. If anyone has a pointer on where to go on this I would really appreciate it!

更新

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

Ok, based on @Armans suggestion I have updated my code so that there is a server class but it still performs the same.

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) + "
")
            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) 

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

I can connect multiple clients and the console displays the following:

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

但是while clientCount"循环中的代码永远不会运行.这是我被困了一段时间的区域,所以如果你有更多想法,我很乐意在这里提出任何想法!

But the code in the "while clientCount" loop never runs. This is the zone where I have been stuck for some time so if you have a couple more ideas I would love to here any ideas!

推荐答案

终于搞定了!非常感谢@Arman 为我指明了正确的线程方向.我终于觉得我明白一切是如何运作的!

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!

这是我的完整服务器 &客户端代码.希望这可以帮助其他拥有主 > 客户端设置的人._broadcast() 函数正在工作,因为您将看到它目前只广播静态消息,但这应该是一个简单的更新.

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.

如果有人对代码清理有任何建议,使用此代码作为示例的 Python 最佳实践,我很乐意听到并了解更多信息.再次感谢 SE!

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) + "
")
            #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) 

这篇关于Python TCP Server 接受连接和广播命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆