2016-03-21 66 views
0

我有一個使用gevent編寫的小型HTTP服務器,它接受傳入連接並使用每個連接的greenlet發回數據。當(本地)的客戶端死機服務器端寫入到客戶端儘管在CLOSE_WAIT狀態下的插座能夠成功:gevent tcp socket已斷開連接但可以發送數據

$ ls -l /proc/21860/fd |grep 22 
lrwx------. 1 mathieu mathieu 64 Mar 21 19:55 22 -> socket:[187093] 
$ lsof |grep 187093 
python 21860  mathieu 22u  IPv4    187093  0t0  TCP localhost.localdomain:36072->localhost.localdomain:48908 (CLOSE_WAIT) 

現在,我希望我gevent.socket.socket創建的套接字的發送方法失敗,但我沒有得到任何例外!

def send(socket, data): 
    sent = socket.send(data) 
    while sent != len(data): 
     data = data[sent:] 
     sent = socket.send(data) 

我的期望是不正確的?如果不是,這裏可能會出現什麼問題?

回答

0

經過一些調試後,事實證明,我對socket套接字API在TCP上的行爲的期望是錯誤的。潛在讀者可能想仔細閱讀TCP option SO_LINGER (zero) - when it's required

東西拿走:

  1. 客戶端的close()發送FIN到大概的意思是「我做你發送數據」的服務器。這意味着服務器可能仍然能夠發回數據。
  2. 如果服務器在客戶端關閉後嘗試寫入,則寫入將成功(返回從用戶空間複製到內核空間的字節數),數據將發送到客戶端,客戶端將發回RST,因爲其套接字仍然處於TIMEWAIT狀態(除非您使用SO_LINGER零來禁用這個功能,這就是爲什麼您不想將SO_LINGER設置爲零),服務器套接字狀態將更新爲CLOSED。
  3. 如果服務器在從客戶端接收到RST後嘗試第二次寫入,則寫入操作將失敗。
  4. 如果服務器在客戶端關閉後嘗試recv,則recv將返回零以指示流結束。

總結一下,這意味着我的服務器需要使用作爲recv()== 0返回的流結束通知作爲客戶端已經關閉其連接並相應採取行動的標誌(即,關閉相關的插座)。