2011-11-02 110 views
13

我正在使用管道在Gnu/Linux上的两个进程之间进行通信。当发送端仍在尝试发送数据时,接收端关闭管道。以下是一些模拟情况的代码。如何在使用boost :: asio时防止SIGPIPE?

#include <unistd.h>                
#include <boost/asio.hpp>               

int main()                  
{                     
    int pipe_fds[2];            
    if(::pipe(pipe_fds) != 0) return 1;           
    // close the receiving end 
    ::close(pipe_fds[0]); 

    boost::asio::io_service io;            
    boost::asio::posix::stream_descriptor sd(io, pipe_fds[1]);  
    boost::system::error_code ec;             
    sd.write_some(boost::asio::buffer("blah"), ec); 

    return 0;                  
} 

当我运行它时,我得到一个SIGPIPE;经典的情况,我知道。但是,我看到boost::asio::error::basic_errors的值为broken_pipe。我希望能够在error_code中返回而不会引发信号。

可这没有创造我的过程中SIGPIPE处理程序来完成?例如,有没有一个配置选项来提升:: asio,我失踪了?也许会在实现中启用MSG_NOSIGNAL的东西?

+1

+1的再生 –

回答

7

安装信号处理程序忽略SIGPIPE,如果你想看到相应的error_code

代码和编译

#include <unistd.h> 
#include <iostream> 
#include <boost/asio.hpp> 


int main(int argc, const char** argv) 
{ 
    bool ignore = false; 
    if (argc > 1 && !strcmp(argv[1], "ignore")) { 
     ignore = true; 
    } 
    std::cout << (ignore ? "" : "not ") << "ignoring SIGPIPE" << std::endl; 

    if (ignore) { 
     struct sigaction sa; 
     std::memset(&sa, 0, sizeof(sa)); 
     sa.sa_handler = SIG_IGN; 
     int res = sigaction(SIGPIPE, &sa, NULL); 
     assert(res == 0); 
    } 

    int pipe_fds[2]; 
    if(::pipe(pipe_fds) != 0) return 1; 
    // close the receiving end 
    ::close(pipe_fds[0]); 

    boost::asio::io_service io; 
    boost::asio::posix::stream_descriptor sd(io, pipe_fds[1]); 
    boost::system::error_code ec; 
    sd.write_some(boost::asio::buffer("blah"), ec); 

    if (ec) { 
     std::cerr << boost::system::system_error(ec).what() << std::endl; 
    } else { 
     std::cout << "success" << std::endl; 
    } 

    return 0; 
} 

[email protected] ~> g++ pipe.cc -lboost_system -lboost_thread-mt 
[email protected] ~> 

运行

[email protected] ~> ./a.out 
not ignoring SIGPIPE 
[email protected] ~> echo $? 
141 
[email protected] ~> ./a.out ignore 
ignoring SIGPIPE 
Broken pipe 
[email protected] ~> 

针对此行为的基本原理是在write(2) man page

EPIPE

fd被连接到管道或插座,其读出端是封闭的。当 发生这种情况时,写入过程也会收到一个SIGPIPE信号。 (由此,写返回值被认为是只有当程序捕捉, 块或忽略该信号。)由我加入

强调。

+0

+1不错的综合答案一如既往:) – Ralf

+0

太糟糕了,我没有执行使用写入实现。我曾希望他们使用send,并且我可以启用传递MSG_NOSIGNAL标志。感谢您的示例代码。 – kalaxy

+0

@kalaxy你可以使用MSG_NOSIGNAL与发送 –

3

SIGPIPE由操作系统生成时没有连接管的一端 - 你真的不能阻止它的boost :: ASIO。但是,您可以简单地忽略信号,其他人应该自行处理。

2

signal_init有做文件boost/asio/detail/signal_init.hpp

+1

但它似乎只为几个平台。不幸的是,它在Linux和OS X上并不包括Boost 1.55.0。 – eregon

相关问题