We help IT Professionals succeed at work.

Create a client server system

bashaer
bashaer asked
on
Medium Priority
356 Views
Last Modified: 2010-04-15
Create a client server system similar to ICQ or IM. The system is much simpler and smaller version than the real ICQ or IM. The tool should be text based only. The idea is to write a program to create two processes (one client and one server). The client and the server need not to establish connection (i.e. no logging or password). They should know each other directly. The client takes a text line written by the user at the client side and sends this line to the server. The server will display this line and wait the user (at server side this time) to write a response to be sent to the client. And it goes back and forth until one of the two processes hits “bye” as the only string in the line. At that time..Both the server and the client should be terminated. Shared memory, piping, or sockets programming can be used.
Comment
Watch Question

idt

Commented:
Homework sparky?

Author

Commented:
yes
idt

Commented:
We cannot do your homework;

A) it would be fraud
B) it is a violation of Experts-Exchange membership rules.

Work on this yourself, and ask about specific problems that you are having.

Psuedo code:
Server
  Init some vars
  read a conf
  wait for connection on a socket
  while connected
    if input == 'bye' disconect
    else send back "some thing"
  }
  cleanup

Client
  Init some vars
  read a conf
  connect ot socket
  while connected
    get input from user
    send to server
    get input from server
    print it
  }
  cleanup
idt

Commented:
Do read up on non-blocking calls
This way your programs do not block, waiting for user, client  or server data.
In the above, the client could only recieve data from the server after the user entered something.

With non blocking, the client could connect, and the server could send out the time every minute, even when the user is idle.

Author

Commented:
I only want guidelines on how to solve the problem. Where to start and what techniques to use. NOT THE SOLUTION.
Kent OlsenData Warehouse / Database Architect
CERTIFIED EXPERT

Commented:
Hi bashaer,

Your rules state that "Shared memory, piping, or sockets programming can be used".  This allows you a lot of flexibility and lets you design your system based on your comfort level.

To properly design a process, you do need to understand the nature of what must happen.  You are going to read and write for a client program, as well as read and write for the server program.  If the two programs are purely "conversational" you can write from one and read from the other, then switch so that the program that just read performs a write and vice versa.  This may be a starting point, but it won't give you a very useful program.  If the same program wants to send two messages it has to wait after sending the first message for the other program to send a message.

Using client/server (socket) programming is by far the most versatile.  It will allow you to run the client program on one system and the server program on another.  It is also the most complicated.  For someone new to this process it is also the hardest to debug.

Shared memory might be the easiest methodology to understand, but it won't necessarily result in a program that's the easiest to code and understand.

A compromise of the two is pipes.  You can read() and write() the pipes and exchange memory that way.  It's easy to write.  Simply create a pair of pipes.  The client will read one pipe and write the other.  The server will write to the pipe that the client is reading and read from the pipe that the client is writing.


You description also states that to do this you will "write a program to create two processes".  Study up on the pipe() function.  It will create the pipes that your program will use.  Also study up on fork().  This function effectively splits your program into two programs.  You'll call pipe() to establish the pipes, the fork() to create two processes.

It should be quite easy set your program up in "conversational" mode.  (That is, the two programs take turns reading and writing.)  This should be a good staring point.  If you want to advance the program so that either side can read or write whenever it wants to, you'll have to perform non-blocking I/O as bashaer suggests, or utilize threads.  Threads are probably a complication that you're not ready for.



Good Luck,
Kent
CERTIFIED EXPERT
Top Expert 2006

Commented:
Try starting here
www.ecst.csuchico.edu/~beej/guide/net/html/

Follow the tutorial sincerly and you will be able to program the solution in no time

Author

Commented:
My partner and I wrote this code. But it's not working.
We are using pipes.
Please tell me where we went wrong..

#include <stdio.h>
#include <unistd.h>
#define SIZE 500

void do_parent(int [], int []);
void do_child( int [], int []);
int check_bye(char [],int);

char subject[SIZE];
int j=0;

int main(int argc, char* argv[]){

        int parent_to_child[2];
        int child_to_parent[2];
        int pid;
        int rc;

        rc=pipe(parent_to_child);
        if(rc==-1){
                perror("pipe :parent_to_child");
                exit(1);
        }


        rc=pipe(child_to_parent);
        if(rc==-1){
             perror("pipe :child_to_parent");
             exit(1);
        }


        pid=fork();
        switch (pid){
        case -1:  perror("fork");
                      exit(1);
        case 0:   do_child(parent_to_child,child_to_parent);
        default:  do_parent(child_to_parent,parent_to_child);
 }/*switch */

        return 0;


}/*main */


void do_parent(int pipe_input[], int pipe_output[]){

     int rc;
     int i=0;

         close(pipe_input[1]);
         close(pipe_output[0]);

         printf("Parent:");
         scanf("%c",&subject[i]);

         while(subject[i]!='/n'){

         scanf("%c",&subject[i]);
         i++;
         }/*while */

         j=i;

         rc=write(pipe_output[1],subject,SIZE);
         if(rc==-1){
                 perror("Parent:write");
                 close(pipe_input[0]);
                 close(pipe_output[1]);
                 exit(1);
         }/*if */

         rc=read(pipe_input[1],subject,SIZE);
         if(rc==-1){
                 perror("Child:write");
                 close(pipe_input[0]);
                 close(pipe_output[1]);
                 exit(1);
         }/*if */

         for(i=0;i<j;i++){
         printf("child: %c",&subject[i]);

         }/*while */

         close(pipe_input[0]);
         close(pipe_output[1]);
         exit(0);
}/*void do_parent */



void do_child(int pipe_input[], int pipe_output[]){

        int rc;
        int i=0;
        char received[SIZE];
        int check;

        close(pipe_input[1]);
        close(pipe_output[0]);

        while(read(pipe_input[0],received,SIZE)>0){
                check=check_bye(received, SIZE);
                if(check==0){
                    printf("child: bye\n");
                    exit(0);
                }
             else{        
                 for(i=0;i<j;i++){
                    printf("child: %c\n",&subject[i]);
                 }
             }/*else*/

                rc=write(pipe_output[1],received,SIZE);
                if(rc==-1){
                        perror("child:write");
                        exit(1);
                }

        }/*while*/

     close(pipe_input[0]);
         close(pipe_output[1]);
         exit(0);

}/*void do_child */

int check_bye(char rec[],int size)
{

        char b[]="bye";
        int i,z;

        for(i=0,z=0;i<3;i++,z++){

                if(b[z]!=rec[i])
                        return 1;
        }/*for */
        return 0;

}
idt

Commented:
Some observations:

Get rid of any public variables.  Pass any var to your functions as arguments.

You read how to use pipe, yet the first thing your functions do is close the file descriptors, and the try to read/write to them.

You pass the descriptors as arrays to your functions, yet you should only pass the decriptors that are relevent to each function.
ie:  your do_parent function has no need to ever know about pipe_output[0], yet it is in scope of that function.

You are using scanf to read one character at a time, yet are treating the results as if you have a 'string' array of characters.

Your do_parent function has no loop, so it will execute exactly one time.

Your remarks only serve to confuse you, you have a remark at a closing brace that says it closes a while, yet it closes a for.

Perhaps you should:

Write a separate function to get user input as a string array, make sure it is null terminated. Takes char * prompt, char* target, int maxlength as arguments, returns length read/error

Write a seperate function to read data from a pipe, taking file descriptor, and char * target as arguments, returns length read/error.

Write a seperate function to write data to a pipe, taking file descriptor, and char * source as arguments, returns success/error.

Daniel P.

Author

Commented:
We tried to fix the code.. but it still doesn't work???????


#include <stdio.h>
#include <unistd.h>
#define SIZE 500

void do_parent(int [], int []);
void do_child( int [], int []);
int check_bye(char [],int);
void print_char(char [],int );
void write_char(char []);

/*char subject[SIZE];*/


int main(int argc, char*argv[]){
      int parent_to_child[2];
    int child_to_parent[2];
      int pid;
      int rc;


      rc=pipe(parent_to_child);
      if(rc==-1){
            perror("pipe :parent_to_child");
            exit(1);
      }


      rc=pipe(child_to_parent);
    if(rc==-1){
            perror("pipe :child_to_parent");
            exit(1);
      }


      pid=fork();
      switch (pid){
      case -1:  perror("fork");
                  exit(1);
      case 0:   do_child(parent_to_child,child_to_parent);
      default:  do_parent(child_to_parent,parent_to_child);

      }//switch

      return 0;


}//main


void do_parent(int pipe_input[], int pipe_output[]){

     int rc;
       int i=0;
       int c;
       char subject[SIZE];


       close(pipe_input[1]);
       close(pipe_output[0]);

     printf("Parent:");
       write_char(subject);

       while((c=getchar())>0){

       rc=write(pipe_output[1],subject,SIZE);
       if(rc==-1){
             perror("Parent:write");
             close(pipe_input[0]);
             close(pipe_output[1]);
             exit(1);
       }/*if*/

       rc=read(pipe_input[1],subject,SIZE);
      c=(int)subject[i];
       if(rc==-1){
             perror("Child:write");
             close(pipe_input[0]);
             close(pipe_output[1]);
             exit(1);
       }//if
       printf("Parent read :");
       print_char(subject,SIZE);


       }/*while*/

     close(pipe_input[0]);
       close(pipe_output[1]);
       exit(0);
}/*void do_parent*/



void do_child(int pipe_input[], int pipe_output[]){

      int rc;
      int i=0;
      char received[SIZE];
      int check;

      close(pipe_input[1]);
      close(pipe_output[0]);

      while(read(pipe_input[0],received,SIZE)>0){

            printf("child read:");
            print_char(received,SIZE);

            check=check_bye(received, SIZE);
            if(check==0){
                  printf("bye\n");
                  exit(0);}

            printf("Child: ");
            write_char(received);
            rc=write(pipe_output[1],received,SIZE);
            if(rc==-1){
                  perror("child:write");
                  exit(1);
            }

      }/*while*/

     close(pipe_input[0]);
       close(pipe_output[1]);
       exit(0);

}/*void do_child*/


int check_bye(char rec[],int size)
{

      char b[]="bye";
      int i,j;

      for(i=0,j=0;i<size;i++,j++){

            if(b[j]!=rec[i])
                  return 1;


      }/*for*/
      return 0;

}/*int check_bye*/

void write_char(char sub[]){


      int s=0;
      scanf("%c",&sub[s]);
      while(sub[s]!='\n'){
            s++;
    scanf("%c",&sub[s]);
}
      sub[s]='\0';


}/*write_char*/


void print_char(char s[],int size ){
            for(int  i=0;s[i]!='\0' || i<size;i++)
           printf("%c",s[i]);

      printf("\n");

}/*print_char*/

Kent OlsenData Warehouse / Database Architect
CERTIFIED EXPERT

Commented:

Hi Bashaer,

Change the startup code in main() to look like this.  Both threads will the read via the descriptor ReadPipe and write via the descriptor WritePipe.

Kent




int main(int argc, char*argv[]){
     int Pipes[2];
     int ReadPipe;
     int WritePipe;
     int pid;
     int rc;


     rc=pipe(parent_to_child);
     if(rc==-1){
          perror("pipe :parent_to_child");
          exit(1);
     }

     pid=fork();
     switch (pid){
       case -1:
          perror("fork");
          exit(1);
     case 0:
          ReadPipe = Pipes[0];
          WritePipe = Pipes[1];
          do_child(parent_to_child,child_to_parent);
          break;

     default:
         ReadPipe = Pipes[1];
         WritePipe = Pipes[0];
         do_parent(child_to_parent,parent_to_child);
     }
idt

Commented:
For some reason
You are still closing your descriptors.
You are still passing the descriptors as arrays to your functions, yet you should only pass the decriptors that are relevent to each function.
You are still having trouble getting data from your user
Your loops aren't.

Your program does not satify the specifications, I suggest that you re-read the specs and make sure that you understand them.

Write sepearate functions for everything, and ensure that they work.
You are trying to do a lot of things, but have not tested each sub-part.

#include <stdio.h>
#define SIZE 500

int getUserString(char* prompr, char* target, int maxsize);
int main(int argc, char*argv[]);

int getUserString(char* prompt, char* target, int maxsize) {
  int c=0;
  int i=0;
  printf("%s",prompt);
  do {
    c=getchar();
    switch (c) {
      case 0x0A: case 0x0D: case EOF :
        c=-1; break;
      default :
        target[i++]=(char)c; break;
    }
  } while((c!=-1)&&(i<maxsize));
  target[i]=0x00;
  return(i);
}

int main(int argc, char*argv[]){
  char myString[SIZE+1];
  int collectedChars;
  collectedChars=getUserString("Enter Some Text Please:",myString,SIZE);
  printf("collected %d characters, and they are %s\n",collectedChars,myString);
  return (0);
}

By breaking your program into bite sized chunks, you will be able to test each piece.

Daniel

Author

Commented:
This code reads from the parent process, but gets stuck at the child process.. it doesn't read from the child?? Any suggestions??
Do we have to add a while loop in the parent process?? Or just the child process??



#include <stdio.h>
#include <unistd.h>
#define SIZE 500

void do_parent(int [], int []);
void do_child( int [], int []);
int check_bye(char [],int);
void getUserstring(char *,char*,int );


int main(int argc, char*argv[]){
        int parent_to_child[2];
        int child_to_parent[2];
        int pid;
        int rc;
     int Pipes[2];
     int ReadPipe;
     int WritePipe;

 rc=pipe(parent_to_child);
        if(rc==-1){
                perror("pipe :parent_to_child");
                exit(1);
        }


        rc=pipe(child_to_parent);
    if(rc==-1){
 perror("pipe :child_to_parent");
                exit(1);
        }


        pid=fork();
        switch (pid){
        case -1:  perror("fork");
                      exit(1);
        case 0:   ReadPipe = Pipes[0];
WritePipe = Pipes[1];

                   do_child(parent_to_child,child_to_parent);
                        break;

        default:  ReadPipe = Pipes[1];
                  WritePipe = Pipes[0];

                 do_parent(child_to_parent,parent_to_child);
 }/*switch*/

        return 0;


}/*main*/


void do_parent(int pipe_input[], int pipe_output[]){
 int rc;
         int i=0;
         char subject[SIZE];
         int check;

         close(pipe_input[1]);
         close(pipe_output[0]);

         getUserString("Parent:",subject,SIZE);
 rc=write(pipe_output[1],subject,SIZE);
         if(rc==-1){
                 perror("Parent:write");
                 close(pipe_input[0]);
                 close(pipe_output[1]);
                 exit(1);
         }/*if*/

rc=read(pipe_input[1],subject,SIZE);

         check=check_bye(subject, SIZE);

        if(check==0){
        printf("bye\n");
        exit(0);}

         if(rc==-1){
                 perror("Child:write");
                 close(pipe_input[0]);
                 close(pipe_output[1]);
                 exit(1);
         }/*if*/
         printf("Parent read :");
close(pipe_input[0]);
         close(pipe_output[1]);
         exit(0);
}/*void do_parent*/



void do_child(int pipe_input[], int pipe_output[]){

        int rc;
int i=0;
        char received[SIZE];
        int check;

        close(pipe_input[1]);
        close(pipe_output[0]);

        while(read(pipe_input[0],received,SIZE)>0){

                printf("child read:");
                printf("%s\n",received);

                check=check_bye(received, SIZE);
                if(check==0){
                        printf("bye\n");
                        exit(0);}

                 getUserString("Child:",received,SIZE);

                rc=write(pipe_output[1],received,SIZE);
if(rc==-1){
                        perror("child:write");
                        exit(1);
                }

        }/*while*/

         close(pipe_input[0]);
         close(pipe_output[1]);
         exit(0);
}/*void do_child*/


int check_bye(char rec[],int size)
{

        char b[]="bye";
        int i,j;
for(i=0,j=0;i<size;i++,j++){

                if(b[j]!=rec[i])
                        return 1;


        }/*for*/
        return 0;

}/*int check_bye*/

int getUserString(char* prompt, char* target, int maxsize) {
  int c=0;
  int i=0;
  printf("%s",prompt);
  do {
    c=getchar();
    switch (c) {
      case 0x0A: case 0x0D: case EOF :
        c=-1; break;
      default :
        target[i++]=(char)c; break;
    }
  } while((c!=-1)&&(i<maxsize));
  target[i]=0x00;

}

-----------------------------------------------------------------------------------------------------------------------
cairo% cc pipe.c
cairo% a.out
Parent:hi how r u
Child:write: child read:hi how r u
Child:Bad file number
cairo%
CERTIFIED EXPERT
Top Expert 2006

Commented:
void do_parent(int pipe_input[], int pipe_output[]){
 int rc;
         int i=0;
         char subject[SIZE];
         int check;

         close(pipe_input[1]);
         close(pipe_output[0]);

         getUserString("Parent:",subject,SIZE);
 rc=write(pipe_output[1],subject,SIZE);
         if(rc==-1){
                 perror("Parent:write");
                 close(pipe_input[0]);
                 close(pipe_output[1]);
                 exit(1);
         }/*if*/

rc=read(pipe_input[1],subject,SIZE); <<<<<<<<<<<<<<<<<<<<<<< you just closed pipe_input[1] ... reading from it will lead to the error saying bad descriptor


2. You are not printing the string recd by the parent

>>>>>>>>printf("Parent read :");<<<<<<<<<< is all you give !!!!

3. Since your child will be in an infinite loop sending and receiving alternately (read is a blocking call), either you put parent processing in a loop or you remove the while loop in the child
 ( while (read...) < .. )
CERTIFIED EXPERT
Top Expert 2006
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.