/////////////////////////////////////////////////////////////////////////////////////// // file : tcp_chat.c // author : Alain Greiner // date : december 2020 /////////////////////////////////////////////////////////////////////////////////////// // This file describes a TCP chat application. Depending on the "is_server argument, // it can be used to launch the the TCP client, or the TCP server application. // The client send the first message. The server wait this first message. // The 4 command line arguments are: is_server, local_ip_addr, remote_ip_addr, port /////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #define BUF_SIZE 256 //////////////////////////// void client_chat( int fdid ) { char buffer[BUF_SIZE]; // string buffer (for both send and receive) int size; // string length (including NUL) int nbytes; // number of characters actually sent or received while( 1 ) { //////// display client prompt to wait local client message //////// printf("\n[local client] "); // build local client message size = get_string( buffer , BUF_SIZE ); // exit chat function when client message is the "exit" string if( strncmp( "exit" , buffer , 4 ) == 0 ) { printf("\n[client_chat] local message is => return to main\n" ); return; } // send local client message nbytes = send( fdid , buffer , size , 0 ); if( nbytes != size ) { printf("\n[client_chat error] cannot send => return to main\n"); return; } ///////// display server prompt to wait remote server message /////// printf("\n[remote server] "); // receive remote server message nbytes = recv( fdid , buffer , BUF_SIZE , 0 ); if( nbytes < 0 ) { printf("\n\n[client_chat error] cannot receive => return to main\n" ); return; } else if( nbytes == 0 ) { printf("\n\n[client_chat] receive EOF => return to main\n" ); return; } // display remote server message printf("%s\n", buffer ); } } // end client_chat() //////////////////////////// void server_chat( int fdid ) { char buffer[BUF_SIZE]; // string buffer (for send and receive) int size; // string length (including NUL) int nbytes; // number of characters actually sent or received while( 1 ) { //////// display client prompt to wait remote client message /////// printf("\n[remote client] "); // receive remote client message nbytes = recv( fdid , buffer , BUF_SIZE , 0 ); if( nbytes < 0 ) { printf("\n\n[server_chat error] cannot receive => return to main\n" ); return; } else if( nbytes == 0 ) { printf("\n\n[server_chat] receive EOF => return to main\n" ); return; } // display remote client message printf("%s\n", buffer ); //////// display server prompt to wait local server message ////// printf("\n[local server] "); // build local server message size = get_string( buffer , BUF_SIZE ); // exit chat function when server message is the "exit" string if( strncmp( "exit" , buffer , 4 ) == 0 ) { printf("\n[server_chat] local message is => return to main\n" ); return; } // send local server message nbytes = send( fdid , buffer , size , 0 ); if( nbytes != size ) { printf("\n[server_chat error] cannot send => return to main\n"); return; } } } // end server_chat() /////////////////////// int main( int argc, char ** argv ) { int pid; // process identifier int fdid; // file index of local socket int new_fdid; // file index for new derver socket int error; sockaddr_in_t local_sin; // local socket internet address sockaddr_in_t remote_sin; // remote socket internet address int addr_length = sizeof(sockaddr_t); unsigned long long start_cycle; // get start cycle get_cycle( &start_cycle ); // get PID pid = getpid(); // get arguments if( argc != 4 ) { printf("\n usage : tcp_chat is_server local_addr remote_addr port\n"); exit( 0 ); } int is_server = atoi( argv[0] ); int local_addr = atoi( argv[1] ); int remote_addr = atoi( argv[2] ); int port = atoi( argv[3] ); if( is_server ) printf("\n[%s] SERVER / pid %x / cycle %d / local %x / remote %x / port %x\n", __FUNCTION__, pid, (unsigned int)start_cycle, local_addr, remote_addr, port ); else printf("\n[%s] CLIENT / pid %x / cycle %d / local %x / remote %x / port %x\n", __FUNCTION__, pid, (unsigned int)start_cycle, local_addr, remote_addr, port ); // initialize local_sin local_sin.sin_domain = HTONS( AF_INET ); local_sin.sin_addr = HTONL( local_addr ); local_sin.sin_port = HTONS( port ); // initialize remote_sin remote_sin.sin_domain = HTONS( AF_INET ); remote_sin.sin_addr = HTONL( remote_addr ); remote_sin.sin_port = HTONS( port ); // create local TCP socket fdid = socket( AF_INET, SOCK_STREAM, 0 ); if( fdid < 0 ) { printf("\n[error] in %s : cannot create socket\n", __FUNCTION__ ); exit( 0 ); } else { printf("\n[%s] created socket[%x,%d]\n", __FUNCTION__, pid, fdid ); } // bind local socket error = bind( fdid, (sockaddr_t *)(&local_sin), sizeof(sockaddr_t) ); if( error ) { printf("\n[error] in %s : cannot bind socket[%x,%d]\n", __FUNCTION__, pid, fdid ); exit( 0 ); } else { printf("\n[%s] client socket[%x,%d] bound\n", __FUNCTION__, pid, fdid ); } /////////////// if( is_server ) { // Listen client connection request error = listen( fdid , 1 ); if( error ) { printf("\n[error] in %s : socket[%x,%d] cannot listen\n", __FUNCTION__, pid, fdid ); exit( 0 ); } else { printf("\n[%s] listening socket[%x,%d] wait client connection\n", __FUNCTION__ , pid , fdid ); } // get new chat socket fdid new_fdid = accept( fdid, (sockaddr_t *)&remote_sin, &addr_length ); if( new_fdid < 0 ) { printf("\n[error] in %s : listening socket[%x,%d] cannot accept\n", __FUNCTION__, pid, fdid ); exit( 0 ); } else { printf("\n[%s] new socket[%x,%d] connected to client\n", __FUNCTION__, pid, new_fdid ); } // call server_chat function server_chat( new_fdid ); // 6 close both listen and chat sockets close( fdid ); close( new_fdid ); printf("\n[tcp_server] closed both & sockets\n" ); } ////////////////// else // is_client { // connect to remote socket error = connect( fdid, (sockaddr_t *)(&remote_sin), sizeof(sockaddr_t) ); if( error ) { printf("\n[error] in %s : socket[%x,%d] cannot connect\n", __FUNCTION__ , pid , fdid ); exit( 0 ); } else { printf("\n[%s] socket[%x,%d] connected to server\n", __FUNCTION__ , pid, fdid ); } // call client_chat function client_chat( fdid ); // close local socket close( fdid ); printf("\n[%s] client closed socket[%x,%d]\n", __FUNCTION__, pid, fdid ); } exit(0); return 0; }