0

我正在使用 boost.asio 编写服务器。我为每个连接都有读写缓冲区,并使用异步读/写函数(async_write_some/ async_read_some)。

使用读取缓冲区和async_read_some,没有问题。只需调用async_read_some函数就可以了,因为读取缓冲区仅在读取处理程序中读取(通常意味着在同一线程中)。

但是,写入缓冲区需要从多个线程访问,因此需要锁定以进行修改。

第一个问题!

有什么办法可以避免写缓冲区的LOCK?

我将自己的数据包写入堆栈缓冲区并将其复制到写入缓冲区。然后,调用async_write_some函数发送数据包。这样,如果我串行发送两个数据包,是否可以async_write_some两次调用函数?

第二个问题!

套接字编程中异步写入的常用方法是什么?

谢谢阅读。

4

3 回答 3

2

抱歉,您有两个选择:

  1. 序列化写入语句,或者使用锁,或者更好地启动一个单独的写入线程,从队列中读取请求,然后其他线程可以在队列上堆叠请求而不会发生太多争用(需要一些互斥)。

  2. 给每个写线程自己的套接字!如果线路另一端的程序可以支持它,这实际上是更好的解决方案。

于 2009-08-06T07:32:54.507 回答
1

答案#1:

锁定是一种可行的方法是正确的,但是有一种更简单的方法可以完成所有这些工作。Boost 在 ASIO 中有一个不错的小结构,称为strand. 任何使用 strand 包装的回调都将被序列化,保证,无论哪个线程执行回调。基本上,它会为您处理任何锁定。

这意味着您可以拥有任意数量的编写器,并且如果它们都被同一股包裹(因此,在所有编写器之间共享您的单股),它们将连续执行。需要注意的一件事是确保您没有尝试使用内存中相同的实际缓冲区来执行所有写入。例如,这是要避免的:

char buffer_to_write[256];  // shared among threads

/* ... in thread 1 ... */
memcpy(buffer_to_write, packet_1, std::min(sizeof(packet_1), sizeof(buffer_to_write)));
my_socket.async_write_some(boost::asio::buffer(buffer_to_write, sizeof(buffer_to_write)), &my_callback);

/* ... in thread 2 ... */
memcpy(buffer_to_write, packet_2, std::min(sizeof(packet_2), sizeof(buffer_to_write)));
my_socket.async_write_some(boost::asio::buffer(buffer_to_write, sizeof(buffer_to_write)), &my_callback);

在那里,您正在共享您的实际写入缓冲区 ( buffer_to_write)。如果你做了这样的事情,你会没事的:

/* A utility class that you can use */
class PacketWriter
{
private:
  typedef std::vector<char>  buffer_type;

  static void WriteIsComplete(boost::shared_ptr<buffer_type> op_buffer, const boost::system::error_code& error, std::size_t bytes_transferred)
  {
    // Handle your write completion here
  }

public:
  template<class IO>
  static bool WritePacket(const std::vector<char>& packet_data, IO& asio_object)
  {
    boost::shared_ptr<buffer_type> op_buffer(new buffer_type(packet_data));

    if (!op_buffer)
    {
      return (false);
    }

    asio_object.async_write_some(boost::asio::buffer(*op_buffer), boost::bind(&PacketWriter::WriteIsComplete, op_buffer, boost::asio::placeholder::error, boost::asio::placeholder::bytes_transferred));
  }
};

/* ... in thread 1 ... */
PacketWriter::WritePacket(packet_1, my_socket);

/* ... in thread 2 ... */
PacketWriter::WritePacket(packet_2, my_socket);

在这里,如果您也将您的链传递到 WritePacket 会有所帮助。不过,你明白了。

答案#2:

我认为您已经采取了非常好的方法。我将提供的一个建议是使用async_write而不是,async_write_some这样可以保证在调用回调之前写入整个缓冲区。

于 2009-12-01T17:12:14.150 回答
0

您可以将您的修改排队并在写入处理程序中的数据上执行它们。

网络很可能是管道中最慢的部分(假设您的修改计算成本不高),因此您可以在套接字层发送先前数据时执行 mods。

如果您正在处理大量频繁连接/断开连接的客户端,请查看 IO 完成端口或类似机制。

于 2009-08-06T08:23:36.183 回答