C ++ TCP检测客户端是否已断开连接几秒钟

时间:2015-12-03 03:09:50

标签: c++ tcp

在C ++中,如何检测与客户端的连接是否已经丢失了几秒钟,让我们说30秒。即使客户端响应超过30秒(例如,服务器正在等待客户端回复),只要连接仍然建立,它就不会丢失连接。

#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秒内没有向服务器发送任何回复,即使连接仍然建立,也会被视为连接丢失。

2 个答案:

答案 0 :(得分: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()-1errnoEAGAIN返回EWOULDBLOCK,以其他方式关闭连接。

答案 1 :(得分:0)

  

上述代码的问题是,如果客户端在30秒内没有向服务器发送任何回复,即使连接仍然建立,也会被视为连接丢失。

只是因为你没有尝试区分错误条件。

  • 如果您获得了读取超时errno == EAGAIN/EWOULDBLOCK,则连接仍处于活动状态,您应该采取适当的操作来执行读取超时。
  • 如果您从recv()然后收到任何其他错误,您应该认为连接已断开。
  • 如果您从send()收到任何错误,那么您会认为连接已关闭,而您根本没有这样做,您忽略了它。

您的代码的另一个问题是您没有检测到流的结尾。如果recv()返回零,则对等方已完全断开连接,您应关闭套接字并停止读取。