本文介绍了随机EOF在多线程中的boost asio的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!



这不是说明。

解决方案

这是boost :: asio 1.54.0的错误



我在互联网上找到了两个类似的主题:





  • 和(在堆栈溢出)。



还有一个错误报告。



我安装了boost 1.53,现在工作正常。


I am quite new to boost asio and I am experiencing random End of File in a multi threaded server.

I could reproduce my problem in this small example:

Server:

This is a simple echo server. The protocol is straightforward :

  • (1) A client Connect
  • (2) The server reads one byte. This byte is the length of the string to read and send back.
  • (3) The server reads N bytes.
  • (4) The server send back N+1 bytes to the client and goes back to (2).

When the Client disconnect An EOF is captured in (3) and the handler loop stops.

class MySocket{
public:
    char buffer[257];
    boost::asio::ip::tcp::socket socket;
    MySocket(boost::asio::io_service*ios):socket(*ios){}
    ~MySocket(){}
};

//Handlers

void readN(std::shared_ptr<MySocket>server,const boost::system::error_code&ec);

//(4)
void echo(std::shared_ptr<MySocket>server,const boost::system::error_code&ec){
    if(ec){
        throw std::exception(("This is NOT OK: "+ec.message()).c_str());}
    size_t n=server->buffer[0]&0xFF;
    std::cout<<std::string(server->buffer+1,n)<<std::endl;
    boost::asio::async_write(server->socket,boost::asio::buffer(server->buffer,n+1),boost::bind(readN,server,boost::asio::placeholders::error));}

//(3)
void read(std::shared_ptr<MySocket>server,const boost::system::error_code&ec){
    if(ec){
        throw std::exception(("This is OK: "+ec.message()).c_str());}
    size_t n=server->buffer[0]&0xFF;
    boost::asio::async_read(server->socket,boost::asio::buffer(server->buffer+1,n),boost::bind(echo,server,boost::asio::placeholders::error));}

//(2)
void readN(std::shared_ptr<MySocket>server,const boost::system::error_code&ec){
    if(ec){
        throw std::exception(("This is also NOT OK: "+ec.message()).c_str());}
    boost::asio::async_read(server->socket,boost::asio::buffer(server->buffer+0,1),boost::bind(read,server,boost::asio::placeholders::error));}

//Server

void serve(boost::asio::io_service*ios){
    for(;;){
        try{ios->run();break;}
        catch(const std::exception&e){std::cout<<e.what()<<std::endl;}}}

//(1)
void accept(boost::asio::io_service*ios,boost::asio::ip::tcp::acceptor*acceptor,std::shared_ptr<MySocket>server,const boost::system::error_code&ec){
    if(server.get()!=nullptr){
        server->socket.set_option(boost::asio::ip::tcp::no_delay(true));
        readN(server,ec);}
    server.reset(new MySocket(ios));
    acceptor->async_accept(server->socket,boost::bind(accept,ios,acceptor,server,boost::asio::placeholders::error));}

int main(){
    boost::asio::io_service ios;
    boost::asio::ip::tcp::acceptor acceptor(ios,boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),1207));
    boost::asio::io_service::work work(ios);
    accept(&ios,&acceptor,nullptr,boost::system::error_code());
//    std::thread other(boost::bind(serve,&ios));
    serve(&ios);
    acceptor.close();
    ios.stop();
//    other.join();
    return 0;}

Client:

The client is connecting once to the server and sending 1000 strings.

int main(){
    try{
        boost::asio::io_service ios;
        boost::asio::ip::tcp::socket socket(ios);
        boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string("127.0.0.1"),1207);
        socket.connect(endpoint);
        socket.set_option(boost::asio::ip::tcp::no_delay(true));
        char buf[257];
        for(size_t i=0;i<1000;++i){
            size_t n=(i%127)+1;
            buf[0]=(char)n;
            for(size_t j=0;j<n;++j){
                buf[j+1]=(char)('A'+(j+i)%26);}
            socket.send(boost::asio::buffer(buf,n+1));
            socket.receive(boost::asio::buffer(buf,1));
            if((buf[0]&0xFF)!=n){
                throw std::exception("Oups!");}
            socket.receive(boost::asio::buffer(buf+1,n));
            for(size_t j=0;j<n;++j){
                if(buf[j+1]!=(char)('A'+(j+i)%26)){
                    throw std::exception("Oups!");}}
            std::cout<<i<<": "<<std::string(buf+1,n)<<std::endl;}}
    catch(const std::exception&e){
        std::cout<<e.what()<<std::endl;}
    return 0;}

When The server uses only one thread (the tread other is commented) the server echos correctly the 1000 strings.

When The server uses the other thread, An EOF is captured in (4) after a random number of printed strings. This should never happen.

  • I tried wrapping all the async calls with a strand, but it did not work.
  • As far as I can see, there is no data race issue. Handlers should be called one after another.

What did I miss ?

What is the correct idiom to handle a multithreaded asio application ?

EDIT :

I did a few tests and it appears that if I replace this line

throw std::exception(("This is NOT OK: "+ec.message()).c_str());

with:

std::cout<<"This is not OK: "<<ec.message()<<std::endl;

The server echos correctly the 1000 lines even if I see that a few EOF were incorrectly passed as arguments a few times.

So I guess the question is why do I get an incorrect boost::asio::error::eof when the socket is obviously not closed ?

This is not what is stated here.

解决方案

This is a bug of boost::asio 1.54.0

I found two similar threads on the internet:

There is also a bug report here.

I installed boost 1.53 and it is now working just fine.

这篇关于随机EOF在多线程中的boost asio的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 11:15