Boost Asio Socket issue

Boost Asio Socket issue

本文关键字:issue Socket Asio Boost      更新时间:2023-10-16

我是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

我不知道_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命名空间中的自由函数。

我猜您在某处将_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();
 }