• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 227
  • Last Modified:

Client/Server...2 small questions...

i have developed a simple concurrent server in C.

2 small questions

1)Firstly i would like to show how many concurent connections there are connected to the server.

Adding to the count is no problem( simply increment after the accept). The problem comes when i try to decrement the count...The thing is that i must pass a msg from the child process to the parent which is usuailly done with a Signal. I cant figure them out. Can someone tell me what to do?

2) and lets say that within the server i have this....

struct sockaddr_in caller;
.
.
.
if ((csd = accept(ssd, (struct sockaddr *)&caller, &length)) < 0)
      ERROR ("accept");

How do I show the client's IP address on the server screen? I have looked up the sockaddr and sockaddr_in structures but i still cant get it!!...I know i must do something like....

printf("Client's IP Address is: %s", caller->...);

What is the exact syntax??

Thankyou guys

JAs.
0
alexeijames
Asked:
alexeijames
  • 7
  • 4
1 Solution
 
smpoojaryCommented:
For question
2)

if ((csd = accept(ssd, (struct sockaddr *)&caller, &length)) < 0)
{
  perror("accept");
  ...
}
printf("server: got connection from %s\n", inet_ntoa(caller.sin_addr));
-Mahesh
0
 
smpoojaryCommented:
For question
1)
I think for handle child process you are using fork(). After finished the child process anyhow it sends SIGCHLD to the parent. you have to catch it and goto the function (eg. void sigchld_handler(int s)) there resume the parent process (use wait()). Inside that function you can decrement the counter. like

void sigchld_handler(int s)
{
      wait(NULL);
      //Decrement your counter here
}

main()
{
   ....
      struct sigaction sa;
   ...
     sa.sa_handler = sigchld_handler; // reap all dead processes
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = SA_RESTART;
     if (sigaction(SIGCHLD, &sa, NULL) == -1)
     {
        perror("sigaction");
        exit(1);
     }
....
}
-Mahesh
0
 
alexeijamesAuthor Commented:
OK I Managed displaying the IP!

The problem is that i didnt understand where we have to put that Signal Catcher that you told me about...

This is my code....I put it before the Fork()... but i think its wrong becasue my client count still does not decrement properly!!!

Note: int clicount is meant to count the current number of connections.


#include <stdio.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>



#define ERROR(s) {fprintf(stderr,"%d-",errno); perror(s); return(-1);}

int clicount = 0;
void sigchld_handler(int s);
int GiveFile (int csd);
int client();
int count;


main (argc, argv)
     int argc;
     char *argv[];
{
  struct sockaddr_in sa;
  struct sockaddr_in caller;
  struct sigaction sig;

  int ssd;
  int csd;
  int length;
char details[BUFSIZ];
int rval;
  if (argc != 2) {
    fprintf (stdout, "usage: %s hostname\n", argv[0]);
    exit (-1);
  }

  printf( "\nSERVER: LISTENING FOR CONNECTIONS...\n\n" );

  sa.sin_family= AF_INET;
  sa.sin_addr.s_addr = INADDR_ANY;
  sa.sin_port= htons((u_short) atoi(argv[1]));

  if ((ssd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    ERROR ("socket");

  if (bind(ssd, (struct sockaddr *)&sa, sizeof sa) < 0)
    ERROR ("bind");

  length = sizeof(sa);

  listen (ssd, 5);

  for (;;) {
    if ((csd = accept(ssd, (struct sockaddr *)&caller, &length)) < 0)
      ERROR ("accept");
            system("clear");


      printf("Server: New Connection - IP Address: %s\n", inet_ntoa(caller.sin_addr));

      sig.sa_handler = sigchld_handler; // reap all dead processes
           sigemptyset(&sig.sa_mask);
           sig.sa_flags = SA_RESTART;
           if (sigaction(SIGCHLD, &sig, NULL) == -1)
           {
              perror("sigaction");
              exit(1);
     }





    int pid = fork();

    switch (pid) {

    case -1:
      {perror("fork");
      close(ssd);
      close(csd);
      exit(1);
            }

    case 0:
      {
      close(ssd);
      while (client(csd) ==0);
          }
    default :
      {
        close(csd);
        clicount++;
        printf("Server: Current Clients: %i\n", clicount);
      }
    }
  }
}


/*---------------------------------------------------------CLIENT---------------------------*/

int client(int sd) {
  int csd=sd;
  int retval;
  int action;
  int exitflag = 0;
  char bufmode[BUFSIZ];



while( exitflag == 0 ){

if((retval = read(csd, bufmode, sizeof(bufmode))) < 0)
      ERROR("Reading stream message\n");
//      buf[retval]='\0';

switch (bufmode[0])
      {

      //case 'V': {  ViewDetails(csd); break; }
      case 'D': { GiveFile ( csd );  break; }
      case 'Q': {      printf("Server: Client closed connection at socket %i",csd);
                        exitflag = 1;
                        break;}

      }
} // end of while
close( csd );

exit(1);
}

/*---------------------------------------------------------CLIENT---------------------------*/

void sigchld_handler(int s)
{
      wait(NULL);
      clicount = clicount - 1;
}



/*---------------------------------------------------------GIVE FILE---------------------------*/
GiveFile(int csd)      {


int filedes;
struct stat filestat;
char filename[100];
char buf[BUFSIZ];


      printf("Server: Request for Download...");

      char path[100];
                  strcpy( path , "./shared/" );
                  strcat( path , "alex.txt");
                  printf( "\n" );

                  filedes = open( path , O_RDONLY );
                  if ( filedes == -1 )

                  { //invalid file name
                        printf( "\n\nERROR: The file requested does not exist in your SHARED folder.");
                  }
                  printf( "Server: Sending..." );

                  buf[0] = 'g';
                  int temp = write ( csd , buf , 1 );
                  if ( temp == -1 ){ perror( "cannot write to pipe" ); exit(1); }


                  fstat ( filedes , &filestat);
                  printf( "%i..." , filestat.st_size );

                  char size[32]; sprintf( size , "%i" ,filestat.st_size);
                  temp = write ( csd , size , sizeof(size) );
                  if ( temp == -1 ){ perror( "cannot write to pipe" ); exit(1); }


                  // read one byte into buf

                  while ( read( filedes, buf , 1 ) != 0 )
                  {

                  //send one char at a time through socket to avoid problems with network byte ordering
                        temp = write ( csd , buf , 1 );
                        if ( temp == -1 ){ perror( strerror( errno ) ); }
                  }

                  buf[0] = EOF;
                  temp = write ( csd , buf , 1 );
                  if ( temp == -1 ){ perror( strerror( errno ) ); exit(1); }

                  close( filedes );

                  printf("Transfer Complete\n");

/*---------------------------------------------------------GIVE FILE---------------------------*/

}
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
smpoojaryCommented:
Modify the above code as
int clicount = 0;
int GiveFile (int csd);
int client();
int count;

void sigchld_handler(int s)
{
      waitpid(0,0,0);
          /*Decrement your counter here*/
      --clicount;
      printf("Server: Connection Closed : Current Clients: %i\n", clicount);
}

main (argc, argv)
...

 listen (ssd, 5);

 sig.sa_handler = sigchld_handler; // reap all dead processes
 sigemptyset(&sig.sa_mask);
 sig.sa_flags = SA_RESTART;
 if (sigaction(SIGCHLD, &sig, NULL) == -1)
 {
            perror("sigaction");
            exit(1);
 }

 for (;;)
 {
   if ((csd = accept(ssd, (struct sockaddr *)&caller, &length)) < 0)
   {
         perror ("accept");
         continue;
   }
    /*system("clear");*/
    printf("Server: New Connection - IP Address: %s\n", inet_ntoa(caller.sin_addr));

    pid = fork();

    switch (pid)
    {
    case -1:
      perror("fork");
      close(ssd);
      close(csd);
      exit(1);
          break;

    case 0:
      close(ssd);
      while (client(csd) ==0);
          close(csd);
       // sleep(2);
          exit(0);  //See here to exit from client
          break;
    default :
       close(csd);
       ++clicount;
       printf("Server: Current Clients: %i\n", clicount);
           break;
    }/*End of switch(pid)*/
  }/*End of for(;;)*/
  return 0;
}/*End of main()*/

With regards
-Mahesh
0
 
alexeijamesAuthor Commented:
ok cool...thx!


When the client requests a Quit (by pressing Q) the count is decremented perfectly...

the only thing is that if the user (client)  presses ctrl-z (exit) the signal is not sent to the parent process and the count remains the same.

How do i catch that and decrement the count? If it is very complex do not worry...

Thanks...again!

JAs
0
 
smpoojaryCommented:
put

  signal(SIGTSTP,SIG_IGN);  //Ignoring Cntrl_Z signal

above for(;;)

-Mahesh
0
 
smpoojaryCommented:
YOu can also do as following. Add following code


sigset_t sigmask;
...
listen (ssd, 5);

     sigemptyset(&sigmask);
     if(sigaddset(&sigmask,SIGTSTP) == -1 ||
             sigprocmask(SIG_SETMASK,&sigmask,0) == -1)
                     perror("set signal mask");

sig.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sig.sa_mask);
sig.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sig, NULL) == -1)
...

-Mahesh
0
 
alexeijamesAuthor Commented:
thankyou very much!

JAs
0
 
alexeijamesAuthor Commented:
ah what you told me is to ignore the Ctrl-Z command if inputted to the server...

What i would have liked was this ( but it doesnt matter too much!):

Server: running normally
.
Client: Connects to server
Server: count + 1
.
.
//client does something
Client: Downloads file for example
.
.
//client exits abruptly with Ctrl-Z
Client: Ctrl-Z is entered (ending communication immediate with the server) as opposed to pressing 'Q' from the menu.
Server: Client count decrements


0
 
smpoojaryCommented:
For this inside child-process in server you have to detect connection failure also. If connection failure or child process sucessfully finishes client request, in both cases you have to exit from the child using exit(0). Means in any case, you have to exit form the child process. Then only the signal SIGCHLD is sent to parent process. I think, in your code, if connection failure occurs in child process the child process won't terminate. This is sure. Check once again.
-Mahesh
0
 
smpoojaryCommented:
Check return value of recv. It it is 0 then you have to think that connection failure occured.

if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0)
{
    // got error or connection closed by client
    if (nbytes == 0)
    {
           // connection closed
           printf("selectserver: socket %d hung up\n", i);
    } else
    {
          perror("recv");
    }
    exit(1);  //Exit from the child process on failure
} else
{
     //Do processing
}

exit(0);  //exit from the child process on success

0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 7
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now