我目前在使用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)
Len Holgate.. 8
首先,这可能是特定于平台的,您没有提到您正在运行的平台; 但是,10054是WSAECONNRESET
如此我猜测某种Windows平台.
其次如前所述,与UDP无关.您Connect()
在客户端中的呼叫只会导致客户端计算机上的网络代码允许您启动Send()
呼叫而不是SendTo()
呼叫,并且当您向Send()
呼叫提供的地址发出呼叫时,只需将您发送数据的地址默认为Connect()
.
第三,我很惊讶你得到了WSAECONNRESET
而不是ERROR_PORT_UNREACHABLE
; 然而,潜在的原因可能是相同的.如果您要发送到的端口上没有打开套接字,则远程计算机上的UDP堆栈可能会发送ICMP端口无法访问错误.因此,如果您的客户端发送数据然后关闭套接字,然后您的服务器将数据发送回客户端地址,您将获得端口无法访问,并且某些版本的Windows可能会将其转换为连接重置错误...
这些ICMP端口无法访问错误的问题在于,它们是通过未通过UDP Recv/RecvFrom调用失败而通过Winsock代码报告的.正如我在这里解释并在这里提出的问题,UDP堆栈显然知道生成端口不可达的地址但它没有将该信息传递给调用者,因此没有什么可以做的就是将这些消息映射到有用的东西.您有可能在Vista之前运行Windows版本,并且UDP堆栈正在对该地址执行一些有用的操作,并且它将错误报告给正确的套接字,但不要在其上下注.
最后你还有问题; ICMP端口无法访问错误未能可靠地传递,因此如果您尝试将UDP数据发送到已消失的客户端,则无法确定是否会收到错误.恕我直言,这意味着你有时不应该依赖它.
您显然正在尝试在UDP之上构建某种面向连接的协议(为什么您的服务器会保留客户端的地址).你需要做更多的工作才能在UDP上建立一个可行的伪连接,首先要意识到的是,你知道客户端何时离开的唯一方法就是设置你自己的超时并"断开"你的如果您在一段时间内没有收到他们的声音,请进行伪连接.
当然这不能回答你的问题; 你怎么避免这个例外.我希望你不能.异常的原因可能是来自Recv()
或RecvFrom()
调用的'失败'返回代码,而python网络代码可能会将所有此类失败返回转换为异常.
首先,这可能是特定于平台的,您没有提到您正在运行的平台; 但是,10054是WSAECONNRESET
如此我猜测某种Windows平台.
其次如前所述,与UDP无关.您Connect()
在客户端中的呼叫只会导致客户端计算机上的网络代码允许您启动Send()
呼叫而不是SendTo()
呼叫,并且当您向Send()
呼叫提供的地址发出呼叫时,只需将您发送数据的地址默认为Connect()
.
第三,我很惊讶你得到了WSAECONNRESET
而不是ERROR_PORT_UNREACHABLE
; 然而,潜在的原因可能是相同的.如果您要发送到的端口上没有打开套接字,则远程计算机上的UDP堆栈可能会发送ICMP端口无法访问错误.因此,如果您的客户端发送数据然后关闭套接字,然后您的服务器将数据发送回客户端地址,您将获得端口无法访问,并且某些版本的Windows可能会将其转换为连接重置错误...
这些ICMP端口无法访问错误的问题在于,它们是通过未通过UDP Recv/RecvFrom调用失败而通过Winsock代码报告的.正如我在这里解释并在这里提出的问题,UDP堆栈显然知道生成端口不可达的地址但它没有将该信息传递给调用者,因此没有什么可以做的就是将这些消息映射到有用的东西.您有可能在Vista之前运行Windows版本,并且UDP堆栈正在对该地址执行一些有用的操作,并且它将错误报告给正确的套接字,但不要在其上下注.
最后你还有问题; ICMP端口无法访问错误未能可靠地传递,因此如果您尝试将UDP数据发送到已消失的客户端,则无法确定是否会收到错误.恕我直言,这意味着你有时不应该依赖它.
您显然正在尝试在UDP之上构建某种面向连接的协议(为什么您的服务器会保留客户端的地址).你需要做更多的工作才能在UDP上建立一个可行的伪连接,首先要意识到的是,你知道客户端何时离开的唯一方法就是设置你自己的超时并"断开"你的如果您在一段时间内没有收到他们的声音,请进行伪连接.
当然这不能回答你的问题; 你怎么避免这个例外.我希望你不能.异常的原因可能是来自Recv()
或RecvFrom()
调用的'失败'返回代码,而python网络代码可能会将所有此类失败返回转换为异常.