2010-03-14 69 views
10

我想測試一個封閉的套接字已被對方正常關閉,而不會發生雙重發送的延遲命中以誘發SIGPIPE測試一個封閉的套接字

這裏的假設之一是,如果關閉的套接字在上次寫入/發送之後立即由對方正常關閉。像過早關閉一樣的實際錯誤會在代碼中的其他地方處理。

如果套接字仍然打開,將會有0或更多字節的數據,我實際上不想從套接字緩衝區中取出數據。

我在想我可以撥打int ret = recv(sockfd, buf, 1, MSG_DONTWAIT | MSG_PEEK);來確定套接字是否仍然連接。如果已連接,但緩衝區中沒有數據,我將返回-1errno == EAGAIN並返回sockfd以供重用。如果它已被對方優雅地關閉,我會得到ret == 0並打開一個新的連接。

我測試過了,它好像工作。但是,我懷疑當我收到我的數據的最後一位和當對方FIN到達時,我可以從我的測試recv中獲得假陽性EAGAIN

這是咬我還是有更好的方法呢?

+0

另一種方法是select()(或poll()),因爲它可以控制fd讀取和寫入,但我不知道它是否真正解決了有關FIN時序的問題。 – 2010-03-14 11:25:21

+0

@Giuseppe:不,我不認爲select會解決計時問題。 – 2010-03-14 12:40:41

回答

3

OK,所以我跑了一些測試,這是我發現了什麼。

我將客戶端設置爲向服務器發送HTTP/1.1 Connection: close消息,導致服務器在上次寫入數據後調用close。當我的客戶端完成從GET事務中讀取數據時,它將測試套接字以查看它是否仍然使用上述方法打開,然後嘗試發出另一個GET。

我發現大約有30%的時間在服務器的FIN到達之前發生,導致誤報和失敗的操作。

也許唯一可以讓這種合理可靠的方法,比方說接近99%的方法是引入與最後一次讀取和試圖重新使用套接字之間的連接延遲有關的人爲延遲 - 但是,這幾乎會導致性能下降。

所以,我不得不得出結論,雖然這個工具是有用的,但它只是勉強如此。

+1

+1:有趣的測試。人們可以理解爲什麼在電信中90%的代碼用於管理異常行爲:) – neuro 2010-03-16 11:39:23

0

你控制另一端嗎?執行「乾淨」關閉套接字的最可靠方法是爲另一端發送某種「再見」消息。

+1

不,我不控制另一端。但是,另一端**應始終發送一個應用程序級別的消息,指出它們正在結束。只是在現實世界中並不總是會發生。我可以把它當作一個常規錯誤來對待,但我想嘗試並在大部分時間裏積極地抓住它。 – 2010-03-14 12:39:25

0

(略爲「偏離主題」,不好意思)。也許this discussion可能對你有幫助四。它仍然沒有回答你「FIN」的問題,但可以幫助你在程序發送時以更簡單的方式響應同行關機。

再見