c++ - 使用相同的 udp 套接字进行异步接收/发送

标签 c++ networking boost boost-asio

我在我的 udp 服务器中使用相同的套接字,以便在某个端口上从客户端接收数据,然后在处理请求后使用 ip::ud::socket::async_send_to 响应客户端

接收也是通过 async_receive_from 异步完成的。套接字使用相同的 ioService(毕竟是相同的套接字) 文档没有明确说明是否可以同时让同一个 udp 套接字从客户端 A(以异步方式)接收数据报,并可能同时向客户端 B(异步发送)发送另一个数据报 我怀疑这可能会导致问题。我最终使用同一个套接字进行回复,因为在回复另一个客户端时我无法将另一个套接字绑定(bind)到同一个服务器端口。

如何将另一个套接字绑定(bind)到同一个服务器端口?

编辑。我尝试将第二个 udp 套接字绑定(bind)到同一个 UDP 端口:

socket(ioService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port))

当我第一次这样做时(绑定(bind)服务器“接收”套接字)没问题,但第二次尝试创建另一个套接字时它会在绑定(bind)时报告错误(asio 抛出异常)

最佳答案

可以让一个 UDP 套接字同时从一个远程端点接收并发送到不同的远程端点。但是,根据 Boost.Asio Threads and Boost.Asio文档,对单个对象进行并发调用通常是不安全的。

因此,这是安全的:

 thread_1                             | thread_2
--------------------------------------+---------------------------------------
socket.async_receive_from( ... );     |
socket.async_send_to( ... );          |

and this is safe:

 thread_1                             | thread_2
--------------------------------------+---------------------------------------
socket.async_receive_from( ... );     |
                                      | socket.async_send_to( ... );

but this is specified as not being safe:

 thread_1                             | thread_2
--------------------------------------+---------------------------------------
socket.async_receive_from( ... );     | socket.async_send_to( ... );
                                      |

Be aware that some functions, such as boost::asio::async_read, are a composed operation, and have additional thread safety restrictions.


If either of the following are true, then no additional synchronization needs to occur, as the flow will be implicitly synchronous:

  • All socket calls occur within handlers, and io_service::run() is only invoked from a single thread.
  • async_receive_from and async_send_to are only invoked within the same chain of asynchronous operations. For example, the ReadHandler passed to async_receive_from invokes async_send_to, and the WriteHandler passed to async_send_to invokes async_receive_from.

    void read()
    {
      socket.async_receive_from( ..., handle_read );  --.
    }                                                   |
        .-----------------------------------------------'
        |      .----------------------------------------.
        V      V                                        |
    void handle_read( ... )                             |
    {                                                   |
      socket.async_send_to( ..., handle_write );  --.   |
    }                                               |   |
        .-------------------------------------------'   |
        |                                               |
        V                                               |
    void handle_write( ... )                            |
    {                                                   |
      socket.async_receive_from( ..., handle_read );  --'
    }
    

另一方面,如果有多个线程可能对套接字进行并发调用,则需要进行同步。考虑通过 boost::asio::io_service::strand 调用函数和处理程序来执行同步,或使用其他同步机制,例如 Boost.Thread 的 mutex .


除了线程安全之外,还必须考虑对象生命周期的管理。如果服务器需要同时处理多个请求,那么请注意每个request->process->responsebufferendpoint 的所有权链。每async_receive_from的文档中,调用者保留对缓冲区端点 的所有权。因此,通过 boost::shared_ptr 管理对象的生命周期可能更容易。 .否则,如果链足够快以至于不需要并发链,那么它会简化管理,允许每个请求使用相同的缓冲区端点


最后,socket_base::reuse_address类允许将套接字绑定(bind)到已在使用的地址。但是,我认为这不是一个适用的解决方案,因为它通常被使用:

  • 对于 TCP,允许进程重新启动并监听同一个端口,即使该端口处于 TIME_WAIT 状态。
  • 对于UDP,允许多个进程绑定(bind)到同一个端口,允许每个进程通过多播接收和广播。

关于c++ - 使用相同的 udp 套接字进行异步接收/发送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12252822/

相关文章:

linux - 在树莓派上使用 libboost 进行编译 - 未定义对 `boost::system::system_category() 的引用

c++ - QDateTime类中缺少addMinutes的原因

c++ - 引用你不拥有的 "std::unique_ptr"(使用原始指针?)

c++ - 对数组的引用与 C++ 中的数组名称完全相同

networking - 数据链路层和传输层

通过 channel 从客户端读取内容时出现 java.nio.channels.IllegalBlockingModeException

c++ - Concurrency::critical_section 构建错误:无法访问私有(private)成员

java - 读取对象时出现 EOFException

c++ - 使用一个TCP套接字的多个请求

c++ - Boost::Python 中的智能指针转换