我的问题类似于 python - How select.select() works? 。但是,那里的解决方案对我不起作用,因为我没有打开()我的文件。相反,它是一个套接字。我找不到任何方法将其设置为无缓冲 documentation .
我有一个glib mainloop(它使用select),我在其中注册了用于读取的套接字。因为 socket.recv() 要求我指定接收缓冲区大小,所以读取的字节数少于套接字读取的字节数并不罕见。只要内核缓冲它们就可以了; select 仍会将套接字标记为“准备读取”。但显然 Python 也有一个缓冲区。对于大文件,在数据流末尾附近,recv() 将读取其中的一部分,其余部分将由 Python 缓冲,并且 select 不再在我的套接字上触发,直到发送新数据。此时,“丢失”的数据先于新数据被接收;没有数据丢失。
我的问题是:我该如何解决这个问题?有没有办法禁用Python套接字上的缓冲区?如果不是,有没有办法检查缓冲区是否为空,这样我就可以确保在缓冲区为空之前我不会从回调中返回?
编辑:
正如评论中所指出的,Python 不会向套接字添加额外的缓冲区,因此这不可能是问题。我无法为该问题创建一个最小的示例。不过,这似乎可能与使用 ssl 套接字有关。我忘记了我使用了加密连接;禁用加密似乎可以解决这个问题,但对我来说是 Not Acceptable 。所以上面的问题仍然存在,请注意缓冲区可能是在 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程序将建立连接。发送超过一个字节的数据将使程序只打印第一个字节;当发送更多字节时,首先读取剩余的 block ,然后读取第一个新字节,然后再次等待。这很容易理解:只要ssl缓冲区中有数据,就不会从内核缓冲区读取新字节,因此select继续报告它。
最佳答案
查看 ssl 源代码,我发现一个未记录的函数可以执行我想要的操作:pending()。它可以像这样使用:
#!/usr/bin/python
import glib
import socket
import ssl
def cb(fd, cond):
print('data: %s' % repr(s.read(1)))
while(s.pending()):
print('more 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()
这解决了问题。
关于python - 如何将 select 与 Python ssl 套接字缓冲一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21663705/