2014-01-07 35 views
0

當我將套接字連接到服務器套接字並且在給定時間服務器套接字關閉時,我在客戶端獲得了BrokenPipeError。但是,下次我嘗試發送一些內容時,並不是在那之後。通過破損的管道發送數據

這裏一個SSCCE:

服務器:

#! /usr/bin/python3 

import socket 

s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) 
s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
s.bind (('', 10100)) 
s.listen (1) 
print ('Waiting on client') 
client, _ = s.accept() 
print ('Accepted') 
data = b'' 
done = False 
while not done: 
    data += client.recv (4096) 
    msgs = data.split (b'\r') 
    for msg in msgs [:-1]: 
     print ('received {}'.format (msg)) 
     done = msg == b'exit' 
    data = msgs [-1] 
s.close() 
print ('Server down') 

客戶:

#! /usr/bin/python3 

import socket 

s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) 
print ('Connecting') 
s.connect (('localhost', 10100)) 
print ('Connected') 
for msg in [b'ping', b'pang', b'exit', b'ping', b'pang']: 
    print ('Sending {}'.format (msg)) 
    sent = s.send (msg + b'\r') 
    print ('Sent {}. {} bytes transmitted'.format (msg, sent)) 
    input ('>> ') 

我啓動服務器,然後在客戶端和回車鍵來逐步的消息。

服務器輸出:

Waiting on client 
Accepted 
received b'ping' 
received b'pang' 
received b'exit' 
Server down 

客戶端輸出是:

Connecting 
Connected 
Sending b'ping' 
Sent b'ping'. 5 bytes transmitted 
>> 
Sending b'pang' 
Sent b'pang'. 5 bytes transmitted 
>> 
Sending b'exit' 
Sent b'exit'. 5 bytes transmitted 
>> 
Sending b'ping' 
Sent b'ping'. 5 bytes transmitted 
>> 
Sending b'pang' 
Traceback (most recent call last): 
    File "./client.py", line 10, in <module> 
    sent = s.send (msg + b'\r') 
BrokenPipeError: [Errno 32] Broken pipe 

爲什麼我得到BrokenPipeError最後pang之後,而不是後ping

爲什麼send在發送ping後返回5時exit

爲什麼在服務器關閉後不會立即損壞管道?


編輯:派遣exit後,我不打客戶端控制檯上輸入,除非在服務器控制檯已經印刷Server down

回答

1

發送功能只確保數據已被傳送到套接字緩衝區。當服務器關閉時,它發送一個FIN,ACK數據包,客戶端只回復ACK。客戶端的套接字在客戶端自己調用close方法之前不會關閉。該連接然後是「半開放」。

當客戶端再次發送數據到封閉的服務器套接字時,服務器回覆RST,客戶端可能會中止連接。有關半開連接和其他異常,請參閱http://tools.ietf.org/search/rfc793#page-33。但是,在發送方法返回後,套接字會關閉。這就是爲什麼只有下一次發送會在BrokenPipe上崩潰,因爲連接現在也從客戶端關閉。

+0

這就是爲什麼我把'輸入'放在客戶端。直到服務器控制檯上最後一個接收打印完成,我才按回車鍵。即使如此,我發現這種破碎型發送得太晚了。 'send'的返回值是什麼意思?那麼多的字節已經交給了操作系統?到我的網卡?或者與TCP相比,他們確實已經在另一邊收到了? – Hyperboreus

+0

我測試了運行Wireshark的代碼。當你調用close()時,看起來FIN,ACK是從服務器發送的。但是,客戶端不會像應該那樣發送FIN,ACK,甚至調用shutdown(SHUT_RDWR)。所以我猜想客戶端連接仍然是開放的。發送新數據時,所有字節都放入緩衝區,操作成功。但是,傳輸時客戶端收到一個RST,然後才關閉其套接字。因此下面的發送失敗。 [如何](http://docs.python.org/3.3/howto/sockets.html#using-a-socket)有一些有趣的信息。 – Cilyan

+0

在更好地審視您的問題後編輯答案。 – Cilyan