boost::asio : data corruption

不打扰是莪最后的温柔 提交于 2019-12-11 10:07:55

问题


I present a simple client and server written in Asio to show something that might be a bug. client repeatedly sends a fixed string of length 102 to the server and server checks the string to be correct and writes an error message if not so and exits.

The code is compiled and run in debian 7 (amd64)
my processor has 2 cores
boost version is 1.55

when running server and client, after a few thousand packets are sent a wrong packet is received.(it may be required to repeat the test a few times)

what is the problem?

Makefile

CXX=g++
LIBS = -lboost_thread -lboost_filesystem -lboost_system

all: server asyncclient
server: server.o
    $(CXX) $(LIBS) server.o -o server
asyncclient: asyncclient.o
    $(CXX) $(LIBS) asyncclient.o -o asyncclient
server.o: server.cpp
    $(CXX) -c server.cpp
asyncclient.o: asyncclient.cpp
    $(CXX) -c asyncclient.cpp

server.cpp

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
using boost::asio::ip::tcp;
char teststr[]="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n";
void session(tcp::socket* sock)
{
    boost::array<char, 102> buf;// 102 == sizeof(teststr)
    int i=0;
    try
    {
            for (;;)
            {
                    std::cout<<i++<<std::endl;
                    boost::system::error_code error;
                    size_t length = boost::asio::read(*sock, boost::asio::buffer(buf), error);
                    if (error == boost::asio::error::eof)
                            break; // Connection closed cleanly by peer.
                    else if (error)
                            throw boost::system::system_error(error); // Some other error.
                    if(strcmp(buf.data(), teststr)!=0)
                    {
                            std::cerr<<"error"<<std::endl;
                            std::cerr<<"    buf.data() = "<<
                                    std::string(buf.data(), buf.size())<<std::endl;
                            return;
                    }
            }
    }
    catch (std::exception& e)
    {
            std::cerr << "Exception: " << e.what() << "\n";
    }
}

int main()
{
    std::cerr<<"sizeof(teststr) = "<<sizeof(teststr)<<std::endl;//DEBUG
    boost::asio::io_service ios;
    tcp::acceptor a(ios, tcp::endpoint(tcp::v4(), 41000));
    tcp::socket sock(ios);
    a.accept(sock);
    boost::thread t(boost::bind(session, &sock));
    t.join();
}

asyncclient.cpp

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

using boost::asio::ip::tcp;

char teststr[]="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n";

void handle_write(size_t num_bytes, boost::system::error_code e)
{
    static int i=0;
    if(!e)
    {
        std::cout<<i++<<std::endl;
    }
    else
    {
        std::cout<<"Error: "<<e.message()<<std::endl;
        exit(1);
    }
}

int main()
{
    boost::asio::io_service ios;

    tcp::resolver r(ios);
    tcp::resolver::query q(tcp::v4(), "127.0.0.1", "41000");
    tcp::resolver::iterator it = r.resolve(q);

    tcp::socket sock(ios);
    boost::asio::connect(sock, it);

    boost::thread t(boost::bind(&boost::asio::io_service::run,&ios));
    try
    {
        for(;;)
        {
            boost::asio::async_write(sock, boost::asio::buffer(teststr,102),
                    boost::bind(&handle_write,
                    boost::asio::placeholders::bytes_transferred,
                    boost::asio::placeholders::error));
        }
    }
    catch(std::exception& e)
    {
        std::cout<<"Exception: "<<e.what()<<std::endl;
    }
    t.join();
}

回答1:


the problem comes from the following for loop:

for(;;)
    {
        boost::asio::async_write(sock, boost::asio::buffer(teststr,102),
                boost::bind(&handle_write,
                boost::asio::placeholders::bytes_transferred,
                boost::asio::placeholders::error));
    }

an async_write operation may be begin before the completion of previous async_write which is not allowed.
REF: async_write

the correct way is to eliminate the for loop and call async_write in the handle_write function:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

using boost::asio::ip::tcp;

char teststr[]="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n";

void handle_write(tcp::socket* sock, size_t num_bytes, boost::system::error_code e)
{
    static int i=0;
    if(!e)
    {
        std::cout<<i++<<std::endl;
        boost::asio::async_write(*sock, boost::asio::buffer(teststr,102),
                boost::bind(&handle_write, sock,
                    boost::asio::placeholders::bytes_transferred,
                    boost::asio::placeholders::error));
    }
    else
    {
        std::cout<<"Error: "<<e.message()<<std::endl;
        exit(1);
    }
}

int main()
{
    boost::asio::io_service ios;

    tcp::resolver r(ios);
    tcp::resolver::query q(tcp::v4(), "127.0.0.1", "41000");
    tcp::resolver::iterator it = r.resolve(q);

    tcp::socket sock(ios);
    boost::asio::connect(sock, it);

    boost::thread t(boost::bind(&boost::asio::io_service::run,&ios));
    boost::asio::async_write(sock, boost::asio::buffer(teststr,102),
            boost::bind(&handle_write, &sock,
                boost::asio::placeholders::bytes_transferred,
                boost::asio::placeholders::error));
    t.join();
}


来源:https://stackoverflow.com/questions/23074776/boostasio-data-corruption

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!