随机EOF在多线程中的boost asio [英] Random EOF in boost asio in multi thread

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

问题描述

我很新推出asio,我在多线程服务器中遇到随机结束文件



我可以在这个小例子中重现我的问题:



服务器 / p>

这是一个简单的回显服务器。协议很简单:




  • (1)客户端连接

  • 一个字节。此字节是要读取和发送回的字符串的长度。

  • (3)服务器读取N个字节。

  • (4)服务器向客户端发回N + 1个字节并返回(2)。



当客户端断开时,在(3)中捕获一个EOF,并且处理程序循环停止。

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

//处理程序

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
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 :: placeholder :: 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 :: placeholder :: error));}

//(2)
void readN(std :: shared_ptr< MySocket> server,const boost :: system :: error_code& ec) {
if(ec){
throw std :: exception((这也不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) );}

//服务器

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 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));
服务(& ios);
acceptor.close();
ios.stop();
// other.join();
return 0;}

客户



客户端连接一次到服务器并发送1000个字符串。

  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 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 if(buf [j + 1]!=(char)('A'+(j + i)%26) ){
throw std :: exception(Oups!);}}
std :: cout<< i<<:< ,n)<< std :: endl;}}
catch(const std :: exception& e){
std :: cout<< e.what()< std :: endl;}
return 0;}

当服务器只使用一个线程胎面其他是注释)服务器正确回答1000字符串。



当服务器使用其他线程时,在随机数字的打印字符串之后(4)捕获EOF。这不应该发生。




  • 我尝试用一​​个strand包装所有的异步调用,但它不工作。

  • 据我所见,没有数据竞争问题。






    $ b

    处理多线程asio应用程序的正确用法是什么?



    >



    我做了一些测试,似乎如果我更换这行

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

    其中:

     code> std :: cout<<这不行:<< ec.message()<< std :: endl; 

    服务器正确地回显1000行,即使我看到一些EOF不正确地作为参数传递几次。



    所以我想问题是为什么我得到一个不正确的boost :: asio :: error :: eof当socket明显不关闭?



    这不是说明此处

    解决方案

    这是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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆