我在我的 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
andasync_send_to
are only invoked within the same chain of asynchronous operations. For example, theReadHandler
passed toasync_receive_from
invokesasync_send_to
, and theWriteHandler
passed toasync_send_to
invokesasync_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->response 的buffer
和endpoint
的所有权链。每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/