如何在Python中清空socket?
我需要清空一个套接字上的数据(确保没有任何数据可以接收)。可惜的是,Python的套接字模块里没有这个功能。
我这样实现的:
def empty_socket(sock):
"""remove the data present on the socket"""
input = [sock]
while 1:
inputready, o, e = select.select(input,[],[], 0.0)
if len(inputready)==0: break
for s in inputready: s.recv(1)
你觉得怎么样?有没有更好的方法?
更新:我不想改变套接字的超时时间,所以我更喜欢用select而不是read。
更新:最开始的问题中用了“flush”这个词。看来“empty”这个词更合适。
更新 - 2010-02-27:我发现当连接关闭时会有个bug。inputready总是被套接字填满。我通过添加一个最大循环次数来修复这个问题。有没有更好的解决办法?
5 个回答
对于UDP数据包,我做了以下几步:
在创建套接字、设置选项和绑定之后,我使用了
socket.settimeout()
。注意,关于setblocking()
的文档提供了一些settimeout()
没有的信息——如果你希望你的套接字操作能够阻塞(也就是等待),你应该只使用settimeout()
来设置超时时间。setblocking()
只是给它设置了一个无限的超时时间。(我曾经遇到过一个错误,就是先调用了settimeout()
然后又调用了setblocking(1)
。)我的“清空缓冲区”函数就是这样写的(“Listener”是我的套接字):
def FlushListen(self): while 1: try: PacketBytes = self.__Listener.recv(1024) except: break;
设置了1秒的超时时间,这样可以读取所有的UDP数据包,然后在没有数据的情况下,1秒后返回。
在我的情况下,我只是用它在同一台电脑上的两个程序之间进行通信,所以我可以轻松地降低我的超时时间,但速度不是问题,所以这样就可以了。
根据其他人发布的一些链接,这个方法也应该适用于数据流。
使用 select.select
是一种很好的做法,这在 Socket 编程指南 中有提到。你需要把套接字设置为非阻塞模式,可以用 sock.setblocking(0)
来实现。
顺便说一下,关于术语的使用:flush
通常是和 输出 操作相关的。
如果你说的“刷新”是指丢弃任何待处理的输入数据,那么你可以像现在这样使用select(),或者把套接字设置为非阻塞模式,然后循环读取数据,直到没有数据为止。
另外需要注意的是(根据Linux的手册):
在Linux下,select()可能会把一个套接字文件描述符报告为“可以读取”,但随后的读取操作可能会被阻塞。这种情况可能发生在数据已经到达,但检查后发现校验和错误而被丢弃。例如,还有其他情况可能导致文件描述符被错误地报告为准备就绪。因此,对于那些不应该阻塞的套接字,使用O_NONBLOCK可能更安全。
另外,正如其他人所提到的,“刷新”通常是指输出。