2013-12-20 93 views
1

我正在編寫一個通過套接字發送數據的應用程序(從客戶端到服務器)。我觀察到非常奇怪的行爲:當我殺死服務器,首先發送後,殺死行爲像服務器存在。下一個返回EPIPE。你能解釋我爲什麼嗎?sendto()到不存在的套接字

這裏是從客戶端應用程序strace的:

(server not killed) 
... 
sendto(5, "\0\1\0\0\0\0\0\0000\311\0\0\211A\264R\0\0\0\0\232\377\4\0\0\0\0\0\0\0\0\0"..., 51516, MSG_NOSIGNAL, NULL, 0) = 51516 
.... 
(server killed) 
****sendto(5, "\0\1\0\0\1\0\0\0000\311\0\0\272A\264R\0\0\0\0c%\0\0\0\0\0\0\0\0\0\0"..., 51516, MSG_NOSIGNAL, NULL, 0) = 51516,**** 
(next send after server is killed) 
sendto(5, "\0\1\0\0\2\0\0\0000\311\0\0\375A\264R\0\0\0\0d\307\n\0\0\0\0\0\0\0\0\0"..., 51516, MSG_NOSIGNAL, NULL, 0) = -1 EPIPE (Broken pipe) 

問候 Ĵ

+0

什麼協議是套接字? UDP? TCP? –

+0

對不起,忘了提及:即時通訊使用TCP套接字 – JosiP

+1

服務器應用程序本身是否打開TCP連接?還是繼承了它或從另一個過程中獲得了它?其他進程是否可以擁有該套接字的副本?服務器是否通過連接調用'fork'並且不關閉它在孩子中? (可以有很多解釋,這並不特別。) –

回答

2

TCP並不能保證一個切斷連接將被檢測,直到你嘗試發送它的一些數據。一旦你嘗試,你可能會收到來自網絡的錯誤,或者發送操作可能會超時。由於應用程序級別的TCP寫入只會在可用緩衝區空間不足的情況下阻塞,因此通常會在可以報告這些錯誤的下一個操作中報告錯誤。

儘管通常立即檢測到斷開的連接,但並非總是如此,並且不能保證是。確切的原因可能因我們不知道的許多因素而異。 (TCP連接是由服務器應用程序本身打開的嗎?還是繼承它或從另一個進程獲得?是否有其他進程擁有該套接字的副本?服務器是否調用fork的連接並且不關閉它?)

1

在TCP中,連接的兩個方向獨立運行。當服務器關閉連接時,它會在服務器 - >客戶端方向發送一條消息,表明它已完成傳輸;如果客戶端執行read()recv(),那麼它將在此時獲得EOF。

但是,此消息沒有提到客戶端 - >服務器方向。 TCP不提供任何方式讓服務器告訴客戶端它不願意再讀取任何數據。因此客戶無法知道發送失敗之前,它會嘗試發送它。

當服務器從客戶端接收到新消息時,如果沒有服務器進程仍在嘗試從連接中讀取數據,則服務器會向客戶端發送一條消息RST。這是異步的 - 客戶機上的sendto()調用已經返回(事實上,在將任何數據發送到網絡之前,它將數據複製到內核緩衝區後立即返回)。當客戶端TCP堆棧收到RST消息時,它會在套接字上設置一個error標誌,並在客戶端嘗試對該套接字執行任何操作時產生EPIPE錯誤,然後下一步

相關問題