C++ + linux 处理 SIGPIPE 信号

C++ + linux handle SIGPIPE signal

是的,我知道这个问题已经讨论过很多次了。 是的,我已经看到并阅读了这些和其他讨论:

1 2 3
而且我仍然无法自己修复我的代码。
我正在编写自己的网络服务器。在下一个周期中,它监听套接字,连接每个新客户端并将其写入向量。 进入我的 class 我有这个结构:

struct Connection
{
    int socket;
    std::chrono::system_clock::time_point tp;
    std::string request;
};

下一个数据结构:

std::mutex connected_clients_mux_;
std::vector<HttpServer::Connection> connected_clients_;

和循环本身:

//...
bind  (listen_socket_, (struct sockaddr *)&addr_, sizeof(addr_));
listen(listen_socket_, 4 );
while(1){
    connection_socket_ = accept(listen_socket_, NULL, NULL);
    //...
    Connection connection_;
    //...
    connected_clients_mux_.lock();
    this->connected_clients_.push_back(connection_);
    connected_clients_mux_.unlock();
}

有效,客户端连接、发送和接收请求。 但问题是,如果连接断开(客户端为“^C”),那么我的程序即使在此刻也不会知道:

    void SendRespons(HttpServer::Connection socket_){   
    write(socket_.socket,( socket_.request + std::to_string(socket_.socket)).c_str(), 1024);
}

正如这个问题的标题所暗示的,我的应用收到了一个 SIGPIPE 信号。 再一次,我看到了“解决方案”。

signal(SIGPIPE, &SigPipeHandler);

void SigPipeHandler(int s) {
    //printf("Caught SIGPIPE\n%d",s);
}

但这并没有帮助。此时,我们有写入的套接字的“№”,是否可以“记住”它并在处理程序方法中关闭此特定连接?
我的系统:

Operating System: Ubuntu 20.04.2 LTS
Kernel: Linux 5.8.0-43-generic
g++ --version
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

如您提供的链接所述,解决方案是忽略 SIGPIPE,并检查写入调用的 RETURN 值。后者是正确操作(短写)所必需的,但最微不足道的卸载情况除外。此外,您使用的固定写入大小 1024 可能不是您想要的——如果您的响应字符串较短,您将发送一堆随机垃圾。你可能真的想要这样的东西:

void SendRespons(HttpServer::Connection socket_){
    auto data = socket_.request + std::to_string(socket_.socket);
    int sent = 0;
    while (sent < data.size()) { 
        int len = write(socket_.socket, &data[sent], data.size() - sent);
        if (len < 0) {
            // there was an error -- might be EPIPE or EAGAIN or EINTR or ever a few other
            // obscure corner cases.  For EAGAIN or EINTR (which can only happen if your
            // program is set up to allow them), you probably want to try again.
            // Anything else, probably just close the socket and clean up.
            if (errno == EINTR)
                continue;
            close(socket_.socket);
            // should tell someone about it?
            break; }
        sent += len; }
}