简体   繁体   中英

C++ + linux handle SIGPIPE signal

Yes, I understand this issue has been discussed many times. And yes, I've seen and read these and other discussions:

1 2 3
and I still can't fix my code myself.
I am writing my own web server. In the next cycle, it listens on a socket, connects each new client and writes it to a vector. Into my class i have this struct:

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

with next data structures:

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

and the cycle itself:

//...
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();
}

it works, clients connect, send and receive requests. But the problem is that if the connection is broken ("^C" for client), then my program will not know about it even at the moment:

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

as the title of this question suggests, my app receives a SIGPIPE signal. Again, I have seen "solutions".

signal(SIGPIPE, &SigPipeHandler);

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

but it does not help. At this moment, we have the "№" of the socket to which the write was made, is it possible to "remember" it and close this particular connection in the handler method?
my system:

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

As stated in the links you give, the solution is to ignore SIGPIPE, and CHECK THE RETURN VALUE of the write calls. This latter is needed for correct operation (short writes) in all but the most trivial, unloaded cases anyways. Also the fixed write size of 1024 that you are using is probably not what you want -- if your response string is shorter, you'll send a bunch of random garbage along with it. You probably really want something like:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM