2015-12-03 276 views
-1

在C++中,如何檢測客戶端的連接是否丟失了幾秒鐘,比如說30秒。即使客戶端不響應超過30秒(例如,服務器正在等待客戶端回覆),只要連接仍然建立,它就不會丟失連接。C++ TCP檢測客戶端是否已斷開連接數秒

#include <string.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <iostream> 
#include <fstream> 
#include <strings.h> 
#include <stdlib.h> 
#include <string> 
#include <pthread.h> 
#include <unistd.h> 

#include <vector> 
#include <thread> 

using namespace std; 

static int connFd; 
void error(const char *msg){ 
    perror(msg); 
    exit(1); 
} 

void task1 (int connFd){ 
    //CEstablish timeut connection for client 
    struct timeval timeout;  
    timeout.tv_sec = 30; 
    timeout.tv_usec = 0; 

    if (setsockopt (connFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, 
       sizeof(timeout)) < 0) 
     error("setsockopt failed\n"); 

    if (setsockopt (connFd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, 
       sizeof(timeout)) < 0) 
     error("setsockopt failed\n"); 


    cout << "Thread No: " << pthread_self() << endl; 
    char test[256]; 
    bzero(test, 256); 
    bool loop = false; 
    int n = write(connFd,"I got your message",18); 
    if (n < 0) error("ERROR writing to socket"); 
    while(!loop){  
     bzero(test, 256);  
     int n = read(connFd, test, 255); 
     if (n < 0) { 
     //error("ERROR reading from socket"); 

     cout << " ERROR " << endl; 
     break; 
     } 
     printf("Here is the message: %s\n",test); 
     //n = write(connFd,"I got your message",18); 
     //if (n < 0) error("ERROR end to socket"); 
     //string tester (test); 
     //cout << tester << endl;  
     //if(tester == "exit") 
      //break; 
    } 
    cout << "\nClosing thread and conn" << endl; 
    close(connFd); 
} 

int main(int argc, char* argv[]){ 
    int pId, portNo, listenFd; 
    socklen_t len; //store size of the address 
    bool loop = false; 
    struct sockaddr_in svrAdd, clntAdd; 

    pthread_t threadA[3]; 
    std::vector<std::thread> threads; 
    if (argc < 2) 
    { 
     cerr << "Syntam : ./server <port>" << endl; 
     return 0; 
    } 

    portNo = atoi(argv[1]); 

    if((portNo > 65535) || (portNo < 2000)) 
    { 
     cerr << "Please enter a port number between 2000 - 65535" << endl; 
     return 0; 
    } 

    //create socket 
    listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 

    if(listenFd < 0) 
    { 
     cerr << "Cannot open socket" << endl; 
     return 0; 
    } 

    bzero((char*) &svrAdd, sizeof(svrAdd)); 

    svrAdd.sin_family = AF_INET; 
    svrAdd.sin_addr.s_addr = INADDR_ANY; 
    svrAdd.sin_port = htons(portNo); 

    //bind socket 
    if(bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0) 
    { 
     cerr << "Cannot bind" << endl; 
     return 0; 
    } 

    listen(listenFd, 5); 

    int noThread = 0; 

    while (noThread < 3) 
    { 
     socklen_t len = sizeof(clntAdd); 
     cout << "Listening" << endl; 

     //this is where client connects. svr will hang in this mode  until client conn 
     connFd = accept(listenFd, (struct sockaddr *)&clntAdd, &len); 

     if (connFd < 0) { 
      cerr << "Cannot accept connection" << endl; 
      return 0; 
     } 
     else { 
      cout << "Connection successful" << endl; 
     } 
     ///thread t(&task1,connFd); 
     threads.push_back(std::thread(task1,connFd)); 
     //pthread_create(&threadA[noThread], NULL, task1, NULL); 
     noThread++; 
    } 

    for(auto && t : threads) 
     t.join(); 

    /*for(int i = 0; i < 3; i++) 
    { 
     pthread_join(threadA[i], NULL); 
    }*/ 


} 

上面代碼的問題是,如果客戶沒有在30秒內發送到服務器的任何答覆的,將被視爲連接丟失甚至連接仍然成立。

+1

這太寬泛了。請縮小範圍。也許顯示你的服務器代碼,你有麻煩執行此。也可以查看'select()'或'(e)poll()'來檢測套接字連接上的讀取超時。 –

+0

我已經添加了我的服務器代碼 – ZZZ

回答

1

設置超時套接字選項後,你的閱讀循環做到這一點:

while(!loop){  
    bzero(test, 256);  
    int n = read(connFd, test, 255); 
    if (n < 0) { 
    cout << " ERROR " << endl; 
    break; 
    } 
    printf("Here is the message: %s\n",test); 
} 
cout << "\nClosing thread and conn" << endl; 
close(connFd); 

現在,超時read()將返回-1,讓你打破和close(connFd);。這解釋了你描述的問題:

上述代碼的問題是,如果客戶端在30秒內未向服務器發送任何答覆,則即使連接仍然建立,它將被視爲連接丟失。

這不是關閉連接的套接字庫 - 它是您的close調用。相反,處理read()返回-1errnoEAGAINEWOULDBLOCK在一些不關閉連接的其他方式。

0

上面代碼的問題是,如果客戶端在30秒內沒有發送任何答覆到服務器,即使連接仍然建立,它將被視爲連接丟失。

只是因爲你試圖區分錯誤條件。

  • 如果你讀超時,errno == EAGAIN/EWOULDBLOCK,連接還活着,你應該採取任何適當的動作來讀超時。
  • 如果從recv(),然後得到任何其他錯誤,您應該考慮連接斷開。
  • 如果你從send()得到任何錯誤,你應該認爲連接關閉,你根本沒有做,你忽略它。

你的代碼的另一個問題是你沒有檢測到流結束。如果recv()返回零,則對等體已完全斷開,您應關閉套接字並停止讀取。

相關問題