/* * Copyright 2007 Stephen Liu * For license terms, see the file COPYING along with this library. */ #include #include #include #include #include #include #include #ifdef WIN32 #include "spgetopt.h" #endif #include "spporting.hpp" #include "event.h" static const char * gHost = "127.0.0.1"; static int gPort = 3333; static int gMsgs = 10; static int gClients = 10; static int gConnWait = 0; static int gSockWait = 0; static time_t gStartTime = 0; struct SP_TestClient { int mFd; struct event mReadEvent; struct event mWriteEvent; int mSendMsgs; int mRecvMsgs; char mBuffer[ 512 ]; }; void showUsage( const char * program ) { printf( "\nStress Test Tools for spserver example -- testecho/testchat\n\n" ); printf( "Usage: %s [-h ] [-p ] [-c ] [-m ]\n" "\t\t\t[-w ] [-s ]\n\n", program ); printf( "\t-h default is %s\n", gHost ); printf( "\t-p default is %d\n", gPort ); printf( "\t-c how many clients, default is %d\n", gClients ); printf( "\t-m messages per client, default is %d\n", gMsgs ); printf( "\t-w how many milliseconds to wait between creating every 100 connections, default is %d\n", gConnWait ); printf( "\t-s how many milliseconds to wait between every event loop, default is %d\n", gSockWait ); printf( "\n" ); } void close_read( SP_TestClient * client ) { //fprintf( stderr, "#%d close read\n", client->mFd ); event_del( &client->mReadEvent ); gClients--; } void close_write( SP_TestClient * client ) { //fprintf( stderr, "#%d close write\n", client->mFd ); event_del( &client->mWriteEvent ); } void close_client( SP_TestClient * client ) { close_write( client ); close_read( client ); } void on_read( int fd, short events, void *arg ) { SP_TestClient * client = ( SP_TestClient * ) arg; if( EV_READ & events ) { int len = recv( fd, client->mBuffer, sizeof( client->mBuffer ), 0 ); if( len <= 0 ) { if( len < 0 && EAGAIN != errno ) { fprintf( stderr, "#%d on_read error, count %d, errno %d, %s\n", fd, client->mRecvMsgs, errno, strerror( errno ) ); } close_client( client ); } else { for( int i = 0; i < len; i++ ) { //if( 10 == fd ) printf( "%c", client->mBuffer[i] ); if( '\n' == client->mBuffer[i] ) client->mRecvMsgs++; } } } else { fprintf( stderr, "#%d on_read timeout\n", fd ); close_client( client ); } } void on_write( int fd, short events, void *arg ) { SP_TestClient * client = ( SP_TestClient * ) arg; if( EV_WRITE & events ) { client->mSendMsgs++; if( client->mSendMsgs >= gMsgs ) { snprintf( client->mBuffer, sizeof( client->mBuffer ), "quit\n" ); } else { snprintf( client->mBuffer, sizeof( client->mBuffer ), "mail #%d, It's good to see how people hire; " "that tells us how to market ourselves to them.\n", client->mSendMsgs ); } int len = send( fd, client->mBuffer, strlen( client->mBuffer ), 0 ); if( len <= 0 && EAGAIN != errno ) { fprintf( stderr, "#%d on_write error, errno %d, %s\n", fd, errno, strerror( errno ) ); close_client( client ); } else { if( client->mSendMsgs >= gMsgs ) close_write( client ); } } else { fprintf( stderr, "#%d on_write timeout\n", fd ); close_client( client ); } } void parse_arg( int argc, char * argv[] ) { extern char *optarg ; int c ; while( ( c = getopt ( argc, argv, "h:p:c:m:w:s:v" )) != EOF ) { switch ( c ) { case 'h' : gHost = optarg; break; case 'p': gPort = atoi( optarg ); break; case 'c' : gClients = atoi ( optarg ); break; case 'm' : gMsgs = atoi( optarg ); break; case 'w': gConnWait = atoi( optarg ); break; case 's': gSockWait = atoi( optarg ); break; case 'v' : case '?' : showUsage( argv[0] ); exit( 0 ); } } } int main( int argc, char * argv[] ) { parse_arg( argc, argv ); #ifdef SIGPIPE signal( SIGPIPE, SIG_IGN ); #endif sp_initsock(); event_init(); SP_TestClient * clientList = (SP_TestClient*)calloc( gClients, sizeof( SP_TestClient ) ); struct sockaddr_in sin; memset( &sin, 0, sizeof(sin) ); sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr( gHost ); sin.sin_port = htons( gPort ); int totalClients = gClients, i = 0; printf( "Create %d connections to server, it will take some minutes to complete.\n", gClients ); for( i = 0; i < gClients; i++ ) { SP_TestClient * client = clientList + i; client->mFd = socket( AF_INET, SOCK_STREAM, 0 ); if( client->mFd < 0 ) { fprintf(stderr, "#%d, socket failed, errno %d, %s\n", i, errno, strerror( errno ) ); #ifdef WIN32 spwin32_pause_console(); #endif return -1; } if( connect( client->mFd, (struct sockaddr *)&sin, sizeof(sin) ) != 0) { fprintf(stderr, "#%d, connect failed, errno %d, %s\n", i, errno, strerror( errno ) ); #ifdef WIN32 spwin32_pause_console(); #endif return -1; } event_set( &client->mWriteEvent, client->mFd, EV_WRITE | EV_PERSIST, on_write, client ); event_add( &client->mWriteEvent, NULL ); event_set( &client->mReadEvent, client->mFd, EV_READ | EV_PERSIST, on_read, client ); event_add( &client->mReadEvent, NULL ); if( 0 == ( i % 10 ) ) write( fileno( stdout ), ".", 1 ); if( gConnWait > 0 && ( i > 0 ) && ( 0 == ( i % 100 ) ) ) usleep( gConnWait * 1000 ); } time( &gStartTime ); struct timeval startTime, stopTime; sp_gettimeofday( &startTime, NULL ); time_t lastInfoTime = time( NULL ); // start event loop until all clients are exit while( gClients > 0 ) { event_loop( EVLOOP_ONCE ); if( time( NULL ) - lastInfoTime > 5 ) { time( &lastInfoTime ); printf( "waiting for %d client(s) to exit\n", gClients ); } if( gSockWait > 0 ) usleep( gSockWait * 1000 ); } sp_gettimeofday( &stopTime, NULL ); double totalTime = (double) ( 1000000 * ( stopTime.tv_sec - startTime.tv_sec ) + ( stopTime.tv_usec - startTime.tv_usec ) ) / 1000000; // show result printf( "\n\nTest result :\n" ); printf( "Host %s, Port %d, ConnWait: %d, SockWait: %d\n", gHost, gPort, gConnWait, gSockWait ); printf( "Clients : %d, Messages Per Client : %d\n", totalClients, gMsgs ); printf( "ExecTimes: %.6f seconds\n\n", totalTime ); printf( "client\tSend\tRecv\n" ); int totalSend = 0, totalRecv = 0; for( i = 0; i < totalClients; i++ ) { SP_TestClient * client = clientList + i; //printf( "client#%d : %d\t%d\n", i, client->mSendMsgs, client->mRecvMsgs ); totalSend += client->mSendMsgs; totalRecv += client->mRecvMsgs; sp_close( client->mFd ); } printf( "total : %d\t%d\n", totalSend, totalRecv ); printf( "average : %.0f/s\t%.0f/s\n", totalSend / totalTime, totalRecv / totalTime ); free( clientList ); #ifdef WIN32 spwin32_pause_console(); #endif return 0; }