Reputation: 22936
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;
}
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
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_port
each 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
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