#include #include #include #include #include #include #include #include #include #define BUF_SIZE 1024 typedef struct MultithreadedEchoServer { char portNum[ 6 ]; int numConnections; pthread_mutex_t lock; } mtEchoServer; void mtEchoServer_init( mtEchoServer * p, int port ) { p->numConnections = 0; pthread_mutex_init( &p->lock, NULL ); sprintf( p->portNum, "%d", port & 0xffff ); } void mtEchoServer_incConnections( mtEchoServer * p ) { pthread_mutex_lock( &p->lock ); p->numConnections++; pthread_mutex_unlock( &p->lock ); } void mtEchoServer_decConnections( mtEchoServer * p ) { pthread_mutex_lock( &p->lock ); p->numConnections--; pthread_mutex_unlock( &p->lock ); } int mtEchoServer_getNumConnections( mtEchoServer * p ) { int result; pthread_mutex_lock( &p->lock ); result = p->numConnections; pthread_mutex_unlock( &p->lock ); return result; } typedef struct bundle { mtEchoServer *es; int sock; } Bundle; void *handleConnection( void * param ) { Bundle *b = (Bundle *) param; int sock = b->sock; mtEchoServer *es = b->es; char greeting[ 256 ]; int i; int bytes; char buf[ BUF_SIZE ]; mtEchoServer_incConnections( es ); sprintf( greeting, "WELCOME TO MY ECHO SERVER %s!!! YOU ARE NUMBER %d\r\n", es->portNum, mtEchoServer_getNumConnections( es ) ); send( sock, greeting, strlen( greeting ), 0 ); while( ( bytes = recv( sock, buf, BUF_SIZE, 0 ) ) > 0 ) { for( i = 0; i < bytes; i++ ) buf[ i ] = toupper( buf[ i ] ); send( sock, buf, bytes, 0 ); } if( bytes < 0 ) fprintf( stderr, "Error on socket\n" ); else fprintf( stderr, "Connection closed\n" ); mtEchoServer_decConnections( es ); close( sock ); free( b ); return NULL; } void mtEchoServer_start( mtEchoServer * p ) { struct addrinfo hints, *res; pthread_t *connectionHandler; int ss; int s; memset( &hints, 0, sizeof( hints ) ); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if( getaddrinfo( NULL, p->portNum, &hints, &res ) ) { fprintf( stderr, "Error invoking getaddrinfo\n" ); return; } ss = socket( res->ai_family, res->ai_socktype, res->ai_protocol ); if( ss < 0 ) { fprintf( stderr, "Error creating socket\n\r" ); return; } if( bind( ss, res->ai_addr, res->ai_addrlen ) < 0 ) { fprintf( stderr, "Error binding to port %s\n", p->portNum ); return; } if( listen( ss, 20 ) < 0 ) { fprintf( stderr, "Error listening to port %s\n", p->portNum ); return; } for( ; ; ) { struct sockaddr_storage *their_addr; socklen_t *addr_size; int sizeofSockAddrStorage = sizeof( struct sockaddr_storage ); Bundle *b; their_addr = (struct sockaddr_storage *) malloc( sizeofSockAddrStorage ); addr_size = (socklen_t *) malloc( sizeof( socklen_t ) ); *addr_size = sizeofSockAddrStorage; s = accept( ss, (struct sockaddr *) their_addr, addr_size ); if( s < 0 ) { fprintf( stderr, "Error in accept %s\n", p->portNum ); return; } connectionHandler = (pthread_t *) malloc( sizeof( pthread_t ) ); b = (Bundle *) malloc( sizeof( Bundle ) ); b->es = p; b->sock = s; pthread_create( connectionHandler, NULL, handleConnection, (void *) b ); } } void * serverStart( void * port ) { mtEchoServer mt1; mtEchoServer_init( &mt1, (int) port ); mtEchoServer_start( &mt1 ); return NULL; } int main( ) { void *status; pthread_t t1, t2; int port1 = 3737, port2 = 4444; pthread_create( &t1, NULL, serverStart, (void *) port1 ); pthread_create( &t2, NULL, serverStart, (void *) port2 ); pthread_join( t1, &status ); pthread_join( t2, &status ); pthread_exit( NULL ); return 0; }