7

我在我的 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))

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

4

1 回答 1

16

可以有一个 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_toWriteHandler传递给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,允许多个进程绑定到同一个端口,允许每个进程通过多播进行接收和广播。
于 2012-09-04T22:13:19.300 回答