差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

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~~