C++ Boost.asio端点是否可以用于随着时间的推移识别UDP连接的客户端?

C++ Boost.asio端点是否可以用于随着时间的推移识别UDP连接的客户端?,c++,sockets,boost,boost-asio,C++,Sockets,Boost,Boost Asio,在客户机/服务器应用程序中,我的客户机使用UDP连接到服务器 服务器按如下方式打开其套接字: boost::asio::ip::udp::socket; 插座 (_ioService, boost::asio::ip::udp::endpoint (boost::asio::ip::udp::v4(),端口)); 客户端按如下方式打开其套接字: boost::asio::ip::udp::socket; 套接字(ioService); open(boost::asio::ip::udp::v4

在客户机/服务器应用程序中,我的客户机使用UDP连接到服务器

服务器按如下方式打开其套接字:

boost::asio::ip::udp::socket;
插座
(_ioService,
boost::asio::ip::udp::endpoint
(boost::asio::ip::udp::v4(),端口));
客户端按如下方式打开其套接字:

boost::asio::ip::udp::socket;
套接字(ioService);
open(boost::asio::ip::udp::v4());
然后,当客户机向服务器发送其第一条消息时,服务器使用客户机端点作为将来消息的标识符。以下是识别过程的简化:

class Server
{
private:
  boost::asio::ip::udp::socket socket;
  boost::asio::ip::udp::endpoint receiveEndpoint;

private:
  void waitIncoming()
  {
    socket.async_receive_from
      ( boost::asio::null_buffers(), receiveEndpoint,
        boost::bind( &Server::messageReceived, this ) );
  }

  void messageReceived()
  {
    registerClient( receiveEndpoint );
  }
}

由于客户端从工作开始到结束都使用相同的套接字实例,因此服务器使用端点作为客户端的标识符是否安全?

这取决于客户端应用程序。它需要在本地打开一个端口并向服务器发送数据报。客户端可以绑定到特定的本地端口,也可以让操作系统随机选择一个空闲的本地端口。只要套接字绑定到本地UDP端口,端口号就不会改变。但是,如果客户端在发送数据报后选择关闭套接字,并且如果它没有显式绑定到下一个数据报的相同本地端口,则操作系统可以自由选择完全不同的端口

当客户端位于具有NAT的路由器后面时,也可能会发生源端口被重写的情况,并且无法保证此端口号在任何时间内保持稳定

因此,虽然它可能在大多数情况下都有效,但我不会依赖于受控环境之外的行为。您可以切换到基于连接的协议(TCP)或使用自己的会话ID。后者可能很棘手,因为您甚至需要在程序重新启动时管理它们,以防止双重ID,并添加一些检查以防止会话劫持(如果这是您的问题)。

增强至少识别唯一标识UDP连接的5个值中的3个:
协议(UDP)
源IP
源端口
。如果您的服务器只使用一个
dest IP
/
dest端口
,或者您自己添加这些参数,或者这无关紧要,则可以将其用作某种会话标识符。但也有一些问题:

  • 这仅在某些特定于应用程序的事务中才可行。例如,在文件传输客户机中,可能需要为每个文件设置新连接。此外,单个客户端可能会使用并行连接来加快速度,从而使您的生活更加困难。这甚至不是特定于UDP的,TCP也有同样的问题
  • 删除会话/标识符非常困难。UDP没有TCP那样的显式断开连接,因此必须使用一些空闲超时。但是,如果把它放得太短,您可能会很快将标识符删除到,如果把它放得太长,实际上新的连接可能会被标识为旧连接

一般来说,建立会话概念通常最好在应用程序级别完成,例如,为每个数据包生成一个随机和前缀。问题1通过指定客户端必须重用此标识符来解决。问题二之所以得以解决,是因为不太可能有任何客户端使用相同的UUID,因此您实际上可以使用相当大的超时。

您使用receiveEndpoint的哪一部分作为标识?在我对UDP的有限理解中,也有地址和端口。即使不完全相同(取决于名称解析/路由),地址也可以是等效的,并且端口在重新连接时会发生变化。如果在非流连接中需要“会话ID”,为什么不在协议中包含该ID?我使用它来比较端点。我不知道Boost.asio是否使用地址和端口以外的其他内容来比较端点。如果是这样,我不知道端口是否可以在客户端套接字的生存期内更改。如果端点不是标识符,我将添加会话ID,但如果是,我希望避免在协议中添加冗余内容。是否可以依赖端点“相等”,仅取决于您的应用程序要求。我建议您明确地编写您的意图。这将是一个坏掉的客户端,响应包如何到达它?NAT实现也是如此。从理论上讲,这是一个很好的论点,但我认为它们并不现实。OP没有提到服务器是否有响应,并且存在客户定期发送数据而从未收到任何反馈的现实场景(例如,智能温度传感器等)。第二天收到新数据报时,无法保证源IP和端口仍然相同(例如,由于DHCP租用时间较短)。另一个客户端也可能与前一天的另一个客户端具有相同的IP/端口。不一定高度可能,但也不是不可能。是的,但这比你的答案所说的限制要多(这使这些问题看起来非常普遍)。事实上,我在回答中也说了同样的话,我们是一致的。