如何在Python中清空一个socket?

14

我需要清空一个套接字中的数据(确保没有接收到任何内容)。不幸的是,Python socket模块中没有此功能。

我这样实现了一些东西:

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: 我注意到在对等端关闭时会出现错误。inputready始终填充套接字。通过添加最大循环次数,我解决了这个问题。有更好的解决方法吗?


这并不是真正的"刷新"。请查看套接字读取文档中的示例。http://docs.python.org/library/socket.html#example - JimB
1
你有没有考虑使用Twisted代替你的程序呢?如果你这样做了,你就不需要再像这样做任何事情了。Twisted会立即从套接字中提取所有数据,并在任何数据到达时将其传递给你,因此你不需要处理像Thomas下面回答中描述的select()问题这样的丑陋细节。 - Glyph
1
@Glyph:不,我没有考虑Twisted,因为我想使用标准的Python模块来避免外部依赖。谢谢你的评论,我会看一下Twisted,也许重新考虑我的选择。 - luc
一个朋友告诉我去看Twisted。经过很多困难,我下次会试试。如果所有糟糕的Python网络示例都能消失就好了。 - John Carlson
5个回答

8
如果“flush”指的是丢弃任何待处理的传入数据,则可以使用像您一样的select(),或将套接字设置为非阻塞,并循环读取直到没有数据。
还要注意(来自Linux手册):
在Linux下,select()可能会报告一个套接字文件描述符为“准备好读取”,但随后的读取会阻塞。例如,当数据到达但检查和值错误并被丢弃时,可能会发生这种情况。在其他情况下,文件描述符可能被虚假地报告为已准备就绪。因此,对于不应阻塞的套接字,使用O_NONBLOCK可能更安全。 Select系统调用的虚假准备通知 正如其他人所指出的,“flush”通常是指输出。

2
“Flushing”一个输入会用什么术语描述比较准确?谢谢你的回答。 - luc
1
个人而言,我会称您正在做的是“清空”套接字。虽然我觉得很奇怪为什么您要这样做-有人出于某种原因向您发送了这些数据,为什么不处理而直接丢弃呢? :) - Glyph
在 select 返回后,我们能否只使用长度为 0 的 recv 来读取数据? - Aditya Sehgal
1
我相信“drain”是正常的术语。 - Gordon Wrigley

5
使用select.select是良好的实践,正如Socket Programming HOWTO中所示。 您需要使用sock.setblocking(0)将套接字设置为非阻塞。
关于命名法的注释:通常将flush输出操作相关联。

1
对于UDP数据包,我做了以下操作:
1.创建套接字、设置选项和绑定后,我使用socket.settimeout()。请注意setblocking()的文档提供了一些settimeout()没有的信息 - 如果您希望套接字操作阻塞,只需使用settimeout()设置超时即可。setblocking()会将其设为无限超时。(我曾经错误地调用了settimeout(),然后是setblocking(1)。)
2.我的“缓冲清空”函数如下(“Listener”是我的套接字): def FlushListen(self): while 1: try: PacketBytes = self.__Listener.recv(1024) except: break; 设置1秒的超时后,这将读取所有UDP数据包,然后在没有数据后1秒返回。
在我的情况下,我仅将其用于在同一台计算机上的两个程序之间进行通信,因此我可以轻松降低超时时间,但速度不是问题,所以我很满意。
根据其他人发布的一些链接,这也应该适用于数据流。

0

我们能不能一直读取,直到缓冲区为空?

def clear_buffer(sock):
    try:
        while sock.recv(1024): pass
    except:
        pass

-1

不确定这是否有效,但您可以将文件对象附加到套接字的文件描述符上,并在该文件对象上调用flush()方法:

import os

file_obj = os.fdopen(your_socket.fileno())
file_obj.flush()

这在Windows上行不通,因为fileno()返回的描述符无法传递给Windows中的os.fdopen()


仅在文件对象上刷新只会刷新用户空间中缓存的输出。比较C语言中的FILE*和fflush。原始套接字I/O通常不会被缓冲,如果它被缓冲了,那么它不会在用户空间中缓冲,类似fflush的操作将无法工作。您可能需要查看TCP的“push”。 - Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接