Подтвердить что ты не робот

Как предотвратить SIGPIPE при использовании boost:: asio?

Я использую канал для связи между двумя процессами в Gnu/Linux. Принимающий конец закрывает трубу, в то время как отправляющий конец все еще пытается отправить данные. Вот какой код, который эмулирует ситуацию.

#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 для моего процесса? Например, есть ли опция конфигурации для boost:: asio, которую я пропускаю? Может быть, что-то, что позволит MSG_NOSIGNAL в реализации?

4b9b3361

Ответ 1

Установите обработчик сигнала, чтобы игнорировать 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) справочной странице

EPIPE

fd подключается к трубе или гнезду, конец считывания которого закрыт. когда это случается, что процесс записи также получит сигнал SIGPIPE. (Таким образом, возвращаемое значение записи видно только в том случае, если программа ловит, блокирует или игнорирует этот сигнал.)

добавленный мной.

Ответ 2

SIGPIPE генерируется операционной системой, когда один конец трубы не подключен - вы не можете предотвратить его с boost:: asio. Однако вы можете просто игнорировать сигнал, а остальные должны заботиться о себе.

Ответ 3

signal_init сделал это в файле boost/asio/detail/signal_init.hpp