2010-11-12 45 views
7

在客戶端,我有一個爲什麼我寫的這個服務器檢測不到客戶端已經關閉了它的套接字?

close(sockfd) 

其中的sockfd是已連接到服務器的插槽。 在我有了這個服務器:

if (sockfd.revents & POLLERR || 
    desc_set[i].revents & POLLHUP || desc_set[i].revents & POLLNVAL) { 
    close(sockfd.fd); 
    printf("Goodbye (connection closed)\n"); 
} 

其中的sockfd是一個結構的pollfd和sockfd.fd是客戶端的套接字的文件描述符。

當客戶端像我放在那裏關閉套接字時,服務器似乎沒有用第二個代碼(desc_set [i] .revents & POLLHUP等)檢測到它。

有誰知道有什麼問題?

回答

9

聽起來你已經設法從half close連接到客戶端。在這種狀態下,連接仍然可以在一個方向上發送數據,即它以半雙工模式工作。這是通過設計,並允許您的服務器完成對客戶發送的任何內容的答覆。通常這意味着完成文件傳輸並調用close(),或者回答查詢的所有方面。 在半關閉狀態下,您仍然可以非常明智地將數據發送到已稱爲close()的一側。在你的服務器上,如果你嘗試閱讀,你會看到eof。 close()只是意味着「我完成了發送,完成了我所要求的任何事情」。

POLLHUP,POLLERRPOLLNVAL只檢查本地連接的輸出端,這裏仍然有效。有一個POLLRDHUP,這是一個GNU擴展,應該檢測到對方關閉,但是你正在做的測試只是檢查它是否仍然可寫,而不是它是否仍然可讀。

另請參見this question,這是談論java,但仍然非常相關。

+0

對不起,我們要如何將這個GNU擴展插入到我的代碼中? – dasen 2010-11-12 16:05:19

+0

#define _GNU_SOURCE在任何#includes之前都會這樣做。使它自己的免費服務器調用close()一旦被服務請求是一個更好,更好的方法。 – Flexo 2010-11-12 16:07:12

+0

我已經使用了GNU擴展,但它仍然沒有在服務器端關閉。 – dasen 2010-11-12 16:11:11

4

遠程關閉或輸出關機既不是錯誤也不是掛機,也不是無效狀態。這是一個read事件,read()將返回零。只要將它作爲正常讀取處理的一部分來處理即可。

順便說一句,你上面的測試條件應該讀取sockfd.revents &(POLLERR | POLLHUP | POLLNVAL)。

+0

右 - 一個優雅的'close()'通過'read()'返回0來發信號,所以它由'POLLIN'指示。 – caf 2010-11-16 05:42:25

相關問題