/* * echo2.c * * sklar modified from http://dada.perl.it/shootout/echo_allsrc.html * * on cunix compile like this: gcc echo2.c -o echo2.x -lsocket * * the difference between this and echo.c is that this one is * simpler and shows hopefully a little clearer, the difference between * the server and the client. * * in this program, the echo_client() prompts the user for input, and * then sends that input to the server. the echo_server() reads that * input and then sends a confirmation ("okay") back to the client. * */ #include #include #include #include #include #include #include #include #include #include typedef int socklen_t; // sklar #define TERM '\n' int sigchld = 0; /*-------------------------------------------------------------------- sysabort() system error occured; reports error and exits program ------------------------------------------------------------------*/ void sysabort ( char *m ) { perror( m ); exit( 1 ); } /* end of sysabort() */ /*-------------------------------------------------------------------- signal_handler() ------------------------------------------------------------------*/ void signal_handler ( int sig ) { sigchld = 1; } /* end of signal_handler() */ /*-------------------------------------------------------------------- server_sock() creates a socket by calling genericSock and then binds an address to that socket, then specifies willingness to accept incoming connections via listen ------------------------------------------------------------------*/ int server_sock () { int ss, optval = 1; struct sockaddr_in sin; /* (1) create an endpoint for communication */ if ((ss = socket(PF_INET, SOCK_STREAM, 0)) == -1) { sysabort( "server/socket" ); } /* (1a) set socket options */ if ( setsockopt( ss, SOL_SOCKET, /* to manipulate options at the socket level */ SO_REUSEADDR, /* basically allows socket to bind */ (const char *)&optval, sizeof(optval)) == -1 ) { sysabort( "server/setsockopt" ); } memset( &sin, 0, sizeof( sin )); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sin.sin_port = 0; /* (2) bind the socket */ if ( bind( ss,(struct sockaddr *)&sin,(socklen_t)sizeof(sin) ) == -1 ) { sysabort( "server/bind" ); } /* (3) listen for connections */ listen( ss,2 ); /* return the socket descriptor */ return( ss ); } /* end of server_sock() */ /*-------------------------------------------------------------------- client_sock() creates a socket by calling genericSock and then attempts to make a connection to that socket ------------------------------------------------------------------*/ int client_sock ( int port ) { int ss, optval = 1; struct sockaddr_in sin; /* (1) create an endpoint for communication */ if (( ss = socket( PF_INET, SOCK_STREAM, 0 )) == -1) { sysabort( "client/socket" ); } /* (1a) set socket options */ if ( setsockopt( ss, SOL_SOCKET, SO_REUSEADDR, /* basically allows socket to bind */ (const char *)&optval, sizeof(optval)) == -1 ) { sysabort( "client/setsockopt" ); } memset( &sin, 0, sizeof( sin )); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sin.sin_port = port; /* (2) make a connection to the server socket */ if ( connect( ss,(struct sockaddr *)&sin,(socklen_t)sizeof(sin) ) == -1 ) { sysabort( "client/connect" ); } /* return the socket descriptor */ return( ss ); } /* end of client_sock() */ /*-------------------------------------------------------------------- get_port() ------------------------------------------------------------------*/ int get_port ( int sock ) { struct sockaddr_in sin; socklen_t slen = sizeof( sin ); /* get the name of specified socket "sock" and stores it in "sin" */ if ( getsockname(sock, (struct sockaddr *)&sin, &slen) == -1 ) { sysabort( "getsockname" ); } return( sin.sin_port ); } /* end of get_port() */ /*-------------------------------------------------------------------- echo_client() ------------------------------------------------------------------*/ void echo_client ( int port ) { int i, sock, olen, nwritten, nread, more; char ibuf[64], obuf[64], *p; /* create client socket on port... */ printf( "client: port=%d\n",port ); sock = client_sock( port ); /* loop, reading input from client and sending it to server */ more = 1; while ( more ) { printf( "enter message to send (q to quit): " ); p = obuf; p = fgets( p,64,stdin ); p[strlen(p)-1] = '\0'; if ( p[0] == 'q' ) { more = 0; } else { printf( "client: writing message [%s]\n",p ); i = strlen( p ); if (( nwritten = write( sock, &i, sizeof( i ) )) == -1 ) { sysabort( "client/write" ); } if (( nwritten = write( sock, p, strlen(p) )) == -1 ) { sysabort( "client/write" ); } p = ibuf; if (( nread = read( sock, p, 64 )) > 0 ) { p[nread] = '\0'; printf( "client: read message [%s]\n",p ); fflush( stdout ); } else { sysabort( "client/read" ); } } } // end while more /* close socket connection */ close( sock ); } /* end of echo_client() */ /*-------------------------------------------------------------------- echo_server() ------------------------------------------------------------------*/ void echo_server () { int ssock, csock, more, nread, nwritten, i, status; pid_t pid; char ibuf[64], obuf[64], *p; struct sockaddr_in sin; socklen_t slen = sizeof( sin ); ssock = server_sock(); signal( SIGCHLD, signal_handler ); if (( pid = fork( )) == -1 ) { sysabort( "server/fork" ); } if ( pid ) { /* accept returns a socket descriptor for the accepted socket */ if (( csock = accept( ssock, (struct sockaddr *)&sin, &slen )) == -1 ) { sysabort( "server/accept" ); } fprintf( stdout,"server: socket created/listen/accepted\n" ); fflush( stdout ); /* loop while reading on the socket... */ more = 1; while ( more ) { if (( nread = read( csock, &i, sizeof( i ))) < 0 ) { sysabort( "server/read" ); } if ( sigchld ) { more = 0; } else { fprintf( stdout,"server: i=%d\n",i ); fflush( stdout ); if (( nread = read( csock, ibuf, i )) < 0 ) { sysabort( "server/read" ); } if ( sigchld ) { more = 0; } ibuf[nread] = '\0'; fprintf( stdout,"server: read message [%s]\n",ibuf ); fflush( stdout ); /* now do output... */ strcpy( obuf,"okay" ); p = obuf; fprintf( stdout,"server: writing message [%s]\n",p ); fflush( stdout ); if (( nwritten = write( csock, p, strlen(p) )) == -1 ) { sysabort( "server/write" ); } } } close( csock ); } else { echo_client( get_port( ssock )); } wait( &status ); } /* end of echo_server() */ /*-------------------------------------------------------------------- main() ------------------------------------------------------------------*/ int main( int argc, char *argv[] ) { echo_server( 1 ); return( 0 ); } /* end of main() */