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; }
}
是的,我知道这个问题已经讨论过很多次了。 是的,我已经看到并阅读了这些和其他讨论:
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; }
}