【问题标题】:C++ + linux handle SIGPIPE signalC++ + linux 处理 SIGPIPE 信号
【发布时间】:2021-05-19 12:35:18
【问题描述】:

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

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

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

【问题讨论】:

  • 为什么不在您的 while 循环中以某种方式 ping 客户端,如果它失败初始化超时序列?
  • @user7778287 每个客户端每次写入? “真正的”服务器会这样做吗?
  • 他们必须做点什么。如果有一种方法可以在不遍历列表的情况下发现每个 x 的状态,我急切地等待了解它..
  • 解决方案是 signal(SIGPIPE, SIG_IGN);,而不是您发布的所谓解决方案。您还需要处理write 调用返回和错误代码。

标签: c++ linux sockets signals


【解决方案1】:

如您提供的链接中所述,解决方案是忽略 SIGPIPE,并检查写入调用的返回值。无论如何,除了最微不足道的空载情况外,都需要后者才能正确操作(短写入)。此外,您使用的 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; }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 2016-03-23
    • 2021-09-07
    相关资源
    最近更新 更多