Reputation:
I am a beginner in Networking. I implemented a multiple-client single-server program using sockets in C. If I run the server and two or more instances of the client then how do I identify the client who has sent a message to server. Is this implementation correct or do I have to modify it?
//server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include<netinet/in.h>
#include<stdlib.h>
#include<unistd.h>
#define MAX 1000
void serveClient(int sock)
{
int r;
char buffer[MAX];
do
{
bzero(buffer, sizeof(buffer));
r = read(sock, buffer, sizeof(buffer));
if(strcasecmp(buffer,"bye")==0) return;
if(r != 0)
printf("\nMessage from client : %s\n",buffer);
}while(1);
}
int main()
{
int sockfd, newfd, len, r, pid;
char buff[MAX];
struct sockaddr_in servaddr,cliaddr;
//creating socket
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(1);
}
else
printf("\nSocket created\n");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(7790);
servaddr.sin_addr.s_addr = INADDR_ANY;
//bnding a name to socket
if(bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind");
exit(1);
}
else
printf("\nBind successful\n");
//listening for connections
if(listen(sockfd, 5) < 0)
{
perror("listen");
exit(1);
}
else
printf("\nListening...\n");
//accepting a connection
do
{
len = sizeof(cliaddr);
if((newfd = accept(sockfd, (struct sockaddr*)&cliaddr, &len)) < 0)
{
perror("accept");
exit(1);
}
else
printf("\nNew connection accepted\n");
pid = fork();
if(pid == -1)
{
perror("fork");
close(newfd);
continue;
}
else if(pid == 0)
{
serveClient(newfd);
close(newfd);
printf("\nClient terminated\n\nWaiting for new client...\n");
}
else
{
close(newfd);
}
}while(1);
close(sockfd);
return 0;
}
//client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include<stdlib.h>
#define MAX 1000
int main(int argc, char *argv[])
{
int len, sockfd, n;
char buff[MAX];
; struct sockaddr_in servaddr, cliaddr;
if(argc == 2)
{
//creating socket
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(1);
}
else
printf("\nSocket created\n");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(7790);
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
//initiating connection on the socket
if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
{
perror("connect");
exit(1);
}
else
printf("\nConnected\n");
//sending message
printf("\nType \"bye\" to disconnect\n");
do
{
printf("\nMessage : ");
scanf("%s",buff);
n = write(sockfd, buff, sizeof(buff));
if(strcasecmp(buff, "bye") == 0) exit(0);
}while(1);
close(sockfd);
}
else
{
printf("\nSpecify an IP address\n");
exit(1);
}
return 0;
}
Upvotes: 0
Views: 2881
Reputation: 136238
If I run the server and two or more instances of the client then how do I identify the client who has sent a message to server.
Each client is identified by its unique file descriptor returned from accept()
. You can get client's address and port number from the file descriptor using getpeername()
.
In a real-world application a server keeps more client state in a structure allocated when accept()
succeed and the client's file descriptor is normally a member of that structure. In other words, that structure associated with the client connection is the client from the server's point of view. This way it is easy to clean up when the client disconnects - just deallocate the structure and close the file descriptor (or, much better, use C++ destructors).
Upvotes: 1
Reputation: 2842
There's a lot of books that say when you have a server client architecture on an unix based OS, let hte OS do all the hard work. When they say this, they mean have your primary thread listening on a socket for clients. When a client comes in, accept hte connection and fork the new socket created with accept to a new thread/process (use a thread, not a process actually, so don't use fork but pthreads). Then have this thread handle that client, and you can distinguish clients based on the thread that is servicing them.
You seem to be doing the fork implementation. While this may seem like a good idea, remember that your child is going to have the same memory footprint as your parent unless you reload the program image using exec. Its a better idea to use threads, so that you only have one program image, and less overhead on every client connecting. You can create even less overhead by having a thread pool waiting on a semaphore, and then release one on a connect. Keep your accepted new file descriptors in an array that you can keep track of. If you run out of threads, you can have one do multiple clients, or just create another t hread to handle the influx! Then you can destroy them later.
You can also just create your communication protocol to contain client data so that you can tell who is saying what. The only problem is that you will have to scan each packet to find out which client it belongs to, and store it until you get the whole message (if it doens't all fit in one packet). Its just easier to use the pthread model of accept, hand off. That way, you can just identify each client by your thread's threadid.
Upvotes: 1