【问题标题】:About write buffer in general network programming关于一般网络编程中的写缓冲区
【发布时间】:2009-08-06 06:29:56
【问题描述】:

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

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

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

第一个问题!

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

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

第二个问题!

socket编程中异步写的常用方法是什么?

感谢阅读。

【问题讨论】:

    标签: c++ networking sockets boost-asio


    【解决方案1】:

    抱歉,您有两个选择:

    1. 序列化 write 语句,使用锁或更好 启动一个单独的编写器线程,从 一个队列,其他线程可以在队列上堆叠请求 没有太多争用的队列(需要一些互斥)。

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        网络很可能是管道中最慢的部分(假设您的修改不是 计算昂贵),因此您可以在套接字层发送 以前的数据。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-09-09
          • 2021-09-21
          • 1970-01-01
          • 1970-01-01
          • 2020-11-22
          • 1970-01-01
          • 1970-01-01
          • 2021-07-17
          相关资源
          最近更新 更多