在客户端/服务器应用程序中,我的客户端使用Boost.asio通过UDP连接到服务器。
服务器打开它的套接字:
boost::asio::ip::udp::socket socket;
socket
( _ioService,
boost::asio::ip::udp::endpoint
( boost::asio::ip::udp::v4(), port ) );
客户端打开它的套接字:
boost::asio::ip::udp::socket socket;
socket( _ioService );
socket.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 );
}
}
由于客户端从工作的开始到结束使用相同的套接字实例,服务器是否可以安全地将端点用作客户端的标识符?
答案 0 :(得分:1)
提升IP endpoint至少标识唯一标识UDP连接的5个值中的3个:protocol (UDP)
,source IP
,source port
。如果您的服务器只使用一个dest IP
/ dest port
或者您自己添加这些参数或者这无关紧要,那么您可以将其用作某种会话标识符。但有几点困难:
通常,建立会话概念通常最好在应用程序级别上完成,例如生成一个随机UUID4并为每个数据包添加前缀。通过指定客户端必须重用此标识符来解决问题1。问题二解决了,因为任何客户端都不可能使用相同的UUID,因此实际上可以使用相当大的超时。
答案 1 :(得分:0)
这取决于您的客户端应用程序。它需要在本地打开一个端口并将数据报发送到您的服务器。客户端可以绑定到特定的本地端口,也可以让操作系统随机选择一个空闲的本地端口。只要套接字绑定到本地UDP端口,端口号就不会改变。但是,如果客户端选择在发送数据报后关闭套接字,并且如果它没有显式绑定到它要发送的下一个数据报的同一本地端口,则操作系统可以自由选择完全不同的端口。
当客户端位于具有NAT的路由器后面时,可能还会发生源端口被重写,并且无法保证此端口号在任何时间内都能保持稳定。
因此,虽然它可能在大多数时间都有效,但我不会依赖受控环境之外的行为。您可以切换到基于连接的协议(TCP)或使用自己的会话ID。后者可能很棘手,因为你甚至需要在程序重启时管理它们以防止双重ID并添加一些检查以防止会话劫持,如果这对你来说是个问题。