差異處
這裏顯示兩個版本的差異處。
Both sides previous revision 前次修改 下次修改 | 前次修改 | ||
python:socket:send_resource_temporarilty_unvailable_error [2016/09/12 15:01] tony [實驗1] |
python:socket:send_resource_temporarilty_unvailable_error [2023/06/25 09:48] (目前版本) |
||
---|---|---|---|
行 51: | 行 51: | ||
[Errno 11] Resource temporarilty unavaliable | [Errno 11] Resource temporarilty unavaliable | ||
</code> | </code> | ||
- | ===== How to? ===== | + | ===== Diagnosis ===== |
==== 實驗1 - 分批送+sleep ==== | ==== 實驗1 - 分批送+sleep ==== | ||
首先我發現接收到的檔案大小一定是33304 bytes,於是我加了以下程式做試驗: | 首先我發現接收到的檔案大小一定是33304 bytes,於是我加了以下程式做試驗: | ||
行 74: | 行 74: | ||
以每次1024 bytes發送,每次中間等待0.001秒,如此就能順利完成發送。但問我無法確定是由於send data thread搶了所有執行資源,造成buffer無法清空的問題;還是由於清buffer就是比較慢。在無法確認實際原因情況下,這方法我不敢使用。 | 以每次1024 bytes發送,每次中間等待0.001秒,如此就能順利完成發送。但問我無法確定是由於send data thread搶了所有執行資源,造成buffer無法清空的問題;還是由於清buffer就是比較慢。在無法確認實際原因情況下,這方法我不敢使用。 | ||
==== 實驗2 - Remove settimeout ==== | ==== 實驗2 - Remove settimeout ==== | ||
- | 在remove settimeout後,socket存取等同於blocking IO。 | + | 在remove settimeout後,就可以正常傳送與接收資料;沒設定timeout等效於setblocking(1)。 |
+ | ==== 實驗3 - setdefaulttimeout ==== | ||
+ | 我在建立socket前,使用socket.setdefaulttimeout(60),發現可以正常傳送與接收資料。這挺奇怪的,我還不曉得這與settimeout有何不同。 | ||
+ | ==== 實驗4 - 使用strace去跑分批送 ==== | ||
+ | 與實驗1的區別在於,我移除sleep並透過strace去執行也可以正常執行完畢。 | ||
+ | <code bash> | ||
+ | strace -o output.txt -s512 python test.py | ||
+ | </code> | ||
+ | 我猜測透過strace可能也造成send資料之間的延遲,好讓buffer有足夠時間釋放。 | ||
+ | ===== How to resolve? ===== | ||
+ | 根據實驗結果,有以下結論: | ||
+ | - 實驗二說明在blocking mode下,sendall應能正常傳送資料。實驗三為例外,原因還不明。 | ||
+ | - 實驗一與四說明,如果將send分批進行且有緩衝,應能正常傳送資料。 | ||
+ | - 並非所有OS有相同結果,可能與python或內核有關。 | ||
+ | 綜合以上,如果要設定timeout,安全作法應該使用non-blocking IO的存取方式。因此參考[[https://vaidik.in/blog/understanding-non-blocking-io-with-python-part-1.html|此篇文章]]修改程式碼,針對Resource temporarilty unavaliable錯誤retry: | ||
+ | <code python> | ||
+ | def sendData(sock, data): | ||
+ | total_sent = 0 | ||
+ | while len(data): | ||
+ | try: | ||
+ | sent = sock.send(data) | ||
+ | total_sent += sent | ||
+ | data = data[sent:] | ||
+ | print 'Sending data' | ||
+ | except socket.error, e: | ||
+ | if e.errno != errno.EAGAIN: | ||
+ | raise e | ||
+ | print 'Blocking with', len(data), 'remaining' | ||
+ | select.select([], [sock], []) | ||
+ | return total_sent | ||
+ | </code> | ||
+ | 呼叫程式改為: | ||
+ | <code python> | ||
+ | data = debugfile.read() | ||
+ | total_data = len(data) | ||
+ | total_send = sendData(conn, data) | ||
+ | print "data size = %s, send size = %s" % (total_data, total_send) | ||
+ | </code> | ||
===== Reference ===== | ===== Reference ===== | ||
* [[https://fwengineer.blogspot.tw/2013/05/setsockopt.html|setsockopt]] | * [[https://fwengineer.blogspot.tw/2013/05/setsockopt.html|setsockopt]] | ||
* [[http://stackoverflow.com/questions/6645851/multiprocessing-manager-rlock-error|multiprocessing > Manager() > RLock Error:]] | * [[http://stackoverflow.com/questions/6645851/multiprocessing-manager-rlock-error|multiprocessing > Manager() > RLock Error:]] | ||
* [[https://github.com/patmun/pynetdicom/pull/47|introduce configurable client socket receive timeout]] | * [[https://github.com/patmun/pynetdicom/pull/47|introduce configurable client socket receive timeout]] | ||
+ | * [[https://docs.python.org/2/library/socket.html|python doc - socket]] | ||
+ | * [[https://vaidik.in/blog/understanding-non-blocking-io-with-python-part-1.html|Understanding Non Blocking I/O with Python - Part 1]] | ||