我的问题类似于python - How select.select() works?。但是,那里的解决方案并不适合我,因为我没有打开()我的文件。相反,它是一个套接字。我找不到任何方法将它设置为在documentation中无缓冲。如何使用选择与Python ssl套接字缓冲?
我有一个glib mainloop(使用select),在那里我注册了socket的读取。由于socket.recv()要求我指定接收缓冲区大小,因此读取比读取套接字更少的字节并不少见。只要内核缓冲它们,这很好; select仍然会将套接字标记为“准备好读取”。但显然Python也有缓冲区。对于接近数据流末尾的大文件,recv()将读取其中的一部分,其余部分将被Python缓存并在我的套接字上选择不再触发,直到发送新数据为止。此时,在新数据之前收到“缺失”数据;没有数据丢失。
我的问题是:我该如何解决这个问题?有没有办法在套接字上禁用Python的缓冲区?如果没有,有没有办法来检查缓冲区是否为空,所以我可以确保我不会从我的回调中返回,直到它是?
编辑:
正如评论指出,Python没有额外的缓存添加到插座,所以这可能不是问题。我无法为这个问题创建一个最简单的例子。但是,它似乎可能与使用ssl套接字有关。我忘记了我使用了加密连接;禁用加密似乎解决了这个问题,但我不能接受。所以上面的问题仍然存在,注意缓冲区可能在ssl模块中实现。
示例代码来说明问题:
#!/usr/bin/python
import glib
import socket
import ssl
def cb (fd, cond):
print ('data: %s' % repr (s.read (1)))
return True
s = ssl.wrap_socket (socket.create_connection (('localhost', 1234)))
glib.io_add_watch (s.fileno(), glib.IO_IN, cb)
glib.MainLoop().run()
然后用
openssl s_server -accept 1234 -key file.key -cert file.crt
运行Python程序将建立连接运行服务器。发送多于一个字节的数据将使程序仅打印第一个字节;当发送更多字节时,首先读取剩余的块,然后读取第一个新字节,然后再次等待。这很容易理解:只要ssl缓冲区中有数据,新的字节不会从内核缓冲区中读取,因此select会继续报告它。
我只是检查['Modules/socketmodule.c',从'2485'的行](http://hg.python.org/cpython/file/3a1db0d2747e/Modules/socketmodule.c#l2485 )'sock_recv'被实现的地方,我可以向你保证python不*做任何缓冲。它会创建一个缓冲区,其大小正好是您用recv指定的大小,并且对系统调用recv的调用会跟踪剩余的字节并要求*表示多个字节,而不是更多(参见[this loop]( http://hg.python.org/cpython/file/3a1db0d2747e/Modules/socketmodule.c#l2439)) – Bakuriu
我发现,使用SSL插座时,这是唯一的发生,并添加示例代码,显示问题。 –
我的解决方案是增加缓冲区大小。我在代码中使用了'recv(4096)',但数据实际上是4726字节。将其更改为'recv(64 * 1024)'解决了缓冲和'select()'问题。 – Lekensteyn