UDP Based Server Can't Distinguish Different Users

114 views Asked by At

This is a C++ server application which communicates with all clients based on UDP protocol. When a user logs into the server from client, the client application registers a UDP channel to the server and this channel is in fixed format: IP+Port, which means if the IP keeps unchanged, then no matter what user logged in the client registers a same channel.

The server's socket layer maintains a heartbeat mechanism which will remove the channel if it doesn't receive any heartbeat packets from the channel in 3 minutes. Everything works fine until the client is down, e.g. the network wire is plugged off. Look at below scene:

    1. User-A logs into server. The Client registers channel (IP:Port) 
       to the server. Because the UDP channel is alive, so the Server 
       sets the User status of User-A as Online. 

    2. Kill the client process, and within 3 minutes(before the channel 
       timeouts in server), let User-B logs into server from the same 
       computer. Because the IP remains unchanged, so actually the client 
       registers a same (IP:PORT) pair to the server as it did when User-A
       logs in.

    3. Since the Server receives packets from (IP:PORT), so it considers
       User-A is still alive, thus setting the user status of User-A as 
       Online which is not right anymore.

In above scenario, the Server is not able distinguish different users logged from a same computer, which results in wrong user states. Does anybody know how to solve this problem?

1

There are 1 answers

0
cjhanks On

I see no reason to presume that the origin port number for any two users will be identical unless the client application is explicitly binding the UDP socket. Clients which initiate the communication can often use ephemeral ports just as effectively. Ephemeral ports may or may not be sufficiently random for your particular use case, code below shows how to access client ports from inbound UDP data. If they are not sufficiently random, it may be wise to encode session cookies or user-cookies into the protocol.

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

int 
main() {
        /*- setup UDP socket on 8500 */
        int rc;
        int server_socket;
        struct sockaddr_in server_address;

        server_socket = socket(AF_INET, SOCK_DGRAM, 0);
        if (server_socket < 0) {
                perror("failed to init socket");
                return 1;
        }

        memset(&server_address, 0, sizeof(server_address));
        server_address.sin_family      = AF_INET;
        server_address.sin_port        = htons(8500);
        server_address.sin_addr.s_addr = inet_addr("127.0.0.1");

        rc = bind(server_socket, (struct sockaddr*) &server_address
                , sizeof(server_address));

        if (rc < 0) { 
                perror("failed to bind");
                return 2;
        }

        /* - receive from UDP socket and print out origin port - */
        char buffer[4096];
        struct sockaddr_in client_address;
        int client_address_len = sizeof(client_address);

        rc = recvfrom(server_socket
                    , buffer 
                    , sizeof(buffer)
                    , 0
                    , (struct sockaddr*) &client_address
                    , &client_address_len);

        if (rc < 0)
                return 3;

        fprintf(stderr, "%s %d\n", buffer, ntohs(client_address.sin_port));

        return 0;
}