//------------------------------------------------------------------- // peekdemo.cpp // // This is a TCP client-application for use with our 'slowecho' // server. It transmits a message, then waits for that message // to be returned in its entirety, but uses the 'recv()' socket // function with the MSG_PEEK flag to watch characters arriving // one-by-one in the TCP socket's input-queue before it finally // dequeues them with 'read()' and shuts the socket connection. // Our purpose here is to examine, in slow motion, the exchange // of TCP packets using our 'nicwatch' packet-sniffing utility. // // to compile: $ g++ peekdemo.cpp -o peekdemo // to execute: $ ./peekdemo // // NOTE: For this demo a privileged user would need to turn off // the 'tcp_window_scaling' option so that outgoing TCP packets // will express the 'window-size' in bytes (without 'scaling'). // For Linux kernel version 2.6.26, this can be done using: // // root# echo 0 > /proc/sys/net/ipv4/tcp_window_scaling // // programmer: ALLAN CRUSE // written on: 27 FEB 2009 //------------------------------------------------------------------- #include // for gethostbyname(), socket() #include // for printf(), perror() #include // for exit() #include // for read(), write(), close() #include // for strncpy() #define DEMO_PORT 54321 int main( int argc, char **argv ) { //------------------------------------------------- // get the server's hostname from the command-line //------------------------------------------------- if ( argc == 1 ) { fprintf( stderr, "must specify server\n" ); exit(1); } char peername[ 64 ] = { 0 }; strncpy( peername, argv[ 1 ], 63 ); //-------------------------------------- // obtain the IP-address for the server //-------------------------------------- struct hostent *pp = gethostbyname( peername ); if ( !pp ) { herror( "gethostbyname" ); exit(1); } //-------------------------------------------- // construct a socket-address for this server //-------------------------------------------- struct sockaddr_in paddr = { 0 }; socklen_t palen = sizeof( paddr ); paddr.sin_family = AF_INET; paddr.sin_port = htons( DEMO_PORT ); paddr.sin_addr.s_addr = *(int32_t*)pp->h_addr; //--------------------------------------------------------------- // prompt the user for the input-message and accept the response //--------------------------------------------------------------- printf( "\nPlease type a short sentence on the line below: \n" ); char msg[ 80 ] = { 0 }; int n = read( STDIN_FILENO, msg, sizeof( msg ) ); //--------------------------------------------------- // create a socket for communication with the server //--------------------------------------------------- int sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( sock < 0 ) { perror( "socket" ); exit(1); } //------------------------------------------------- // shrink the size of this socket's receive-buffer //------------------------------------------------- int oval = 256; socklen_t olen = sizeof( oval ); if ( setsockopt( sock, SOL_SOCKET, SO_RCVBUF, &oval, olen ) < 0 ) { perror( "setsockopt" ); exit(1); } //--------------------------------------------------- // obtain the modified buffer-size for display later //--------------------------------------------------- if ( getsockopt( sock, SOL_SOCKET, SO_RCVBUF, &oval, &olen ) < 0 ) { perror( "getsockopt" ); exit(1); } //---------------------------------------- // establish a connection with the server //---------------------------------------- if ( connect( sock, (sockaddr*)&paddr, palen ) < 0 ) { perror( "connect" ); exit(1); } //------------------------------------------------------- // write the message-characters to the socket one-by-one //------------------------------------------------------- for (int i = 0; i < n; i++) if ( write( sock, msg+i, 1 ) < 0 ) { perror( "write" ); break; } //---------------------------------------------- // shut down the writing end of this connection //----------------------------------------------- fflush( fdopen( sock, "rw" ) ); if ( shutdown( sock, SHUT_WR ) < 0 ) perror( "shutdown" ); //----------------------------------------- // receive all the replies from the server //----------------------------------------- char buf[ 1500 ] = { 0 }; int len = sizeof( buf ); int m = 0; while( 1 ) { int px = recv( sock, buf, len, MSG_PEEK ); if ( px < 0 ) { perror( "recv PEEK" ); exit(1); } if ( px == n ) break; if ( px == m ) continue; printf( "\r%s", buf ); fflush( stdout ); ++m; } printf( "\n\nsize of socket's receive-buffer:" ); printf( " 0x%04X (=%d bytes) \n\n", oval, oval ); //-------------------------------------------------- // close the socket and release its file descriptor //-------------------------------------------------- int rx = read( sock, buf, len ); if ( rx < 0 ) { perror( "read" ); exit(1); } if ( close( sock ) < 0 ) perror( "close" ); }