2011-07-16 170 views
7

是我嗎,還是我可以找不到在python中的非阻塞套接字很好的教程?Python中的非阻塞套接字?

我不知道如何正確地在其中工作.recv.send。根據python文檔(至少我的理解),recv'ed或send'ed數據可能只是部分數據。那麼這是否意味着我必須以某種方式連接數據,而recv並確保所有數據通過send發送。如果是這樣,怎麼樣?一個例子將不勝感激。

+5

http://www.doughellmann.com/PyMOTW/select/ – Epeli

+0

您可能想區分send()和sendall()。 http://tarekziade.wordpress.com/2011/07/12/firefox-sync-python/另外你可能想使用一些像Eventlet這樣的高級異步IO框架:http://eventlet.net/ –

回答

8

你的套接字是否處於非阻塞模式並不重要,recv/send的工作幾乎相同;唯一的區別是非阻塞套接字拋出'資源暫時不可用'錯誤,而不是等待數據/套接字。

recv方法返回收到的字節數,它被告知小於或等於傳遞的bufsize。如果你想獲得準確大小字節,你應該做類似下面的代碼的東西:

def recvall(sock, size): 
    data = '' 
    while len(data) < size: 
    d = sock.recv(size - len(data)) 
    if not d: 
     # Connection closed by remote host, do what best for you 
     return None 
    data += d 
    return data 

記住這一點,在阻塞模式,你必須做同樣是很重要的。 (傳遞給應用層的字節數例如是在OS通過的recv緩衝器尺寸的限制。)

發送方法返回發送的字節數,其被告知要小於或等於傳遞的字符串的長度。 (根據文檔)誤差

def sendall(sock, data): 
    while data: 
    sent = sock.send(data) 
    data = data[sent:] 

您可以直接sock.sendall使用,但一個例外是:如果你要保證整個郵件的發送,你應該做類似下面的代碼的東西並且沒有辦法確定成功發送了多少數據(如果有的話)

Python中的套接字遵循BSD套接字API並且以類似於c樣式套接字的方式工作(不同之處在於,例如,它們拋出異常而不是返回錯誤代碼)。您應該對網絡上的任何套接字教程和聯機幫助頁感到滿意。

+0

感謝您接受@ultimatebuster,我剛剛意識到'recvall'中的錯誤處理並不是太好,並且添加了'如果不是d'來處理關閉的連接。 – tomasz

0

保留要發送到緩衝區中的字節。 (字節的字符串列表是最好的,因爲你沒有將它們串聯。)使用fcntl.fcntl功能設置在非阻塞模式套接字:

import fcntl, os 
fcntl.fcntl(mysocket, fcntl.F_SETFL, os.O_NONBLOCK) 

然後select.select會告訴你什麼時候可以讀取和寫入套接字。 (如果寫入不正確,會在非阻塞模式下出現EAGAIN錯誤。)寫入時,請檢查返回值以查看實際寫入的字節數。從你的緩衝區中消除很多字節。如果使用字符串列表方法,則每次只需要嘗試寫入第一個字符串。

如果您讀取空字符串,您的套接字已關閉。

+0

還有[ mysocket.setblocking(0)'](https://docs.python.org/2/library/socket.html#socket.socket.setblocking)。 –