Losowy EOF w trybie zwiększania asio w wielu wątkach

Jestem całkiem nowy, aby zwiększyć asio i doświadczamlosowy koniec pliku na serwerze wielowątkowym.

Mógłbym odtworzyć mój problem w tym małym przykładzie:

Serwer:

Jest to prosty serwer echa. Protokół jest prosty:

(1) Klient Połącz(2) Serwer odczytuje jeden bajt. Ten bajt to długość ciągu do odczytania i odesłania.(3) Serwer odczytuje N bajtów.(4) Serwer wysyła z powrotem N + 1 bajtów do klienta i wraca do (2).

Gdy klient się rozłączy EOF jest przechwytywany w (3), a pętla obsługi zatrzymuje się.

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;}

Klient:

Klient łączy się raz z serwerem i wysyła 1000 ciągów.

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;}

Gdy serwer używa tylko jednego wątku (komentuje inny bieżnik), serwer poprawnie wyświetla 1000 ciągów.

Gdy serwer używa drugiego wątku, EOF jest przechwytywany w (4) po losowej liczbie drukowanych ciągów. To nigdy nie powinno się zdarzyć.

Próbowałem zawinąć wszystkie wywołania asynchroniczne za pomocą nici, ale to nie zadziałało.O ile widzę, nie ma problemu z wyścigami danych. Handlers powinien być wywoływany jeden po drugim.

Co mnie ominęło ?

Jaki jest prawidłowy idiom do obsługi wielowątkowej aplikacji asio?

EDYTOWAĆ :

Zrobiłem kilka testów i wydaje się, że jeśli wymienię ten wiersz

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

z:

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

Serwer poprawnie wyświetla 1000 wierszy, nawet jeśli widzę, że kilka EOF zostało błędnie przekazanych jako argumenty kilka razy.

Myślę więc, że pytanie brzmidlaczego otrzymuję niepoprawny boost :: asio :: error :: eof, gdy gniazdo oczywiście nie jest zamknięte?

To nie jest to, co zostało powiedzianetutaj.

questionAnswers(2)

yourAnswerToTheQuestion