当客户端在 write() 期间终止连接时,由对等套接字错误重置连接

Posted

技术标签:

【中文标题】当客户端在 write() 期间终止连接时,由对等套接字错误重置连接【英文标题】:Connection reset by peer socket error when the client terminate connection during write() 【发布时间】:2020-06-19 21:12:08 【问题描述】:

我让我的服务器向客户端(网络浏览器)发送一个大文件,但是当我刷新我的页面时,我得到 连接被对等错误重置并且程序终止。我期待的是服务器获得一个新的连接。

 while (true)
    
        check((new_socket = accept(server_fd, (struct sockaddr *)&address,

                                   (socklen_t *)&addrlen)),
              "accept_failed");
        read(new_socket, buffer_recv, 1024);
        printf("%s\n", buffer_recv);
        T = std::thread(handle_connection, new_socket);
        T.detach();
    

handle_connection 包含

while (file.read(&buffer[0], 1024))
    
        s = file.gcount();
        content = chunk::make_chunk(buffer, s);
        check(write(new_socket, &content[0], content.size()), "Write_error");
    

检查是简单的错误处理函数和make_chunk返回字符串。如何使服务器不退出并继续侦听连接请回答我是套接字编程的新手

【问题讨论】:

如果这是您的“Web 服务器”上代码的总和,那么肯定缺少某些东西——似乎显示的代码实际上并没有实现 HTTP 的任何部分。要么就是这样,要么显示的代码不符合minimal reproducible example 的要求,正如help center 中所解释的那样,因此任何人都无法帮助您。 在 Linux 上,在某些情况下写入套接字时会生成 SIGPIPE 信号,导致应用程序默认终止。您可以尝试send(new_socket, &content[0], content.size(), MSG_NOSIGNAL); 而不是write 可能会得到错误代码而不是信号。 或者,您可以在新套接字上使用setsockopt(SO_NOSIGPIPE),然后您可以继续使用read()write(),而不必在每个recv() 和@987654333 上指定MSG_NOSIGNAL @。见How to prevent SIGPIPEs (or handle them properly)。 @RemyLebeau MSG_NOSIGNAL 工作,谢谢。有没有办法终止线程而不是杀死整个进程。 @ArjunUS 这就是禁用 SIGPIPE 的重点。这将导致套接字 I/O 操作失败并出现您可以在代码中正常处理的错误代码,例如中断循环和退出线程过程,而不是终止您的进程。 【参考方案1】:

是的,您可以将send()MSG_NOSIGNAL 一起使用,或者您可以将SO_NOSIGPIPE 套接字选项与setsockopt() 一起使用。但是通过对现有代码的最小更改以及将设置应用于所有创建的套接字,您可以执行以下操作:

来自write()的手册页

EPIPE : fd 连接到读取端关闭的管道或套接字。当这种情况发生时,写入过程也会收到一个 SIGPIPE 信号。 (因此,只有当程序捕获、阻塞或忽略此信号时,才会看到写入返回值。)

#include <signal.h>
#include <stddef.h>
#include <unistd.h>
#include <errno.h>

int main()

    /* .... */

    sigset_t sigmask;

    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGPIPE);

    if (sigprocmask(SIG_BLOCK, &sigmask, NULL) != 0)  // get EPIPE instead
        goto handle_sigprocmask_fail;

    /* .... */

    int wr_return = write(sockfd, buf, sizeof(buf));

    if (wr_return == -1) 
        if (errno == EPIPE)
            goto handle_epipe;
    

【讨论】:

感谢 Mohith MSG_NOSIGNAL 为我工作。当这个信号发生时,我如何终止当前线程而不是杀死整个进程 @ArjunUS 现在有什么需要,你不会再得到 SIGPIPE。 来自signal 手册页:信号可以是进程导向的或线程导向的。进程导向的信号是针对整个进程的(因此是等待处理的)。信号可能是进程导向的,因为它是由内核出于硬件异常以外的原因生成的,或者因为它是使用 kill(2) 或 sigqueue(3) 发送的。 >> @ArjunUS 听起来SIGPIPE是进程导向的,所以它被放在进程信号队列而不是线程信号队列中,因此我们不知道哪个线程负责生成SIGPIPE @ArjunUS 残酷的事实是,你需要处理这种情况,参考这个链接why write() generates SIGPIPE instead of just giving -1 when receiving end is closed

以上是关于当客户端在 write() 期间终止连接时,由对等套接字错误重置连接的主要内容,如果未能解决你的问题,请参考以下文章

Spring web Flux WebClient:对等连接休息,#block因错误而终止。在以下站点观察到错误

如何正确拆除多人连接会话?

Python 处理 socket.error:[Errno 104] 连接由对等方重置

javax.net.ssl.SSLException:读取错误:ssl=0x9524b800:系统调用期间的 I/O 错误,对等方重置连接

在 Python 中使用 Twitch IRC 时“由对等方重置连接”

Python socket.error:[Errno 104] 对等方重置连接