我的问题类似于python-select.select()如何工作?。但是,那里的解决方案对我不起作用,因为我没有打开()文件。相反,它是一个套接字。我找不到任何方法可以在文档中将其设置为不缓冲。
我有一个glib mainloop(使用select),在其中注册了要读取的套接字。因为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继续报告它。
在查看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()
这样就解决了问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句