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

时间:2012-09-03 18:56:49

标签: c++ networking boost boost-asio

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

响应客户端

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

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

修改即可。我尝试将第二个udp套接字绑定到相同的UDP端口:

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

当我第一次执行此操作(绑定服务器“接收”套接字)时,可以尝试再次创建另一个套接字,就像它在bind上报告错误一样(asio抛出异常)

1 个答案:

答案 0 :(得分:14)

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

因此,这是安全的:

 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)是撰写的操作,并且还有其他线程安全限制。


如果满足以下任一条件,则不需要进行其他同步,因为流将隐式同步:

  • 所有套接字调用都在处理程序中进行,io_service::run()仅从单个线程调用。
  • async_receive_fromasync_send_to仅在同一个异步操作链中调用。例如,传递给ReadHandler的{​​{1}}会调用async_receive_from,传递给async_send_to的{​​{1}}会调用WriteHandler

    async_send_to

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


除线程安全外,还必须考虑对象生命周期的管理。如果服务器需要同时处理多个请求,请注意每个请求 - >进程 - >响应链的async_receive_fromvoid 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 ); --' } 的所有权。根据{{​​3}}的文档,调用者保留缓冲区端点的所有权。因此,通过async_receive_from管理对象的生命周期可能更容易。否则,如果链足够快以至于不需要并发链,那么它可以简化管理,允许每个请求使用相同的缓冲区端点


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

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