UDP 套接字可以同时从一个远程端点接收数据并将其发送到另一远程端点。然而,根据 Boost.Asio线程和 Boost.Asio http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/overview/core/threads.html根据文档,对单个对象进行并发调用通常是不安全的。
因此,这是安全的:
thread_1 | thread_2
--------------------------------------+---------------------------------------
socket.async_receive_from( ... ); |
socket.async_send_to( ... ); |
这是安全的:
thread_1 | thread_2
--------------------------------------+---------------------------------------
socket.async_receive_from( ... ); |
| socket.async_send_to( ... );
但这被指定为不安全:
thread_1 | thread_2
--------------------------------------+---------------------------------------
socket.async_receive_from( ... ); | socket.async_send_to( ... );
|
请注意,某些功能,例如boost::asio::async_read http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/async_read/overload1.html, are a 组合操作,并且有额外的线程安全限制。
如果以下任一条件为真,则不需要发生额外的同步,因为流程将是隐式同步的:
- 所有套接字调用都发生在处理程序中,并且
io_service::run()
仅从单个线程调用。
-
async_receive_from
and async_send_to
仅在同一异步操作链中调用。例如,ReadHandler
传递给async_receive_from
调用async_send_to
,以及WriteHandler
传递给async_send_to
调用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 ); --'
}
另一方面,如果有多个线程可能并发调用套接字,则需要进行同步。考虑通过调用函数和处理程序来执行同步升压::asio::io_service::strand http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/io_service__strand.html,或者使用其他同步机制,例如Boost.Thread的mutex http://www.boost.org/doc/libs/1_51_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_types.mutex.
除了线程安全之外,还必须考虑对象生存期的管理。如果服务器需要同时处理多个请求,那么要小心该请求的所有权buffer
and endpoint
对于每个请求->处理->响应链。每async_receive_from http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/basic_datagram_socket/async_receive_from/overload1.html的文档中,调用者保留两者的所有权buffer and endpoint。因此,通过以下方式管理对象的生命周期可能会更容易升压::shared_ptr http://www.boost.org/doc/libs/1_51_0/libs/smart_ptr/smart_ptr.htm。否则,如果链足够快,不需要并发链,那么它就简化了管理,允许相同的buffer and endpoint根据请求使用。
最后,socket_base::reuse_address http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/socket_base/reuse_address.html类允许将套接字绑定到已在使用的地址。但是,我认为这不是一个适用的解决方案,因为它通常使用:
- 对于 TCP 来说,允许进程重新启动并侦听同一端口,即使该端口位于同一端口
TIME_WAIT
state.
- 对于UDP来说,允许多个进程绑定到同一个端口,允许每个进程通过组播接收和广播。