如何在C中查找套接字连接状态?

如何在C中查找套接字连接状态?,c,network-programming,C,Network Programming,我有一个TCP连接。服务器只是从客户端读取数据。现在,如果连接丢失,客户端将在将数据写入管道(断开的管道)时出错,但服务器仍在侦听该管道。是否有任何方法可以确定连接是否已打开?您可以按如下方式调用getsockopt: int error = 0; socklen_t len = sizeof (error); int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len); 要测试插座是否打开,请

我有一个TCP连接。服务器只是从客户端读取数据。现在,如果连接丢失,客户端将在将数据写入管道(断开的管道)时出错,但服务器仍在侦听该管道。是否有任何方法可以确定连接是否已打开?

您可以按如下方式调用getsockopt:

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (socket_fd, SOL_SOCKET, SO_ERROR, &error, &len);
要测试插座是否打开,请执行以下操作:

if (retval != 0) {
    /* there was a problem getting the error code */
    fprintf(stderr, "error getting socket error code: %s\n", strerror(retval));
    return;
}

if (error != 0) {
    /* socket has a non zero error status */
    fprintf(stderr, "socket error: %s\n", strerror(error));
}

对于BSD插座,我想退房。当recv返回0时,您知道另一侧已断开连接


现在你可能会问,检测另一侧断开连接的最简单方法是什么?一种方法是让线程始终执行recv。当客户端断开连接时,该线程将能够立即判断

TCP keepalive套接字选项(SO_keepalive)在这种情况下会有所帮助,并在连接丢失时关闭服务器套接字。

可靠检测套接字是否仍然连接的唯一方法是定期尝试发送数据。定义客户端忽略的应用程序级“ping”数据包通常更方便,但是如果已经指定了没有这种功能的协议,那么您应该能够通过设置套接字选项来配置tcp套接字来实现这一点。我已经链接到winsock文档,但是在所有类似BSD的套接字堆栈上都应该有相同的功能。

我遇到了类似的问题。我想知道服务器是连接到客户端还是客户端连接到服务器。在这种情况下,recv函数的返回值可以派上用场。如果套接字未连接,它将返回0字节。因此,我使用它打破了循环,不必使用任何额外的函数线程。如果专家认为这是正确的方法,你也可以使用同样的方法

获取sock opt可能有些有用,但是,另一种方法是为SIGPIPE安装信号处理程序。基本上,每当套接字连接中断时,内核都会向进程发送一个SIGPIPE信号,然后您就可以执行所需的操作。但这仍然不能提供了解连接状态的解决方案。希望这有帮助。

您应该尝试使用:getpeername函数

现在,当连接断开时,您将进入errno: ENOTCONN-套接字未连接。 这意味着你会失望

否则(如果没有其他故障),返回代码将为0-->这意味着向上

资源:
手册页:

您可以在
getsockopt()
函数中使用
SS\u ISCONNECTED
宏。
SS_ISCONNECTED
是在
socketvar.h

中定义的,有一种简单的方法可以通过
poll
调用检查套接字连接状态。首先,您需要轮询套接字,它是否有
POLLIN
事件

  • 如果套接字未关闭且有数据要读取,则
    read
    将返回大于零的值
  • 如果套接字上没有新数据,则
    POLLIN
    将在
    revents
  • 如果套接字关闭,则
    POLLIN
    标志将设置为1,read将返回0
  • 下面是一段小代码片段:

    int client_socket_1, client_socket_2;
    if ((client_socket_1 = accept(listen_socket, NULL, NULL)) < 0)
    {
        perror("Unable to accept s1");
        abort();
    }
    if ((client_socket_2 = accept(listen_socket, NULL, NULL)) < 0)
    {
        perror("Unable to accept s2");
        abort();
    }
    pollfd pfd[]={{client_socket_1,POLLIN,0},{client_socket_2,POLLIN,0}};
    char sock_buf[1024]; 
    while (true)
    {
        poll(pfd,2,5);
        if (pfd[0].revents & POLLIN)
        {
            int sock_readden = read(client_socket_1, sock_buf, sizeof(sock_buf));
            if (sock_readden == 0)
                break;
            if (sock_readden > 0)
                write(client_socket_2, sock_buf, sock_readden);
        }
        if (pfd[1].revents & POLLIN)
        {
            int sock_readden = read(client_socket_2, sock_buf, sizeof(sock_buf));
            if (sock_readden == 0)
                break;
            if (sock_readden > 0)
                write(client_socket_1, sock_buf, sock_readden);
        }
    }
    
    int client_socket_1,client_socket_2;
    如果((客户端\u套接字\u 1=accept(侦听\u套接字,NULL,NULL))<0)
    {
    perror(“无法接受s1”);
    中止();
    }
    if((客户端\u套接字\u 2=accept(侦听\u套接字,NULL,NULL))<0)
    {
    perror(“无法接受s2”);
    中止();
    }
    pollfd pfd[]={{client_socket_1,POLLIN,0},{client_socket_2,POLLIN,0};
    char sock_buf[1024];
    while(true)
    {
    投票(pfd,2,5);
    if(pfd[0]。revents和POLLIN)
    {
    int sock_readden=read(client_socket_1,sock_buf,sizeof(sock_buf));
    if(sock_readden==0)
    打破
    如果(sock_readden>0)
    写入(客户端套接字2、套接字buf、套接字readden);
    }
    if(pfd[1]。收入和收入)
    {
    int sock_readden=read(client_socket_2,sock_buf,sizeof(sock_buf));
    if(sock_readden==0)
    打破
    如果(sock_readden>0)
    写入(客户端套接字1、套接字buf、套接字readden);
    }
    }
    
    非常简单,如图中所示

    要检查是否需要使用
    MSG\u PEEK
    MSG\u DONT\u WAIT
    从套接字读取1字节。这不会使数据出列(
    PEEK
    ),并且操作是非阻塞的(
    DONT_WAIT


    找到示例。

    在Windows上,您可以使用以下命令查询任何网络适配器上任何端口的精确状态:

    您可以将其过滤到与流程等相关的内容,并根据需要定期监控。这是一种“替代”方法


    您还可以复制套接字句柄,在套接字上设置IOCP/重叠i/o等待,并以这种方式对其进行监视。

    我认为您应该澄清是为windows还是linux/unix开发。发送错误结果时,您应该首先检查它实际上是什么错误,然后确定这是否是一个可恢复的错误(也许它能自己修复吗?)或者,如果这意味着您的连接肯定已断开。如果确实已断开,请关闭套接字。如果您仍然可以获得任何流量,则另一方将看到套接字已关闭。如果无法获得任何流量,则仍将丢失。在这种情况下,另一方可以注意到的唯一方法是发送本身应触发的内容一个回复,如果没有这样的回复,那么另一方就死了。不,不会。tcp堆栈只能在以下情况下检测套接字是否关闭:(a)它接收到来自另一方的数据包,或者(b)等待已发送数据包的ack时超时。对于recv,如果中间路由器停机或远程主机异常关闭套接字(未发送关闭消息),将不会有数据包到达以警告套接字堆栈recv正在等待关闭连接。但它不会检测到无声中断的套接字。常见的情况是,中间的NAT网关超时连接(和)
    while (recv(client->socket,NULL,1, MSG_PEEK | MSG_DONTWAIT) != 0) {
        sleep(rand() % 2); // Sleep for a bit to avoid spam
        fflush(stdin);
        printf("I am alive: %d\n", socket);
    }
    
    // When the client has disconnected, this line will execute
    printf("Client %d went away :(\n", client->socket);