简体   繁体   English

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

[英]Use same udp socket for async receive/send

I use the same socket in my udp server in order to receive data from clients on some port, and later after processing of requests respond to to clients using ip::ud::socket ::async_send_to 我在我的udp服务器中使用相同的套接字以便从某些端口上的客户端接收数据,然后在处理请求后使用ip :: ud :: socket :: async_send_to响应客户端

Receive is done async with async_receive_from also. 接收也与async_receive_from异步完成。 The socket uses same ioService (it's the same socket after all) The documentation does not state clearly if one can have at a moment the same udp socket receive datagrams from client A (in async way) and possibly send another datagram to client B (async sent) at the same time I suspect this could lead to problems. 套接字使用相同的ioService(毕竟它是相同的套接字)文档没有明确说明是否可以在同一个udp套接字从客户端A接收数据报(以异步方式)并可能将另一个数据报发送到客户端B(异步)我怀疑这可能导致问题。 I ended up using same socket for reply because I could not bind another socket to the same server port while replying to another client. 我最终使用相同的套接字进行回复,因为在回复另一个客户端时,我无法将另一个套接字绑定到同一个服务器端口。

How can I bind another socket to the same server port? 如何将另一个套接字绑定到同一个服务器端口?

EDIT . 编辑 I try to bind the second udp socket to the same UDP port with: 我尝试将第二个udp套接字绑定到同一个UDP端口:

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

When I do this first time (binding for server "receive" socket) it's OK but trying to create another socket the second time like that it reports error at bind (asio throws exception) 当我第一次这样做(绑定服务器“接收”套接字)时没关系,但是第二次尝试创建另一个套接字,就像它在bind上报告错误一样(asio抛出异常)

It is possible to have a UDP socket concurrently receiving from one remote endpoint and sending to a different remote endpoint. 可以从一个远程端点同时接收UDP套接字并发送到不同的远程端点。 However, per the Boost.Asio Threads and Boost.Asio documentation, it is generally unsafe to make concurrent calls on a single object. 但是,根据Boost.Asio Threads和Boost.Asio文档,对单个对象进行并发调用通常是不安全的。

Thus, this is safe: 因此,这是安全的:

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. 请注意,某些函数(如boost::asio::async_read )是一个组合操作 ,并具有其他线程安全限制。


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. 所有套接字调用都在处理程序中进行,而io_service::run()仅在单个线程中调用。
  • async_receive_from and async_send_to are only invoked within the same chain of asynchronous operations. async_receive_fromasync_send_to仅在同一个异步操作链中调用。 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 . 例如, ReadHandler传递给async_receive_from调用async_send_toWriteHandler传递给async_send_to调用async_receive_from

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

On the other hand, if there are multiple threads potentially making concurrent calls to the socket, then synchronization needs to occur. 另一方面,如果有多个线程可能对套接字进行并发调用,则需要进行同步。 Consider performing synchronization by either invoking the functions and handlers through a boost::asio::io_service::strand , or using other synchronization mechanisms, such as Boost.Thread's mutex . 考虑通过boost :: asio :: io_service :: strand调用函数和处理程序,或使用其他同步机制(如Boost.Thread的互斥锁)来执行同步。


In addition to thread safety, the management of object lifetimes must be considered. 除线程安全外,还必须考虑对象生命周期的管理。 If the server needs to process multiple request concurrently, then be careful about ownership of the buffer and endpoint for each request->process->response chain. 如果服务器需要同时处理多个请求,那么请注意每个请求 - >进程 - >响应链的bufferendpoint所有权。 Per async_receive_from 's documentation, the caller retains ownership of both the buffer and endpoint . 根据async_receive_from的文档,调用者保留缓冲区端点的所有权。 As such, it may be easier to manage the lifetime of the objects via boost::shared_ptr . 因此,通过boost :: shared_ptr管理对象的生命周期可能更容易。 Otherwise, if the chain is quick enough that concurrent chains are not required, then it simplifies management, allowing the same buffer and endpoint to be used per request. 否则,如果链足够快以至于不需要并发链,那么它简化了管理,允许每个请求使用相同的缓冲区端点


Finally, the socket_base::reuse_address class allows a socket to be bound to an address that is already in use. 最后, socket_base::reuse_address类允许将套接字绑定到已在使用的地址。 However, I do not think it is an applicable solution here, as it is generally used: 但是,我不认为这是一个适用的解决方案,因为它通常用于:

  • For TCP to allow a process to restart and listen to the same port, even if the port is in a TIME_WAIT state. 对于TCP,允许进程重新启动并侦听同一端口,即使该端口处于TIME_WAIT状态。
  • For UDP to allow multiple processes to bind to the same port, allowing each process to receive and broadcast via multicast. 对于UDP,允许多个进程绑定到同一端口,允许每个进程通过多播接收和广播。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM