2011-11-16 48 views
2

我錯過了什麼?發送成功嗎?

我有非常簡單的客戶端和服務器。服務器使用recv超時(使用select)3秒鐘。然後它是shutdown s和close的插座和出口。

客戶端連接到服務器,睡30秒併發送非常短的消息。在服務器關閉插座並退出後約27秒。
send不會失敗..?爲什麼?爲什麼它不會返回錯誤-1


請注意:我削減返回代碼所有檢查並刪除所有日誌,使這個短,我可以。此外,我刪除了所有內容,以縮短這個時間。但它是一個真實的代碼。

客戶端代碼:

int main(int argc, char* argv[]) 
{ 
    addrinfo hints; 
    memset(&hints, 0, sizeof hints); // make sure the struct is empty 

    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; // TCP stream sockets 

    addrinfo *res; 
    getaddrinfo("127.0.0.1", "1313", &hints, &res); 
    int nSocketFD = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 
    assert(-1 != connect(nSocketFD, res->ai_addr, res->ai_addrlen)); 
    freeaddrinfo(res); // free the linked-list, we don't need it anymore 

    sleep(30); 
    if(send(nSocketFD, "bla", 4, 0) > 0) 
    { 
     printf("Message successfully sent!\n"); 
    } 

    close(nSocketFD); 

    return 0; 
} 

和服務器:

int main() 
{ 
    addrinfo hints; 
    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; 

    addrinfo *res; // will point to the results 
    getaddrinfo(NULL, "1313", &hints, &res); 
    int nSocketFD = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 
    bind(nSocketFD, res->ai_addr, res->ai_addrlen); 
    freeaddrinfo(res); // free the linked-list 
    listen(nSocketFD, 1); 

    sockaddr_storage their_addr; 
    socklen_t addr_size = sizeof(sockaddr_storage); 
    int nAcceptedSocket = accept(nSocketFD, (sockaddr*)&their_addr, &addr_size); 
    assert(-1 != nAcceptedSocket); 

    fd_set fds; 
    FD_ZERO(&fds); 
    FD_SET(nAcceptedSocket, &fds); 
    timeval tv; 
    tv.tv_sec = 3; 
    tv.tv_usec = 0; 

    if(0 == select(nAcceptedSocket + 1, &fds, NULL, NULL, &tv)) 
    { 
     printf("recv timeout! Exiting..\n"); 
     shutdown(nSocketFD, SHUT_RDWR); 
     close(nSocketFD); 
     shutdown(nAcceptedSocket, SHUT_RDWR); 
     close(nAcceptedSocket); 
     return 1; 
    } 
    assert(false); 
    return 0; 
} 

當我執行它,我看到消息recv超時和成功發送的消息。

對不起,很可能是愚蠢的問題。

回答

3

一般而言,您需要從套接字中讀取以使其注意到遠程端已關閉連接。

send手冊頁面(這只是write但標誌):

No indication of failure to deliver is implicit in a send(). Locally 
detected errors are indicated by a return value of -1. 
+0

這是不正確的。選擇,(e)輪詢可以做到這一點... –

+0

@yi_H'select'等人將返回一個套接字在連接關閉時可讀,但你仍然必須從實際套接字中讀取以獲得該錯誤。 –

+0

OMG(facepalm)(facepalm)(facepalm)我讀了'send'和'recv'的手冊頁,不知何故,我認爲,就像'recv','send'將返回0,以防連接從其他方面:XI認爲今天10h工作就夠了。非常感謝! –

1

你沒有不關閉系統在用戶端插座 - 所以這有效的套接字。從發送()的手冊頁

No indication of failure to deliver is implicit in a send(). Locally detected errors are indicated by a return value of -1. 

我們有這個問題與我們的一些軟件的 - 如果網絡硬件沿線某處出現故障,且被帶回來了 - 然後兩端仍然認爲插座是否有效 - 如果沒有keepalives探測器 - 它會保持這種狀態。

補充說: 看一看socket選項(人setsockopt的和男人TCP)SO_KEEPALIVE

從TCP手冊頁 tcp_keepalive_intvl(整數;默認:75;因爲Linux 2.4) 秒TCP之間的數目保持活性探針。

tcp_keepalive_probes (integer; default: 9; since Linux 2.2) 
      The maximum number of TCP keep-alive probes to send before giving up and killing the connection if no response is obtained from the other end. 

    tcp_keepalive_time (integer; default: 7200; since Linux 2.2) 
      The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes. Keep-alives are only sent when the SO_KEEPALIVE socket option is enabled. The default value is 7200 seconds (2 hours). An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval of 75 seconds apart) when keep-alive is enabled. 

      Note that underlying connection tracking mechanisms and application timeouts may be much shorter. 
+0

我不需要關閉客戶端中的套接字。我需要檢測,服務器已經走了。無論如何 –

+0

對不起 - 應該更清楚 - 我的意思是套接字,如果在客戶端有效 - 所以它會高興地接受數據發送 –

+0

是的,你完全正確的。我只是認爲我讀了'send'返回'0',以防連接從另一端關閉。我只是將'recv'手冊頁與'send'混合在一起:)所以,我的問題是通過添加'recv'(非阻塞)來檢查連接是否仍然可用。我不知道這是否是最好的解決方案,但它絕對可以解決我的問題:) –