关于一般网络编程中的写缓冲区

时间:2009-08-06 06:29:56

标签: c++ networking sockets boost-asio

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

使用读缓冲区和async_read_some,没有问题。只调用async_read_some函数是可以的,因为读缓冲区只在读处理程序中读取(通常在同一个线程中)。

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

第一个问题!

有没有办法避免写入缓冲区的LOCK?

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

第二个问题!

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

感谢阅读。

3 个答案:

答案 0 :(得分:2)

很抱歉,您有两种选择:

  1. 使用锁定或更好地序列化write语句 启动一个单独的编写器线程来读取请求 一个队列,其他线程然后可以堆叠请求 没有太多争用的队列(需要一些静音)。

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

答案 1 :(得分: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,这样可以保证在调用回调之前写入整个缓冲区。

答案 2 :(得分:0)

您可以对修改进行排队,并对写入处理程序中的数据执行修改。

网络很可能是管道中最慢的部分(假设您的修改不是 计算上很昂贵),这样你就可以在套接字层发送时执行mod 以前的数据。

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