A More Fully Commented Version of client.c



/*============================================================*
  File name : client.c
  Related files: server.c
  Author : Ting-jen Yen (yentj@cs.nyu.edu)
  Date : 1998 (for Yap's visualization class)

  Description : This is the client side program
                of a simple TCP client-server test program.
                It simply reads a number (unsigned, integer
		or float) from the user input, sends it to the
		server (see server.c file), and then
                display everything returned from the server.
                This is repeated until the user types "quit",
		at which point both sides will close the connection.

  Usage: Simply type "client" to access the server at 
		jinai.cs.nyu.edu, at default port 1234.
	The general format is
		 % client [] [ -p  ]

  How to compile :

  On Solaris 2 :

	% gcc -o client client.c -lsocket -lnsl

  On SGI machines or Linux machines:

	% gcc -o client client.c

 *============================================================*/


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

int             con_sock;
int             srv_port = 1234;
char		host[128];

/*
  Received a signal. Close the connection and quit.
*/
void signal_handler()
{
	close(con_sock);

	exit(0);
}


/*============================================================*
  establish_connection()
	performs the first 2 steps of a connection-based client:
		(a) socket()
		(b) connect()
	as in the lecture notes.

  	It makes a connection to the server.
  	It uses the global variables host and srv_port
  	as input.  Then it updates the value of con_sock,
  	which is the file descriptor of the socket
  	used for communicating with the server.
 *============================================================*/

establish_connection()
{
	struct sockaddr_in name;
	struct hostent *hptr;
	int flag;

   /*  create a socket  */
	con_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

		// SOCKET is step (a) of a connection-based server
		//	in our lecture notes
		// PF_INET specifies the protocol family.
		// 	PF_INET refers to the TCP/IP protocols.
		// 	N.B. Confusingly, the argument "AF_INET" is
		//	sometimes used in place of "PF_INET".  This
		//	is based on a misconception, as pointed out 
		/	by [Comer+Stevens, p.47].
		// SOCK_STREAM specifies that we want the stream service
		//	in this protocol family (i.e., TCP)
		// The last argument IPPROTO_TCP identifies which stream
		//	service in the protocol family to pick
		//	(if there are no alternatives, this value can
		//	be set to 0).  Since PF_INET has only one choice
		//	this means IPPROTO_TCP must be 0.

	if (con_sock <= 0) {
		perror("Open socket failed");
		exit(1);
	}

	name.sin_family = AF_INET;
	name.sin_port = htons(srv_port); // set up port number
					 // The utility htons="host to network
					 // short" converts a short value
					 // from the "host byte order" to 
					 // "network byte order".
					 // See [Comer+Stevens, p.53].

   /* getting the host IP information */

	if ((hptr = gethostbyname(host)) == NULL) {
	  perror("gethostbyname");
	  exit(1);
	}

	bcopy(hptr->h_addr, (char *)&name.sin_addr.s_addr, hptr->h_length);

	printf("Trying to contact %s...\n", host);

   /* making connection */
	flag = connect(con_sock, (struct sockaddr *) &name, sizeof(name));
		// CONNECT is step (b) of a connection-based server
		//	in our lecture notes

	if (flag < 0)
	{
	  perror("No connection");
	  close(con_sock);
	  exit(1);
	}
	printf("Connected\n");
}

extern int errno;


/*============================================================*
  make_trans() 
	will get user input, put them to the server,
	and then display the return message from the server.

	In other words, it performs the
		(c) write()
		(d) read()
	loop described in the lecture notes for connection-oriented client.
 *============================================================*/


make_trans()
{
  char buff[1024], out[1024];
  int lg, flag;

  flag = 1;

  do {
	/* getting one line from standard input */
    gets(buff);

    sprintf(out, "%s\r\n", buff);
	/* write everything to the network. */
    lg = write(con_sock, out, strlen(out));

	/* If having any trouble with the socket, it means that
   	the connection is closed somehow, quit the program. */
    if (lg == -1 && errno == EBADF)
      goto error;

	/* If the user input is "quit", then end the loop. */
    if (strncmp(buff, "quit", 4) == 0)
    {
      flag = 0;
      break;
    }
    do {
	/* get response from the server. If therer is error
   	and it is EBADF, it means the connection might
   	be closed, otherwise, try to read it again until
   	we read it successfully.   */
    lg = read(con_sock, buff, 1024);
    if (lg == -1 && errno == EBADF)
      goto error;
    } while (lg <= 0);
    if (buff[lg - 1] != '\n' || buff[lg - 2] != '\r') {
       fprintf(stderr, "Error: Wrong format\r\n");
    }

	/* Display the response to standard output */
    buff[lg - 1] = '\0';
    buff[lg - 2] = '\n';
    printf("%s", buff);
  } while (flag);

	/* close the connection if */
  error:
  close(con_sock);
}//make_trans


usage()
{
	fprintf(stderr, "usage: client [-p port]\n");
	exit(1);
}

main(argc, argv)
int argc;
char **argv;
{
	int             lg;


/* shift the parameters */
	argc--;
	argv++;

/* set initial value of the server. */
	strcpy(host, "jinai.cs.nyu.edu");
	while (argc > 0) {
		if (argv[0][0] != '-')
		{
/* setting new server name */
		  strcpy(host, argv[0]);
		  argv ++;
		  argc --;
		  continue;
		}
		switch (argv[0][1]) {
/* setting port number */
		case 'p':
			srv_port = atoi(argv[1]);
			argv += 2;
			argc -= 2;
			break;
		default:
			usage();
		}
	}

/* Intercept some signals so we can quit the program
   more gracefully when interrupted by such signals. */
	signal(SIGTERM, signal_handler);
	signal(SIGQUIT, signal_handler);
	signal(SIGINT, signal_handler);

	establish_connection();
	make_trans();
}