我的問題類似於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