提升Asio Socket问题

时间:2011-11-22 18:32:22

标签: c++ boost boost-asio

我是Boost的新手。我正在开发一个小服务器。当客户端向我的服务器发送消息时,我遇到了问题。我的服务器调用函数读取套接字两次

这是我的客户端类中的代码

void ClientManager::ToRecv(void)
{
    this->_socket.async_read_some(boost::asio::buffer(_buffer),
    _strand.wrap(boost::bind(&ClientManager::HandleRead, this, boost::asio::placeholders::error))
    );
}

void ClientManager::HandleRead(boost::system::error_code const & error)
{
    _mutex.lock();
    std::cout << boost::this_thread::get_id() << " client->HandleRead()" << std::endl;
    for (unsigned int i = 0; i < _buffer.size(); ++i)
    {
         std::cout << _buffer[i]; // I display the message
    }
    std::cout << std::endl;
    _mutex.unlock();

    this->ToRecv();
 }

当客户端连接时,我调用start函数。这是我启动服务器时在控制台中显示的内容:

我创建了3个帖子。

Server Connect
[004FE200] Thread Start
[004FE238] Thread Start
[004FE7C8] Thread Start

这是我将putty客户端连接到我的服务器

[004FE7C8] acceptor->NewClient()
[004FE7C8] client->Start()

这是我的服务器在客户端发送“hello world”时显示的内容。

[004FE238] client->HandleRead()
hello world

[004FE7C8] client->HandleRead()
llo world

2 个答案:

答案 0 :(得分:1)

我不知道_buffer是什么类型的,但它应该看起来像这样,请注意bytes_transferred

    void ClientManager::HandleRead(boost::system::error_code const & error, size_t bytes_transferred)  
{
        _mutex.lock();
        std::cout << boost::this_thread::get_id() << " client->HandleRead()" << std::endl;
        for (unsigned int i = 0; i < bytes_transferred; ++i)
        {
             std::cout << _buffer[i]; // I display the message
        }
        std::cout << std::endl;
        _mutex.unlock();

        this->ToRecv();  
}

互斥锁有什么用?这是否有必要?

我会这样写:

void ClientManager::HandleRead(boost::system::error_code const & error, size_t bytes_transferred)  
{
    std::cout << boost::this_thread::get_id() << " client->HandleRead()" << std::endl;
    std::copy(_buffer.begin(), _buffer.begin() + bytes_transferred, std::ostream_iterator<char>(std::cout));
    std::cout << std::endl; 
    this->ToRecv();  
}

现在,你可能会看到的(并且已经从下面的评论中看到)是HandleRead()将被多次调用,只包含部分消息。如果在调用read函数之前知道消息的大小,则可以使用组合函数async_read()。这是boost::asio命名空间中的自由函数。

答案 1 :(得分:0)

我猜想你在某处初始化了_buffer到“Hello World”。

调用socket::async_read_some并不能保证在调用完成处理程序之前已读取所有数据。您可以使用asio命名空间中的组合自由函数来执行此操作。

所以可能发生的事情是你在第一次调用处理程序时获得部分消息,其余部分在第二次调用中。但是,如果缓冲区已经初始化,那么看起来就像是你收到了两次消息。

更改此行以传递占位符以传输的字节数:

_strand.wrap(
   boost::bind(
      &ClientManager::HandleRead,
      this,
      boost::asio::placeholders::error,
      boost::asio::placeholders::bytes_transferred)));

然后适当更改HandleRead()功能:

void ClientManager::HandleRead(
   boost::system::error_code const & error,
   size_t bytes_transferred) // Add bytes_transferred
{
    _mutex.lock();
    std::cout << boost::this_thread::get_id() << " client->HandleRead()" << std::endl;

    // Then -- check the buffer up to the number of bytes transferred:
    for (unsigned int i = 0; i < bytes_transferred; ++i)
    {
         std::cout << _buffer[i]; // I display the message
    }
    std::cout << std::endl;
    _mutex.unlock();

    this->ToRecv();
 }