使用相同的udp套接字进行异步接收/发送 [英] Use same udp socket for async receive/send

查看:254
本文介绍了使用相同的udp套接字进行异步接收/发送的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

$ b响应客户端
$ b

接收与async_receive_from异步完成。套接字使用相同的ioService(毕竟它是相同的套接字)
文档没有清楚地说明如果一个人可以有一个时刻相同的udp套接字接收来自客户端A的数据报(以异步方式),并可能发送另一个数据报客户端B(异步发送)同时
我怀疑这可能会导致问题。我最后使用相同的套接字作为回复,因为我不能绑定另一个套接字到同一服务器端口,而回复另一个客户端。



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



编辑。我尝试绑定第二个udp套接字到同一个UDP端口与:

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

当我第一次这样做(绑定服务器接收套接字)它是确定,但尝试第二次创建另一个套接字,像它报告错误绑定(asio抛出异常)

解决方案

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



因此,这是安全的:

 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 , / em>,并具有其他线程安全限制。






如果以下任一条件为真,




  • 所有套接字调用都在处理程序中发生, io_service ::

  • async_receive_from async_send_to 仅在同一异步操作链中调用。例如, ReadHandler 传递到 async_receive_from 调用 async_send_to 并且 WriteHandler 传递给 async_send_to 调用 async_receive_from p>

      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的互斥






必须考虑对象生命周期的管理。如果服务器需要同时处理多个请求,那么请小心每个缓冲区端点的所有权> request-> process-> response chain。按 async_receive_from 的文档,调用者保留了缓冲区端点的所有权。因此,通过 boost :: shared_ptr 可以更容易地管理对象的生命周期。 / a>。否则,如果链足够快,不需要并发链,则它简化了管理,允许每个请求使用相同的缓冲器端点




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




  • 对于TCP允许进程重新启动和监听同一端口,即使端口处于 TIME_WAIT 状态。

  • 对于UDP,允许多个进程绑定到相同的端口,允许每个进程通过多播接收和广播。


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

Receive is done async with async_receive_from also. 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. 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:

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)

解决方案

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.

这篇关于使用相同的udp套接字进行异步接收/发送的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆