差異處
這裏顯示兩個版本的差異處。
python:socket:send_resource_temporarilty_unvailable_error [2016/09/12 15:29] tony [How to resolve?] |
python:socket:send_resource_temporarilty_unvailable_error [2023/06/25 09:48] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | {{tag>python socket}} | ||
- | ====== socket.send with Resource temporarily unavailable error ====== | ||
- | ===== Problem ===== | ||
- | 我的python程式如下,目標是建立一個socket server等待連線,並將檔案給送到socket client: | ||
- | <code python> | ||
- | import socket | ||
- | import os | ||
- | import sys | ||
- | import stat | ||
- | from os.path import dirname, abspath, join | ||
- | def transmitDebugInfo(): | ||
- | filename = "/bootpart.gz" | ||
- | |||
- | debugfile = None | ||
- | s = None | ||
- | conn = None | ||
- | try: | ||
- | debugfile = open(filename,'rb') | ||
- | blocksize = os.path.getsize(filename) | ||
- | |||
- | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
- | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | ||
- | s.settimeout(60) | ||
- | s.bind(('0.0.0.0', 5555)) | ||
- | s.listen(1) | ||
- | conn, addr = s.accept() | ||
- | data = debugfile.read() | ||
- | conn.send(data) | ||
- | except: | ||
- | print sys.exc_info()[0] | ||
- | print sys.exc_info()[1] | ||
- | finally: | ||
- | if s is not None: | ||
- | s.close() | ||
- | if conn is not None: | ||
- | conn.close() | ||
- | if debugfile is not None: | ||
- | debugfile.close() | ||
- | |||
- | |||
- | transmitDebugInfo() | ||
- | </code> | ||
- | 我的client為了方便測試,是直接使用linux的nc command: | ||
- | <code bash> | ||
- | nc 192.168.0.1 5555 > test.txt | ||
- | </code> | ||
- | 然而,在VMWare ESXI6.0 u2下會出現以下錯誤: | ||
- | <code> | ||
- | <class `socket.error`> | ||
- | [Errno 11] Resource temporarilty unavaliable | ||
- | </code> | ||
- | ===== Diagnosis ===== | ||
- | ==== 實驗1 - 分批送+sleep ==== | ||
- | 首先我發現接收到的檔案大小一定是33304 bytes,於是我加了以下程式做試驗: | ||
- | <code python> | ||
- | print "bufsize = %s" % s.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) | ||
- | s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 5000) | ||
- | print "bufsize = %s" % s.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) | ||
- | </code> | ||
- | server程式輸出為: | ||
- | <code> | ||
- | bufsize = 32768 | ||
- | bufsize = 5000 | ||
- | </code> | ||
- | 而client輸出檔案大小則變為5792 bytes。我猜想可能和發送buffer有關,於是找了一台ubuntu 14.04做測試;沒想到雖然buffer size為16384卻能正常的發送完檔案。因此我猜測可能和buffer釋放時間有關,於是改寫了以下發送方式: | ||
- | <code python> | ||
- | while 1: | ||
- | data = debugfile.read(1024) | ||
- | if not data: break | ||
- | conn.send(data) | ||
- | time.sleep(0.000001) | ||
- | </code> | ||
- | 以每次1024 bytes發送,每次中間等待0.001秒,如此就能順利完成發送。但問我無法確定是由於send data thread搶了所有執行資源,造成buffer無法清空的問題;還是由於清buffer就是比較慢。在無法確認實際原因情況下,這方法我不敢使用。 | ||
- | ==== 實驗2 - Remove settimeout ==== | ||
- | 在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? ===== | ||
- | 根據實驗結果, | ||
- | |||
- | |||
- | |||
- | <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 ===== | ||
- | * [[https://fwengineer.blogspot.tw/2013/05/setsockopt.html|setsockopt]] | ||
- | * [[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://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]] | ||
- | |||
- | |||
- | ===== ===== | ||
- | ---- | ||
- | \\ | ||
- | ~~DISQUS~~ |