Question

I try to have an TCP-Server, which is reading Data, processing them and send them back. After that it shall wait for new Data. My Problem is, that the server works fine for the first time data is sent. At the second time, the program stays in the run_one()-loop.

size_t m_lengthReceive;
io_service m_ioService;
std::vector<unsigned char> m_vectorBuffer;
unsigned char m_bufferReceive[128];


void SyncServer::initialize(){      
        m_acceptor = shared_ptr<tcp::acceptor>(
                new tcp::acceptor(m_ioService,
                        tcp::endpoint(tcp::v4(), m_port)));

        m_acceptor->set_option(tcp::acceptor::reuse_address(true));
        m_sock = shared_ptr<tcp::socket>(new tcp::socket(m_ioService));

        m_acceptor->accept(*m_sock, m_ec);
}

void SyncServer::tcpReceiveVector(){
        boost::system::error_code ec;
        m_sock->async_read_some(buffer(m_bufferReceive),
                boost::bind(&SyncServer::tcpReceiveHandler, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
        do{
            m_ioService.run_one();
        }while(m_lengthReceive == 0);
}


void SyncServer::tcpReceiveHandler(const boost::system::error_code& ec,
        size_t size){
    if(size > 0 && !ec){
        m_sock->cancel();
        m_lengthReceive = size;
        m_vectorBuffer.resize(m_lengthReceive);
        int i = 0;
        for(std::vector<unsigned char>::iterator it = m_vectorBuffer.begin();
                it != m_vectorBuffer.end(); ++it){
            *it = m_bufferReceive[i];
            ++i;
        }
    }else{
        m_lengthReceive = 0;
        m_sock->async_read_some(buffer(m_bufferReceive),
                boost::bind(&SyncServer::tcpReceiveHandler, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
    }
}

std::vector<unsigned char> SyncServer::getVectorBuffer(){
    return m_vectorBuffer;
}

void SyncServer::openConnection(){
    if(!m_sock->is_open())
        m_sock->open(tcp::v4());
    m_lengthReceive = 0;
}

void SyncServer::closeConnection(){
    m_sock->close();

}

main(){
    m_tcpServer = shared_ptr<SyncServer>(new SyncServer(m_tcpPort));
    m_tcpServer->initialize();
    while(1){
        m_tcpServer->openConnection();
        m_tcpServer->tcpReceiveVector();
        vector = m_tcpServer->getVectorBuffer();

        //do something with vector

        m_tcpServer->tcpSend(vector); //this works fine
        m_tcpServer->closeConnection();
    }
}

Updated Code:

void SyncServer::tcpReceiveHandler(const boost::system::error_code& ec,
        size_t size){
    if(ec){
        std::cout<< ec << std::endl;
    }else{
        if(size > 0){
            m_sock->cancel();
            m_lengthReceive = size;
            m_vectorBuffer.resize(m_lengthReceive);
            int i = 0;
            for(std::vector<unsigned char>::iterator it = m_vectorBuffer.begin();
                    it != m_vectorBuffer.end(); ++it){
                *it = m_bufferReceive[i];
                ++i;
            }
        }else{
            m_lengthReceive = 0;
            m_sock->async_read_some(buffer(m_bufferReceive),
                    boost::bind(&SyncServer::tcpReceiveHandler, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
        }
    }
}
Was it helpful?

Solution 2

In addition to what Nim answered, you also did the classical asio error. As documented here: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_service/run_one/overload1.html "Subsequent calls to run(), run_one(), poll() or poll_one() will return immediately unless there is a prior call to reset()."

After your .run_one you need to call m_ioservice.reset() or it will never do any running again. It just returns instead of invoking any any async operations and thus m_lengthReceive will not change after the first time.

    do{
        m_ioService.run_one();
        m_ioService.reset();
    }while(m_lengthReceive == 0);

This is the reason people normally do not use run_one() but run() and start a new async operation within the handler of the last one. In that case the run() does not return and no reset() is required.

OTHER TIPS

In your receive handler, you will only trigger another read if there is a problem(?)

void SyncServer::tcpReceiveHandler(const boost::system::error_code& ec,
        size_t size){
    if(size > 0 && !ec){
        m_sock->cancel();
        m_lengthReceive = size;
        m_vectorBuffer.resize(m_lengthReceive);
        int i = 0;
        for(std::vector<unsigned char>::iterator it = m_vectorBuffer.begin();
                it != m_vectorBuffer.end(); ++it){
            *it = m_bufferReceive[i];
            ++i;
        }
    }else{
        m_lengthReceive = 0;
        m_sock->async_read_some(buffer(m_bufferReceive),
                boost::bind(&SyncServer::tcpReceiveHandler, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
    }
}

On this callback, you need to queue the next read (normally if there are no problems, not when there is a problem!)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top