8

I have just started learning basic networking concepts.I am trying to implement a multithread server-client prog in C.but the problem is instead of running multiple windows/terminals/instances for clients,i should use fork() to create children of client.so by creating children of client multiple clients will be created.now each of these child clients will communicate with the server on a thread.

Earlier i created a similar prog but in that for multiple client you have to open multiple windows for clients and run all of them.

I am having trouble where to modify my code (both in server and client ones.I think server one is ok.but i am having no idea where to fork() in client program and what changes should be made).

Actually i don't want to open multiple windows to run multiple client,thats why i am using fork() to create multiple copies of it.Is there any other way by which i can create multiple clients and connect them to my server prog via threads.

Server :

// socket server example, handles multiple clients using threads

#include<stdio.h>
#include<string.h>    //strlen
#include<stdlib.h>    //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write
#include<pthread.h> //for threading , link with lpthread

//the thread function
void *connection_handler(void *);

int main(int argc , char *argv[])
{
    int socket_desc , client_sock , c , *new_sock;
    struct sockaddr_in server , client;

    //Create socket
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    {
        printf("Could not create socket");
    }
    puts("Socket created");

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 3000 );

    //Bind
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
    {
        //print the error message
        perror("bind failed. Error");
        return 1;
    }
    puts("bind done");

    //Listen
    listen(socket_desc , 3);

    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);

        c=sizeof(struct sockaddr_in);
       while(client_sock=accept(socket_desc,(struct sockaddr*)&client,(socklen_t*)&c))
       {
        puts("Connection accepted");

        pthread_t sniffer_thread;
        new_sock = malloc(1);
        *new_sock = client_sock;

        if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
        {
            perror("could not create thread");
            return 1;
        }

        puts("Handler assigned");
    }

    if (client_sock < 0)
    {
        perror("accept failed");
        return 1;
    }
    return 0;
}
/*
  This will handle connection for each client
  */
void *connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    int sock = *(int*)socket_desc;
    int n;

        char    sendBuff[100], client_message[2000];

      while((n=recv(sock,client_message,2000,0))>0)
      {

        send(sock,client_message,n,0);
      }
      close(sock);

      if(n==0)
      {
        puts("Client Disconnected");
      }
      else
      {
        perror("recv failed");
      }
    return 0;
}

Client:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>

#define MAX_SIZE 50

int main()
{
    int sock_desc;
    struct sockaddr_in serv_addr;
    char sbuff[MAX_SIZE],rbuff[MAX_SIZE];

    if((sock_desc = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        printf("Failed creating socket\n");

    bzero((char *) &serv_addr, sizeof (serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(3000);

    if (connect(sock_desc, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
        printf("Failed to connect to server\n");
        return -1;
    }

    printf("Connected successfully - Please enter string\n");
    while(fgets(sbuff, MAX_SIZE , stdin)!=NULL)
    {
      send(sock_desc,sbuff,strlen(sbuff),0);

          if(recv(sock_desc,rbuff,MAX_SIZE,0)==0)
           printf("Error");
          else
           fputs(rbuff,stdout);

       bzero(rbuff,MAX_SIZE);//to clean buffer-->IMP otherwise previous word characters also came
    }
        close(sock_desc);
    return 0;

}
Shikhar Deep
  • 253
  • 2
  • 8
  • 19
  • Why do you want to `fork()` on client? This is unusual – Filipe Gonçalves Jan 28 '14 at 12:07
  • @Felipe: It would make sense if the client is test code to simulate multiple clients connecting to the server. – Klas Lindbäck Jan 28 '14 at 12:14
  • 1
    If you want to learn network programming I suggest you look at more modern concepts than fork. Investigate thread or event based IO. Forking is a primitive and obsolete model for network programs. – usr Jan 28 '14 at 12:17
  • Filipe:Thats' what my teacher asks me to.Actually i don't want to open multiple windows to run multiple client,thats why i am using fork() to create multiple copies of it.Is there any other way by which i can create multiple clients and connect them to my server prog via threads. – Shikhar Deep Jan 28 '14 at 12:40
  • You forgot to free(socket_desc) in connection_handler. – Chien-Wei Huang May 15 '15 at 07:13

2 Answers2

11

You can create multiple clients using thread. Create a separate thread for each client and then from thread handler connect to the server. I am not sure if it is a good way or not.

Code:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>

#define MAX_SIZE 50
#define NUM_CLIENT 5
void *connection_handler(void *socket_desc);
int main()
{
    int socket_desc , new_socket , c , *new_sock, i;
    pthread_t sniffer_thread;
    for (i=1; i<=NUM_CLIENT; i++) {
        if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) i) < 0)
        {
            perror("could not create thread");
            return 1;
        }
        sleep(3);
    }
    pthread_exit(NULL);
    return 0;
}

void *connection_handler(void *threadid)
{
    int threadnum = (int)threadid;
    int sock_desc;
    struct sockaddr_in serv_addr;
    char sbuff[MAX_SIZE],rbuff[MAX_SIZE];

    if((sock_desc = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        printf("Failed creating socket\n");

    bzero((char *) &serv_addr, sizeof (serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    if (connect(sock_desc, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
        printf("Failed to connect to server\n");
    }

    printf("Connected successfully client:%d\n", threadnum);
    while(1)
    {
        printf("For thread : %d\n", threadnum);
        fgets(sbuff, MAX_SIZE , stdin);
        send(sock_desc,sbuff,strlen(sbuff),0);

        if(recv(sock_desc,rbuff,MAX_SIZE,0)==0)
            printf("Error");
        else
           fputs(rbuff,stdout);

        bzero(rbuff,MAX_SIZE);
        sleep(2);
    }
    close(sock_desc);
    return 0;
}

For understanding purpose, i used sleep.

REF:

http://www.amazon.com/UNIX-Network-Programming-Richard-Stevens/dp/0139498761

http://beej.us/guide/bgnet/

https://computing.llnl.gov/tutorials/pthreads/

curious_beast
  • 85
  • 1
  • 9
sujin
  • 2,813
  • 2
  • 21
  • 33
  • sujin: getting following warnings and error mthclient.c: In function ‘main’: mthclient.c:18: warning: cast to pointer from integer of different size mthclient.c: In function ‘connection_handler’: mthclient.c:31: warning: cast from pointer to integer of different size /tmp/ccuPwTxp.o: In function main': mthclient.c:(.text+0x2d): undefined reference to pthread_create' collect2: ld returned 1 exit status lnxrc186055-14:/shikhar # ./c -bash: ./c: No such file or directory – Shikhar Deep Jan 28 '14 at 13:20
  • its working fine.but some synch. issue is there i think.... Server:-Socket created bind done Waiting for incoming connections... Connection accepted Handler assigned Connection accepted Handler assigned Connection accepted Handler assigned Connection accepted Handler assigned Connection accepted Handler assigned Client Disconnected Client Disconnected Client Disconnected Client Disconnected Client Disconnected – Shikhar Deep Jan 30 '14 at 06:05
  • client:-Connected successfully client:1 For thread : 1 hello hello hi $Connected successfully client:2 For thread : 2 hi ads $Connected successfully client:3 For thread : 3 ads adas asd $Connected successfully client:4 For thread : 4 adas $Connected successfully client:5 For thread : 5 asd........i am not able to post the output in proper format.sorry for that...'hi' which i wrote when client 1 gets connected gets echoed in client 2. why????? – Shikhar Deep Jan 30 '14 at 06:07
  • sujin:are you able to understand the o/p which i posted or shall i mail u the screenshot of o/ps.i don't know how to post screenshot here in stack overflow. – Shikhar Deep Jan 30 '14 at 06:12
  • All the threads are sharing same terminal, so there may be some conflict. I really don't understand what is the need of this app, just a home work right? – sujin Jan 30 '14 at 06:15
  • sujin:yeah just an assignment.but still if u can remove that conflict it will be nice.there is sleep for 5 sec.so whatever i type in that 5 sec should gets echoed back but its only echoing the very first message rest all the messages are getting echoed in next client.that's the only problem..in short for each client i can have only one echoed message ,if i wrote more than one then those messages gets echoed in next client. – Shikhar Deep Jan 30 '14 at 06:19
  • There is lots of changes need to do in client to meet your requirement. I just given you how to connect multiple client. practice more tcp ,thread and synchronization program, automatically you will find the conclusion for this problem. I can able to realize that this code from `binarytides.com`, there itself lots of example there. good luck for you success.. – sujin Jan 30 '14 at 06:24
  • okk,anyways thanks for your help.could you suggest me some websites and books for practicing tcp,network and socket programming and all these necessary os concepts like processes and threads. I have Unix ntwk Prog by richard stevens but its bitt tuff to understand.The language is not that much simple.Any book or website which builts my concepts from ground level?? – Shikhar Deep Jan 30 '14 at 06:28
  • `Richard steven` is always best. see my answer updates for more reference – sujin Jan 30 '14 at 06:30
6

Firstly, if you fork(), you will be creating additional processes, not additional threads. To create additional threads, you want to use pthread_create.

Secondly, as you are a student, the canonical answer here is 'read Stephens'. Not only is this an invaluable tool even for those of us experienced in writing socket I/O routines, but also it contains examples of non-threaded non-forking async I/O, and various ways to add threads and forking to them. I believe the one you want is: http://www.amazon.com/Programming-Environment-Addison-Wesley-Professional-Computing/dp/0321637739 (chapter 14 if memory serves). This should be in your college library.

abligh
  • 24,573
  • 4
  • 47
  • 84
  • 1
    1+ for recommending Stevens: http://www.amazon.de/Unix-Network-Programming-Richard-Stevens/dp/0139498761 – alk Jan 28 '14 at 14:06