可以有一个 UDP 套接字同时从一个远程端点接收并发送到另一个远程端点。但是,根据 Boost.Asio Threads 和 Boost.Asio文档,对单个对象进行并发调用通常是不安全的。
因此,这是安全的:
线程_1 | 线程_2
--------------------------------------------------+------------ ----------------------------
socket.async_receive_from( ... ); |
socket.async_send_to( ... ); |
这是安全的:
线程_1 | 线程_2
--------------------------------------------------+------------ ----------------------------
socket.async_receive_from( ... ); |
| socket.async_send_to( ... );
但这被指定为不安全:
线程_1 | 线程_2
--------------------------------------------------+------------ ----------------------------
socket.async_receive_from( ... ); | socket.async_send_to( ... );
|
请注意,某些函数(例如boost::asio::async_read
)是组合操作,并且具有额外的线程安全限制。
如果满足以下任一条件,则不需要进行额外的同步,因为流将是隐式同步的:
- 所有套接字调用都发生在处理程序中,并且
io_service::run()
仅从单个线程调用。
async_receive_from
并且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 ); --'
}
另一方面,如果有多个线程可能对套接字进行并发调用,则需要进行同步。考虑通过boost::asio::io_service::strand调用函数和处理程序来执行同步,或者使用其他同步机制,例如 Boost.Thread 的mutex。
除了线程安全之外,还必须考虑对象生命周期的管理。如果服务器需要同时处理多个请求,那么要注意buffer
每个endpoint
请求- >处理->响应链的所有权。Perasync_receive_from
的文档中,调用者保留了缓冲区和端点的所有权。因此,通过boost::shared_ptr管理对象的生命周期可能更容易。否则,如果链足够快以至于不需要并发链,那么它会简化管理,允许每个请求使用相同的缓冲区和端点。
最后,socket_base::reuse_address
该类允许将套接字绑定到已在使用的地址。但是,我认为这不是一个适用的解决方案,因为它通常被使用:
- 让 TCP 允许进程重新启动并侦听同一个端口,即使该端口处于某种
TIME_WAIT
状态。
- 对于UDP,允许多个进程绑定到同一个端口,允许每个进程通过多播进行接收和广播。