本文介绍了UDP数据接收上的Python套接字错误. (10054)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I currently have a problem using UDP and Python socket module. We have a server and clients. The problem occurs when we send data to a user. It's possible that user may have closed their connection to the server through a client crash, disconnect by ISP, or some other improper method. As such, it is possible to send data to a closed socket.

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

Of course with UDP you can't tell if the data really reached or if it's closed, as it doesn't care (atleast, it doesn't bring up an exception). However, if you send data and it is closed off, you get data back somehow (???), which ends up giving you a socket error on sock.recvfrom. [Errno 10054] An existing connection was forcibly closed by the remote host. Almost seems like an automatic response from the connection.

尽管这很好,并且可以通过try:except:块来处理(即使它会稍微降低服务器的性能).问题是,我不知道这是谁来的或者关闭了哪个套接字.无论如何,有没有找出发送此邮件的谁"(ip,套接字号)?太好了,因为我可以立即断开它们的连接并将它们从数据中删除.有什么建议?谢谢.

Although this is fine, and can be handled by a try: except: block (even if it lowers performance of the server a little bit). The problem is, I can't tell who this is coming from or what socket is closed. Is there anyway to find out 'who' (ip, socket #) sent this? It would be great as I could instantly just disconnect them and remove them from the data. Any suggestions? Thanks.

服务器:

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)

推荐答案

首先,这可能是特定于平台的,并且您没有提及正在运行的平台.但是10054是WSAECONNRESET,所以我猜是某种Windows平台.

Firstly this is possibly platform specific and you don't mention the platform that you're running on; however, 10054 is WSAECONNRESET so I'm guessing a Windows platform of some kind.

其次,如先前指出的那样,与UDP没有连接.在客户端中对Connect()的调用只会导致客户端计算机上的网络代码允许您发起Send()调用,而不是SendTo()调用,并且仅在发出Send()时默认将数据发送到的地址呼叫到提供给Connect()呼叫的地址.

Secondly as previously pointed out there is no connection with UDP. Your call to Connect() in the client simply causes the networking code on your client machine to allow you to initiate Send() calls rather than SendTo() calls and simply default the address that you are sending data to when you issue Send() calls to the address supplied to the call to Connect().

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

Thirdly I'm surprised that you're getting WSAECONNRESET and not ERROR_PORT_UNREACHABLE; however the underlying reason is probably the same. The UDP stack on the remote machine will likely be sending a ICMP Port Unreachable error if there's no socket open on the port that you are sending to. So, if your client sends data and then closes the socket and then your server sends data back to the client address you'll get a port unreachable and some versions of windows might be translating that into a connection reset error...

这些ICMP端口无法访问错误的问题是,通过使未决的UDP Recv/RecvFrom调用失败而通过Winsock代码报告了这些错误.正如我在此处和问题此处 UDP堆栈显然知道生成端口不可达的地址,但是它不会将该信息传递给调用方,因此您无法做任何操作来将这些消息映射到有用的东西.您可能正在Vista之前的Windows版本上运行,并且UDP堆栈正在对该地址进行某些有用的操作,并且正在将错误报告给正确的套接字,但不要打赌.

The problem with these ICMP port unreachable errors, is that they're reported via the Winsock code by failing a pending UDP Recv/RecvFrom call. As I explain here and question here the UDP stack obviously knows the address that generated the port unreachable but it doesn't pass that information on to the caller so there's nothing that you can do to map these messages to something useful. It's possible that you're running on a version of Windows prior to Vista and the UDP stack is doing something useful with the address and it IS reporting the error to the correct socket, but don't bet on it.

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

Finally you have a problem anyway; the ICMP port unreachable error isn't delivered reliably so you can't know for sure that you WILL get an error if you try and send UDP data to a client that has gone away. IMHO this means that you shouldn't rely on it even if it works sometimes.

您显然正在尝试在UDP之上构建某种面向连接的协议(为什么您的服务器还会保留客户机的地址).您需要做更多的工作才能在UDP上创建可行的伪连接,并且要意识到的第一件事就是,您可以知道客户端何时离开的唯一方法是设置自己的超时时间并断​​开"连接如果您在一定时间内没有收到伪连接,则为伪连接.

You are obviously attempting to build some kind of connection oriented protocol on top of UDP (why else would your server hold on to the addresses of the clients). You'll have to do a lot more to create a viable pseudo connection over UDP and one of the first things to realise is that the only way you can know when a client has gone away is to set your own timeout and 'disconnect' your pseudo connection if you don't hear from them within a certain period of time.

这当然不能回答您的问题;您如何避免该异常.我希望你不能.导致异常的原因很可能是Recv()RecvFrom()调用的失败"返回代码,而python网络代码很可能会将所有此类失败返回都转换为异常.

Of course this doesn't answer your question; how do you avoid the exception. I expect you can't. The cause of the exception is likely a 'failure' return code from a Recv() or RecvFrom() call and the python network code is probably converting all such failure returns into exceptions for you.

这篇关于UDP数据接收上的Python套接字错误. (10054)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-27 02:21
查看更多