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

时间:2010-11-10 07:10:14

标签: c network-programming

我有TCP连接。服务器只是从客户端读取数据。现在,如果连接丢失,客户端在将数据写入管道(断开的管道)时会出错,但服务器仍会侦听该管道。如果连接是UP还是NOT,我能找到任何方法吗?

11 个答案:

答案 0 :(得分:33)

您可以像下面这样调用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));
}

答案 1 :(得分:11)

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

答案 2 :(得分:3)

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

答案 3 :(得分:2)

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

您应该尝试使用: getpeername 功能。

现在当连接断开时,你将进入errno: ENOTCONN - 插座未连接。 这对你意味着下降。

else(如果没有其他失败)返回代码将为0 - >这意味着UP。

<强>资源: 手册页:http://man7.org/linux/man-pages/man2/getpeername.2.html

答案 6 :(得分:1)

There is an easy way to check socket connection state via poll call. First, you need to poll socket, whether it has POLLIN event.

  1. If socket is not closed and there is data to read then read will return more than zero.
  2. If there is no new data on socket, then POLLIN will be set to 0 in revents
  3. If socket is closed then POLLIN flag will be set to one and read will return 0.

Here is small code snippet:

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);
    }
}

答案 7 :(得分:0)

您可以在SS_ISCONNECTED函数中使用getsockopt()宏。 SS_ISCONNECTED中定义了socketvar.h

答案 8 :(得分:0)

非常简单,如recv所示。

要检查您是否想使用MSG_PEEKMSG_DONT_WAIT从套接字读取1个字节。这不会使数据(PEEK出队,并且操作是非阻塞(DONT_WAIT

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);

找到了示例here

答案 9 :(得分:0)

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

您可以仅将其筛选为与过程相关的内容,并根据需要定期进行监视。这是一种“替代”方法。

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

答案 10 :(得分:-2)

对于BSD套接字,我会查看Beej's guide。当recv返回0时,您知道另一侧已断开连接。

现在您可能真的在问,检测对方断开连接的最简单方法是什么?一种方法是让一个线程总是做一个recv。该线程将能够立即告知客户端何时断开连接。