Use same udp socket for async receive/send

主宰稳场 提交于 2019-12-03 03:38:43

It is possible to have a UDP socket concurrently receiving from one remote endpoint and sending to a different remote endpoint. However, per the Boost.Asio Threads and Boost.Asio documentation, it is generally unsafe to make concurrent calls on a single object.

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.


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 and async_send_to are only invoked within the same chain of asynchronous operations. 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.

    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 );  --'
    }
    

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.


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. Per async_receive_from's documentation, the caller retains ownership of both the buffer and endpoint. As such, it may be easier to manage the lifetime of the objects via 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. 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.
  • For UDP to allow multiple processes to bind to the same port, allowing each process to receive and broadcast via multicast.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!