Solved

Create a client server system

Posted on 2004-03-25
15
284 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.
0
Comment
Question by:bashaer
  • 5
  • 5
  • 3
  • +1
15 Comments
 
LVL 3

Expert Comment

by:idt
ID: 10679405
Homework sparky?
0
 

Author Comment

by:bashaer
ID: 10679551
yes
0
 
LVL 3

Expert Comment

by:idt
ID: 10679757
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
0
 
LVL 3

Expert Comment

by:idt
ID: 10679803
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.

0
 

Author Comment

by:bashaer
ID: 10679879
I only want guidelines on how to solve the problem. Where to start and what techniques to use. NOT THE SOLUTION.
0
 
LVL 45

Expert Comment

by:Kdo
ID: 10680219
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
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10687374
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
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:bashaer
ID: 10697842
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;

}
0
 
LVL 3

Expert Comment

by:idt
ID: 10700237
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.
0
 

Author Comment

by:bashaer
ID: 10757981
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*/

0
 
LVL 45

Expert Comment

by:Kdo
ID: 10758138

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);
     }
0
 
LVL 3

Expert Comment

by:idt
ID: 10760256
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
0
 

Author Comment

by:bashaer
ID: 10764055
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%
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10764414
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...) < .. )
0
 
LVL 45

Accepted Solution

by:
sunnycoder earned 325 total points
ID: 10765502
Another note about your program ... you do not do the cleanup before you exit
e.g.

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

you need to close the file handles before you exit !!!
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand and use structures in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to use strings and some functions related to them in the C programming language.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now