user1958241
user1958241

Reputation:

Identifying the messages from clients in multiple client single server program implemented in C

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

Answers (2)

Maxim Egorushkin
Maxim Egorushkin

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

KrisSodroski
KrisSodroski

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

Related Questions