简体   繁体   中英

Can a Boost.asio endpoint be used to identify a client over time for UDP connections?

In a client/server application, my client connects to the server via UDP using Boost.asio .

The server opens its socket like this:

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

The client opens its socket like this:

boost::asio::ip::udp::socket socket;
socket( _ioService );
socket.open( boost::asio::ip::udp::v4() );

Then when a client sends its first message to the server, the server uses the client endpoint as an identifier for future messages. Here is a simplification of the identification process:

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

Since the client uses the same socket instance from the beginning to the end of its work, is it safe for the server to use the endpoint as an identifier of the client?

A boost IP endpoint at least identifies 3 of the 5 values that uniquely identify a UDP connection: protocol (UDP) , source IP , source port . If your server uses only one dest IP / dest port or you add these parameters yourself or this does not matter, then yes you can use this as some sort of session identifier. A few gotchas though:

  • This is only realistic during some application-specific transaction. For example, in a file transfer client, it might be that you setup a new connection for every file. Also, a single client might use parallel connections to speed things up making your life harder. This is not even UDP specific, TCP has the same issue.
  • Deleting the session/identifier is extremely hard. UDP has no explicit disconnect as TCP has, so you have to use some idle timeout. However, put this too short and you might remove the identifier to soon, put this too long and an actually new connection might be identified as an old one.

In general, establishing a session concept is usually better done on application level, eg generate a random UUID4 and prefix that to every packet. Problem one is solved by specifying that the client must reuse this identifier. Problem two is solved because it's unlikely that any client will ever use the same UUID, so you can actually use quite a large timeout.

This depends on your client application. It needs to open a port locally and send a datagram to your server. The client can either bind to a specific local port or let the operating system choose a free local port at random. As long as the socket is bound to the local UDP port, the port number won't change. However, if the client chooses to close the socket after sending a datagram and if it does not explicitly bind to the same local port for the next datagram it is about to send, the operating system is free to choose a totally different port.

When the client is behind a router with NAT, it might also happen that the source port is rewritten and there is no guarantee that this port number will stay stable for any amount of time.

So while it might work most of the time, I would not rely on the behavior outside a controlled environment. You might switch to a connection based protocol (TCP) or use own session IDs. The latter might be tricky, because you'll need to manage them possibly even across program restarts to prevent double IDs and add some checks to prevent session hijacking if that's an issue for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM