【问题标题】:Check connection open or closed ?(in C in Linux)检查连接打开或关闭?(在 Linux 中的 C 中)
【发布时间】:2010-12-20 04:38:12
【问题描述】:

在 Linux 的套接字编程中,我需要在套接字中写入数据,但我不知道套接字是打开还是关闭。我如何知道套接字是打开和关闭而不读取?

printf("befor read%d\n", n);
bzero(buffer, MAX_SIZE_BUFFER);
n = read(sockfd, buffer, MAX_SIZE_BUFFER - 1);
printf("after read%d\n", n);
if (n <= 0)
{
    break;
}
printf("befor write%d, s: %d \n", n , sockfd);

n = write(newsockfd, buffer, n);
if (n <= 0)
{
    break;
}

我从 sockfd 读取,我确定这个连接是打开的。什么时候在newsockfd中写入缓冲区我不知道newsockfd是打开还是关闭如何检查newsockfd是否关闭?


我知道问题。在写作过程中连接关闭。例如在 500 个连接关闭和程序关闭中写入 1024 个数据。如何避免这种情况?

【问题讨论】:

    标签: c linux sockets network-programming


    【解决方案1】:

    令人惊讶的是,检查是否可以写入套接字的方法是尝试写入它:-)

    如果套接字已关闭,您将从write 获得-1 返回码,您可以检查errno 以查看问题所在。

    如果套接字仍然有效,但此时您不能写入任何数据,write 将返回 0。read 调用也以类似的方式运行,如果出现问题则返回 -1

    基本上,对于write

    • 如果您返回 -1,则表示存在问题,您应该检查 errno 以查看它是可恢复的还是致命的。
    • 如果您返回 0,那么您目前无法编写任何内容(可能是网络积压或其他问题,但绝对不是(尚未)致命的)。
    • 如果您获得的值小于您想要的值,则表示已发送一些数据。调整您的指针,以便您可以尝试在下一个周期发送其余的。 不要假设一个正的返回值意味着整个块已经发送。
    • 如果您返回的字节数与您尝试发送的字节数相同,则表示整个缓冲区已被接受传送。
    • 如果您返回的内容超出了您要求发送的内容,请向内核开发人员发送一封电子邮件,并附上一些尖刻的评论。 Linus 等人会喜欢的 :-)

    更新: 正如 caf 在 cmets 中指出的那样,我忘了考虑信号处理。您必须忽略损坏的管道信号,否则write 将通过提高该信号在内部失败。

    您可以通过插入:

    struct sigaction new_actn, old_actn;
    new_actn.sa_handler = SIG_IGN;
    sigemptyset (&new_actn.sa_mask);
    new_actn.sa_flags = 0;
    sigaction (SIGPIPE, &new_actn, &old_actn);
    

    在开始使用套接字函数之前。然后你可以使用:

    sigaction (SIGPIPE, &old_actn, NULL);
    

    恢复之前的信号处理。

    【讨论】:

    • 在下一行查看 if(n
    • @SjB,如果write 返回 0,请不要假设问题。如果存在临时网络积压,可能会发生这种情况。如果积压变成一个真正的问题,会话将被关闭,你最终会得到-1。在那之前,请继续努力。
    • 我知道问题。在写作过程中连接关闭。例如在 500 个连接关闭和程序关闭中写入 1024 个数据
    • pax,您忘记了默认情况下尝试write 到已被另一端关闭的套接字将导致您的进程收到SIGPIPE 信号,其默认操作是终止进程。
    • 我的错误。现已修复(希望如此)。
    【解决方案2】:

    我使用 send() 代替 write() 处理无信号:

    bzero(buffer, MAX_SIZE_BUFFER);
    n = read(sockfd, buffer, MAX_SIZE_BUFFER - 1);
    printf("after read%d\n", n);
    if (n <= 0)
    {
        break;
    }
    n2 = send(newsockfd, buffer, n, MSG_NOSIGNAL);
    if (n2 == -1)
    {
        close(sockfd);
        close(newsockfd);
        return;
    }
    if (n2 != n)
    {
        break;
    }
    

    【讨论】:

    • 这会起作用,另一种选择是使用sigaction 忽略SIGPIPE(将其处理程序设置为SIG_IGN)。
    【解决方案3】:

    Socket 编程可能相当棘手,因为您通常直到很久以后才知道发生了错误。

    例如,如果您正在写入的机器异常关闭,则 write 调用可能会成功(因为您能够写入内部 OS 缓冲区),但在 close 调用期间会失败。

    除非您有验证套接字是否处于活动状态的应用层方法(即,发送消息并要求在某个时间段内做出响应),否则您无法知道。如果您使用的是标准协议,则可能已经存在处理错误的东西。

    所以简短的回答是,您需要检查几乎每个接触套接字的调用(读取、写入、关闭等...)的错误返回。

    【讨论】:

    • 不幸的是,这是正确的答案。我尝试了几种方法来确定保持活动的 HTTP 连接是否仍然有效,但它不可靠且没有竞争条件。
    猜你喜欢
    • 1970-01-01
    • 2017-12-01
    • 2011-10-20
    • 1970-01-01
    • 2012-09-19
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 1970-01-01
    相关资源
    最近更新 更多