Aquarius_Girl
Aquarius_Girl

Reputation: 22936

How to ensure that server distinguishes two different TCP clients running from two different shells on the same computer?

If I run the client program from two different shells, how should the server be able to determine to whom he is talking to currently?

Platform: Linux, GCC

Client code: This client takes the host name as an argument.

#define SERVERPORT 3490
#define MAXDATASIZE 1000 

int main (int argc, char *argv[])
{
    int             clientSocketFD;
    int                 numOfBytesReceived;
    char                    receivedData[MAXDATASIZE];
    struct hostent                  *objHostent;
    struct sockaddr_in              serverAddress;

    if (argc != 2) 
    {
        fprintf (stderr,"usage: key in client hostname.\n");
        exit (1);
    }

    if ((objHostent = gethostbyname (argv[1])) == NULL)
    {
        herror ("error: incorrect host name specified.");
        exit (1);
    }

    if ((clientSocketFD = socket (PF_INET, SOCK_STREAM, 0)) == -1) 
    {
        perror ("error: socket system call failed.");
        exit (1);
    }

    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port    = htons (SERVERPORT);
    serverAddress.sin_addr   = *((struct in_addr *)objHostent->h_addr);
    memset (serverAddress.sin_zero, '\0', sizeof serverAddress.sin_zero);

    if (connect (clientSocketFD, (struct sockaddr *)&serverAddress, sizeof serverAddress) == -1)
    {
        perror ("connect() error");
        exit (1);
    }

    while (1)
    {
        if ((numOfBytesReceived = recv (clientSocketFD, receivedData, MAXDATASIZE-1, 0)) == -1)
        {
            perror ("\nrecv() error");
        }

        receivedData [numOfBytesReceived] = '\0';

        if (send (clientSocketFD, "Get Lost", 15, 0) == -1)
        {
            perror ("send() error");
        }
    }
    close (clientSocketFD);
    return 0;
}

Server code:

#define SERVERPORT 3490
#define BACKLOG 10

struct threadArguments
{
    int    threadId;
    int    listeningSocketDescriptor;
    char *message;
};

struct threadArguments threadDataArray [5];

void* genericThreadFunction (void* threadData)
{
    struct threadArguments *temp;
    temp         = (struct threadArguments *) threadData;

    printf ("Hello World! It's me, thread #%ld!\n", (long) temp->threadId);

    while (1)
    {
        if (send (temp->listeningSocketDescriptor, temp->message, 14, 0) == -1)
            perror ("\nsend() error\n");

        char receivedData [14];
        int    numOfBytesReceived;
        if ((numOfBytesReceived = recv (temp->listeningSocketDescriptor, receivedData, 14-1, 0)) == -1)
        {
            perror ("\nrecv() error\n");
        }
        else
        {
            receivedData [numOfBytesReceived] = '\0';
            printf ("\nReceived: %s\n", receivedData);
        }
    }
}

int main (void)
{
    int                 serverSocketFD;
    int                 newServersocketFD;
    struct sockaddr_in          serverAddress;

    struct sockaddr_in          clientAddress;
    socklen_t           sin_size;

    if ((serverSocketFD = socket (AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror ("socket");
        exit (1);
    }
    int yes=1;
    if (setsockopt (serverSocketFD, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
    {
        perror ("setsockopt");
        exit (1);
    }

    serverAddress.sin_family     = AF_INET;                 // host byte order
    serverAddress.sin_port       = htons (SERVERPORT);      // short, network byte order
    serverAddress.sin_addr.s_addr = INADDR_ANY;             // automatically fill with my IP
    memset (serverAddress.sin_zero, '\0', sizeof serverAddress.sin_zero);

    if (bind (serverSocketFD, (struct sockaddr *)&serverAddress, sizeof serverAddress) == -1)
    {
        perror ("bind");
        exit (1);
    }

    if (listen (serverSocketFD, BACKLOG) == -1)
    {
        perror ("listen"); 
        exit (1);
    }

    pthread_t threads [5];
    int     returnValueOfPthreadCreate;
    long    threadId = -1;

    while (1) 
    {
        sin_size = sizeof clientAddress;
        if ((newServersocketFD = accept (serverSocketFD, (struct sockaddr *)&clientAddress, &sin_size)) == -1) 
        {
                perror ("accept");
                continue;
        }
        printf ("accept(): got connection from %s\n", inet_ntoa (clientAddress.sin_addr));

        threadId++;

        threadDataArray [threadId].threadId                  = threadId;
        threadDataArray [threadId].listeningSocketDescriptor = newServersocketFD;
        threadDataArray [threadId].message                   = "Excuse Me, please!";

        returnValueOfPthreadCreate = pthread_create (&threads [threadId], NULL, genericThreadFunction, (void*) &threadDataArray[threadId]);

        if (returnValueOfPthreadCreate)
        {
            printf ("ERROR; return code from pthread_create() is %d\n", returnValueOfPthreadCreate);
        }
    }

    pthread_exit (NULL);
    return 0;
}

EDIT 1.

Peername returns 0:

if ((newServersocketFD                                                 = accept (serverSocketFD, (struct sockaddr *)&clientAddress, &sin_size)) == -1) 
        {
                perror ("accept");
                continue;
        }
        printf ("accept(): got connection from %s\n", inet_ntoa (clientAddress.sin_addr));
        printf ("\npeername: %d", getpeername (newServersocketFD, (struct sockaddr *)&clientAddress, &sin_size));

Upvotes: 1

Views: 718

Answers (2)

alk
alk

Reputation: 70971

The client's ip-address and (source-)port, fetched as described below, do identify a client(-connection) uniquely.

If you are using address family IF_INET to create the listen()ing socket you can pull the client's ip-address and (the client's connection specific) (source-)port from the variable of type struct sockaddr_in which's reference was passed to accept() by using it's members sin_addr and sin_porteach time accept() returns successfully.

Depending on the platform you are on, you need to change the byte order of such members (see man-page for ntoh() on how to do this). For directly converting the member sin_addr to a character array you are already using a method (inet_ntoa()) taking care of the byte order.

Using getpeername() on the file descriptor which was return by the successful accept() (and, in the context of the server process, is also uniquely identifying the client's connection) shall return the same values for ip-address and port of the peer as the call to accept() did.

Upvotes: 6

ugoren
ugoren

Reputation: 16441

You'll have a separate accepted socket (newServersocketFD in your code) per client.
If you use getpeername() on each, you'll find that they use different source ports.

Upvotes: 2

Related Questions