Python UDP recvfrom() 指定地址

2 投票
1 回答
4493 浏览
提问于 2025-04-17 10:32

我看到这个代码的问题是,虽然它能正常工作,但有些客户端(玩家)发送到服务器的信息会错误地到达'permission'这个方法,而不是'clientRequests'。这是因为这两个方法都有recvfrom()这个功能。所以,如果我能在recvfrom()里指定我想要从哪个地址获取信息,那就能解决这个问题。我相信在C++中可以做到,但在Python中可以吗?怎么做呢?

使用TCP就没有这个问题,但我更喜欢UDP。

类似于:recvfrom(512, address=(ip, port))?

'permission'这个方法是用来处理新客户端连接的。

问题在于,像位置、事件这些从客户端发送的信息不会在'permission'里被处理。

class Server:
    def __init__(self):
        #host = '192.168.0.2'
        host = '127.0.0.1'
        port = 50007
        addr = (host, port)
        self.UDPSock = socket(AF_INET, SOCK_DGRAM)
        self.UDPSock.bind(addr)
        self.UDPSock.settimeout(5.0)
        self.searchForClients = True
        self.playersOnline = []
        threading.Thread(target=self.permission).start()
        Gui.add_event("Server online on port %s" % port)


    def permission(self):
        global _status
        while self.searchForClients:
            time.sleep(0.5)
            _status.set("Status: Running; Connected: %s" % len(self.playersOnline))
            try:
                clientMessage, addr = self.UDPSock.recvfrom(1024) # , MSG_PEEK
            except:
                clientMessage = ""
            if clientMessage == "CONNECT" and addr not in self.playersOnline:                       
                if self.searchForClients:
                    self.addNewClient(addr)

            elif clientMessage == "DISCONNECT" and addr in self.playersOnline:
                self.removeClient(addr)

        Gui.add_event("No longer accepting logins")
        return False

    def clientRequests(self, addr):
        latestRequest = time.time()
        while addr in self.playersOnline:
            time.sleep(0.01)
            try:
                data, requestAddr = self.UDPSock.recvfrom(1024)
            except:
                requestAddr, data = "", ""
            if requestAddr == addr:
                latestRequest = time.time()
                dataCommand = data.split(':')
            if time.time() - latestRequest > 2:
                if addr in self.playersOnline:
                    self.removeClient(addr)

        if not self.searchForClients:       
            Gui.add_event("Player %s(%s) forcibly removed" % addr)
        return False

1 个回答

1

我觉得线程会让像这样的简单UDP服务器变得复杂。你只需要在套接字上监听,然后根据数据包的来源地址来处理请求,如果这个地址之前见过就行。

而且,普通的 recvfrom(2) 系统调用并不能让你“过滤”来自哪个地址的数据,它只是用来获取这些信息。要进行过滤的话,可以使用 connect(2) 在UDP套接字上,但这样的话你就只能处理来自一个地址的数据了。

撰写回答