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

C++ 关于一般网络编程中的写缓冲区,c++,networking,sockets,boost-asio,C++,Networking,Sockets,Boost Asio,我正在使用boost.asio编写服务器。我对每个连接都有读写缓冲区,并使用异步读写功能(async\u write\u some/async\u read\u some) 有了读取缓冲区和异步读取部分,就没有问题了。只要调用async\u read\u some函数就可以了,因为读取缓冲区在读取处理程序中是只读的(通常意味着在同一线程中) 但是,写入缓冲区需要从多个线程访问,因此需要锁定它以进行修改 第一个问题 有没有办法避免写入缓冲区被锁定? 我将自己的数据包写入堆栈缓冲区,并将其复制到写入

我正在使用boost.asio编写服务器。我对每个连接都有读写缓冲区,并使用异步读写功能(
async\u write\u some
/
async\u read\u some

有了读取缓冲区和异步读取部分,就没有问题了。只要调用
async\u read\u some
函数就可以了,因为读取缓冲区在读取处理程序中是只读的(通常意味着在同一线程中)

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

第一个问题

有没有办法避免写入缓冲区被锁定?

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

第二个问题

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


感谢阅读。

对不起,您有两个选择:

  • 序列化write语句,可以使用锁,也可以使用更好的方法 启动一个单独的writer线程,从中读取请求 然后,其他线程可以在队列上堆叠请求 没有太多争用的队列(需要一些互斥)

  • 给每一个书写线程自己的套接字! 如果程序位于另一端,这实际上是更好的解决方案 金属丝的长度可以支撑它


  • 很抱歉,您有两个选择:

  • 序列化write语句,可以使用锁,也可以使用更好的方法 启动一个单独的writer线程,从中读取请求 然后,其他线程可以在队列上堆叠请求 没有太多争用的队列(需要一些互斥)

  • 给每一个书写线程自己的套接字! 如果程序位于另一端,这实际上是更好的解决方案 金属丝的长度可以支撑它


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

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

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

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

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

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

    回答#1: 您认为锁定是一种可行的方法,这是正确的,但是有一种更简单的方法来完成所有这一切。Boost在ASIO中有一个很好的小构造,称为
    。无论哪个线程执行回调,使用串包装的任何回调都将被序列化,并得到保证。基本上,它为您处理任何锁定

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

    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\u to\u 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);
    
    /*您可以使用的实用程序类*/
    类包编写器
    {
    私人:
    typedef std::向量缓冲区类型;
    静态void WriteIsComplete(boost::shared\u ptr op\u buffer,const boost::system::error\u code&error,std::size\u t bytes\u transfer)
    {
    //在这里处理您的写入完成
    }
    公众:
    模板
    静态bool WritePacket(const std::向量和数据包、IO和asio对象)
    {
    boost::共享的缓冲区(新的缓冲区类型(包数据));
    if(!op_缓冲区)
    {
    返回(假);
    }
    asio_object.async_write_some(boost::asio::buffer(*op_buffer),boost::bind(&PacketWriter::WriteIsComplete,op_buffer,boost::asio::placeholder::error,boost::asio::placeholder::bytes_transfer));
    }
    };
    /* ... 在线程1中*/
    PacketWriter::WritePacket(packet_1,my_套接字);
    /* ... 在线程2中*/
    PacketWriter::WritePacket(packet_2,my_套接字);
    
    在这里,如果您也将您的链传递到WritePacket中,则会有所帮助。不过你明白了

    答复#2: 我认为你已经采取了一个非常好的方法。我的一个建议是使用
    async\u write
    而不是
    async\u write\u some
    ,这样可以保证在调用回调之前写入整个缓冲区。

    Answer#1: 您认为锁定是一种可行的方法,这是正确的,但是有一种更简单的方法来完成所有这一切。Boost在ASIO中有一个很好的小构造,称为
    。无论哪个线程执行回调,使用串包装的任何回调都将被序列化,并得到保证。基本上,它为您处理任何锁定

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

    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\u to\u 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);
    
    /*您可以使用的实用程序类*/
    类包编写器
    {
    普里瓦