UDP数据接收上的Python套接字错误。 (10054)

时间:2010-04-05 04:28:29

标签: python sockets client udp

我目前在使用UDP和Python套接字模块时遇到问题。我们有服务器和客户端。当我们向用户发送数据时会出现问题。用户可能通过客户端崩溃,ISP断开连接或其他一些不正确的方法关闭了与服务器的连接。因此,可以将数据发送到封闭的套接字。

当然,使用UDP,您无法判断数据是否真正到达或是否已关闭,因为它并不关心(至少,它不会引发异常)。但是,如果您发送数据并且它已关闭,则会以某种方式返回数据(???),最终会在sock.recvfrom上出现套接字错误。 [Errno 10054]远程主机强行关闭现有连接。几乎看起来像连接的自动响应。

虽然这很好,但可以通过try来处理:except:block(即使它稍微降低了服务器的性能)。问题是,我不知道这是来自谁或什么套接字关闭。有没有找到'谁'(ip,socket#)发送这个?它会很棒,因为我可以立即断开它们并将它们从数据中删除。有什么建议?感谢。

服务器:

import socket

class Server(object):
    def __init__(self):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.connected = {}

    def connect(self):
        self.socket.bind(('127.0.0.1', 5579))

    def find_data(self):
        while 1:
            data, address = self.socket.recvfrom(1024)
            self.got_data(data,address)
            if self.connected.has_key(address):
                pass
            else:
                self.connected[address] = None

    def got_data(self, data, address):
        print "GOT",data,"FROM",address
        for people in self.connected:
            print people
            self.send_data('hi', people)

    def send_data(self, data, address):
        self.socket.sendto(data,address)


if __name__ == '__main__':
    server = Server()
    server.connect()
    print "NOW SEARCHING FOR DATA"
    server.find_data()

客户端:

import socket, time

class Client(object):
    def __init__(self):
        self.socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

    def connect(self):
        self.socket.connect(('127.0.0.1', 5579))

    def send_data(self):
        self.socket.sendto('hi',('127.0.0.1', 5579))

    def got_data(self, data, address):
        print "GOT",data,"FROM",address


if __name__ == '__main__':
    client = Client()
    client.connect()
    while 1:
        client.send_data()
        time.sleep(5)

3 个答案:

答案 0 :(得分:8)

首先,这可能是特定于平台的,您没有提到您正在运行的平台;但是,10054是WSAECONNRESET所以我猜测某种Windows平台。

其次如前所述,与UDP无关。您在客户端中对Connect()的调用只会导致客户端计算机上的网络代码允许您启动Send()次呼叫而不是SendTo()次呼叫,只需将您要发送数据的地址默认为当您对Send()的调用所提供的地址发出Connect()次调用时。

第三,我很惊讶你得到WSAECONNRESET而不是ERROR_PORT_UNREACHABLE;然而,潜在的原因可能是相同的。如果您要发送到的端口上没有打开套接字,则远程计算机上的UDP堆栈可能会发送ICMP端口无法访问错误。因此,如果您的客户端发送数据然后关闭套接字,然后您的服务器将数据发送回客户端地址,您将获得一个端口无法访问,某些版本的Windows可能会将其转换为连接重置错误...

这些ICMP端口无法访问错误的问题在于,它们是通过Winsock代码通过未通过的UDP Recv / RecvFrom调用失败来报告的。当我解释here和问题here时,UDP堆栈显然知道生成端口不可达的地址,但它没有将该信息传递给调用者,因此您无法做任何事情来映射这些消息有用的东西。您可能在Vista之前运行的是Windows版本,并且UDP堆栈正在对该地址执行一些有用的操作,它会将错误报告给正确的套接字,但不要在其上下注。

最后你还有问题; ICMP端口无法访问错误未能可靠地传递,因此如果您尝试将UDP数据发送到已消失的客户端,则无法确定是否会收到错误。恕我直言,这意味着你有时不应该依赖它。

您显然正在尝试在UDP之上构建某种面向连接的协议(为什么您的服务器会保留客户端的地址)。你需要做更多的工作才能在UDP上建立一个可行的伪连接,首先要意识到的是,你知道客户端何时离开的唯一方法就是设置你自己的超时并“断开”你的伪连接如果你在一段时间内没有收到他们的消息。

当然这不能回答你的问题;你怎么避免这个例外。我希望你不能。异常的原因很可能是来自Recv()RecvFrom()调用的“失败”返回代码,而python网络代码可能会将所有此类失败返回转换为异常。

答案 1 :(得分:2)

这个问题远比它看起来简单得多。使用socket.recv()而不是socket.recvfrom() - 我在本地进行了此更改,然后您的代码可以正常工作。

答案 2 :(得分:1)

嗯,这似乎很明显。

  1. UDP没有连接,因此Client.connect错误
  2. 您将客户地址存储在Server.connected dict中。当客户关闭时,没有人会在那里接收您发送的内容。
  3. 正确地进行网络通信很困难,因为socket库太低级了(它是C套接字的薄包装)。你的代码遗漏了很多细节。我建议尝试更高级别的库,例如twisted。这里有一些example on UDP可以帮助您入门。