正在显示
1 个修改的文件
包含
330 行增加
和
0 行删除
src/server/spserver/testiocpstress.cpp
0 → 100644
1 | +/* | ||
2 | + * Copyright 2008 Stephen Liu | ||
3 | + * For license terms, see the file COPYING along with this library. | ||
4 | + */ | ||
5 | + | ||
6 | +#include <signal.h> | ||
7 | +#include <stdio.h> | ||
8 | +#include <sys/types.h> | ||
9 | +#include <stdlib.h> | ||
10 | +#include <errno.h> | ||
11 | +#include <time.h> | ||
12 | +#include <string.h> | ||
13 | + | ||
14 | +#include "spgetopt.h" | ||
15 | + | ||
16 | +#include "spwin32port.hpp" | ||
17 | + | ||
18 | +#pragma comment(lib,"ws2_32") | ||
19 | +#pragma comment(lib,"mswsock") | ||
20 | +#pragma comment(lib,"advapi32") | ||
21 | + | ||
22 | +static const char * gHost = "127.0.0.1"; | ||
23 | +static int gPort = 3333; | ||
24 | +static int gMsgs = 10; | ||
25 | +static int gClients = 10; | ||
26 | + | ||
27 | +struct SP_TestStat { | ||
28 | + int mRecvFail; | ||
29 | + int mWSARecvFail; | ||
30 | + | ||
31 | + int mSendFail; | ||
32 | + int mWSASendFail; | ||
33 | + | ||
34 | + int mGQCSFail; | ||
35 | +}; | ||
36 | + | ||
37 | +static struct SP_TestStat gStat; | ||
38 | +static time_t gStartTime = 0; | ||
39 | + | ||
40 | +struct SP_TestEvent { | ||
41 | + enum { eEventRecv, eEventSend }; | ||
42 | + | ||
43 | + OVERLAPPED mOverlapped; | ||
44 | + WSABUF mWsaBuf; | ||
45 | + int mType; | ||
46 | +}; | ||
47 | + | ||
48 | +struct SP_TestClient { | ||
49 | + SOCKET mFd; | ||
50 | + | ||
51 | + SP_TestEvent mRecvEvent; | ||
52 | + SP_TestEvent mSendEvent; | ||
53 | + | ||
54 | + int mSendMsgs; | ||
55 | + int mRecvMsgs; | ||
56 | + int mIsStop; | ||
57 | +}; | ||
58 | + | ||
59 | +void showUsage( const char * program ) | ||
60 | +{ | ||
61 | + printf( "Stress Test Tools for spserver example\n" ); | ||
62 | + printf( "Usage: %s [-h <host>] [-p <port>] [-c <clients>] [-m <messages>]\n", program ); | ||
63 | + printf( "\t-h default is %s\n", gHost ); | ||
64 | + printf( "\t-p default is %d\n", gPort ); | ||
65 | + printf( "\t-c how many clients, default is %d\n", gClients ); | ||
66 | + printf( "\t-m messages per client, default is %d\n", gMsgs ); | ||
67 | + printf( "\n" ); | ||
68 | +} | ||
69 | + | ||
70 | +void close_client( SP_TestClient * client ) | ||
71 | +{ | ||
72 | + if( 0 == client->mIsStop ) { | ||
73 | + client->mIsStop = 1; | ||
74 | + gClients--; | ||
75 | + } | ||
76 | +} | ||
77 | + | ||
78 | +void on_read( SP_TestClient * client, SP_TestEvent * event ) | ||
79 | +{ | ||
80 | + char buffer[ 4096 ] = { 0 }; | ||
81 | + int bytesTransferred = recv( (int)client->mFd, buffer, sizeof( buffer ), 0 ); | ||
82 | + | ||
83 | + if( bytesTransferred <= 0 ) { | ||
84 | + if( bytesTransferred < 0 ) { | ||
85 | + printf( "recv fail, errno %d\n", WSAGetLastError() ); | ||
86 | + gStat.mRecvFail++; | ||
87 | + } | ||
88 | + close_client( client ); | ||
89 | + return; | ||
90 | + } | ||
91 | + | ||
92 | + for( int i = 0; i < bytesTransferred; i++ ) { | ||
93 | + if( '\n' == buffer[i] ) client->mRecvMsgs++; | ||
94 | + } | ||
95 | + | ||
96 | + memset( &( event->mOverlapped ), 0, sizeof( OVERLAPPED ) ); | ||
97 | + event->mType = SP_TestEvent::eEventRecv; | ||
98 | + event->mWsaBuf.buf = NULL; | ||
99 | + event->mWsaBuf.len = 0; | ||
100 | + | ||
101 | + DWORD recvBytes = 0, flags = 0; | ||
102 | + if( SOCKET_ERROR == WSARecv( (SOCKET)client->mFd, &( event->mWsaBuf ), 1, | ||
103 | + &recvBytes, &flags, &( event->mOverlapped ), NULL ) ) { | ||
104 | + if( ERROR_IO_PENDING != WSAGetLastError() ) { | ||
105 | + gStat.mWSARecvFail++; | ||
106 | + printf( "WSARecv fail, errno %d\n", WSAGetLastError() ); | ||
107 | + close_client( client ); | ||
108 | + } | ||
109 | + } | ||
110 | +} | ||
111 | + | ||
112 | +void on_write( SP_TestClient * client, SP_TestEvent * event ) | ||
113 | +{ | ||
114 | + if( client->mSendMsgs < gMsgs ) { | ||
115 | + client->mSendMsgs++; | ||
116 | + | ||
117 | + char buffer[ 4096 ] = { 0 }; | ||
118 | + if( client->mSendMsgs >= gMsgs ) { | ||
119 | + snprintf( buffer, sizeof( buffer ), "quit\n" ); | ||
120 | + } else { | ||
121 | + snprintf( buffer, sizeof( buffer ), | ||
122 | + "mail #%d, It's good to see how people hire; " | ||
123 | + "that tells us how to market ourselves to them.\n", client->mSendMsgs ); | ||
124 | + } | ||
125 | + | ||
126 | + int bytesTransferred = send( (SOCKET)client->mFd, buffer, strlen( buffer ), 0 ); | ||
127 | + if( bytesTransferred <= 0 ) { | ||
128 | + if( bytesTransferred < 0 ) { | ||
129 | + printf( "send fail, errno %d\n", WSAGetLastError() ); | ||
130 | + gStat.mSendFail++; | ||
131 | + } | ||
132 | + close_client( client ); | ||
133 | + return; | ||
134 | + } | ||
135 | + | ||
136 | + DWORD sendBytes = 0; | ||
137 | + | ||
138 | + event->mType = SP_TestEvent::eEventSend; | ||
139 | + memset( &( event->mOverlapped ), 0, sizeof( OVERLAPPED ) ); | ||
140 | + event->mWsaBuf.buf = NULL; | ||
141 | + event->mWsaBuf.len = 0; | ||
142 | + | ||
143 | + if( SOCKET_ERROR == WSASend( (SOCKET)client->mFd, &( event->mWsaBuf ), 1, | ||
144 | + &sendBytes, 0, &( event->mOverlapped ), NULL ) ) { | ||
145 | + if( ERROR_IO_PENDING != WSAGetLastError() ) { | ||
146 | + gStat.mWSASendFail++; | ||
147 | + printf( "WSASend fail, errno %d\n", WSAGetLastError() ); | ||
148 | + close_client( client ); | ||
149 | + } | ||
150 | + } | ||
151 | + } else { | ||
152 | + // do nothing | ||
153 | + } | ||
154 | +} | ||
155 | + | ||
156 | +void eventLoop( HANDLE hIocp ) | ||
157 | +{ | ||
158 | + DWORD bytesTransferred = 0; | ||
159 | + SP_TestClient * client = NULL; | ||
160 | + SP_TestEvent * event = NULL; | ||
161 | + | ||
162 | + BOOL isSuccess = GetQueuedCompletionStatus( hIocp, &bytesTransferred, | ||
163 | + (DWORD*)&client, (OVERLAPPED**)&event, 100 ); | ||
164 | + DWORD lastError = WSAGetLastError(); | ||
165 | + | ||
166 | + if( ! isSuccess ) { | ||
167 | + if( NULL != client ) { | ||
168 | + gStat.mGQCSFail++; | ||
169 | + close_client( client ); | ||
170 | + } | ||
171 | + return; | ||
172 | + } | ||
173 | + | ||
174 | + if( SP_TestEvent::eEventRecv == event->mType ) { | ||
175 | + on_read( client, event ); | ||
176 | + return; | ||
177 | + } | ||
178 | + | ||
179 | + if( SP_TestEvent::eEventSend == event->mType ) { | ||
180 | + on_write( client, event ); | ||
181 | + return; | ||
182 | + } | ||
183 | +} | ||
184 | + | ||
185 | +int main( int argc, char * argv[] ) | ||
186 | +{ | ||
187 | + extern char *optarg ; | ||
188 | + int c ; | ||
189 | + | ||
190 | + while( ( c = getopt ( argc, argv, "h:p:c:m:v" )) != EOF ) { | ||
191 | + switch ( c ) { | ||
192 | + case 'h' : | ||
193 | + gHost = optarg; | ||
194 | + break; | ||
195 | + case 'p': | ||
196 | + gPort = atoi( optarg ); | ||
197 | + break; | ||
198 | + case 'c' : | ||
199 | + gClients = atoi ( optarg ); | ||
200 | + break; | ||
201 | + case 'm' : | ||
202 | + gMsgs = atoi( optarg ); | ||
203 | + break; | ||
204 | + case 'v' : | ||
205 | + case '?' : | ||
206 | + showUsage( argv[0] ); | ||
207 | + exit( 0 ); | ||
208 | + } | ||
209 | + } | ||
210 | + | ||
211 | +#ifdef SIGPIPE | ||
212 | + signal( SIGPIPE, SIG_IGN ); | ||
213 | +#endif | ||
214 | + | ||
215 | + WSADATA wsaData; | ||
216 | + | ||
217 | + int err = WSAStartup( MAKEWORD( 2, 0 ), &wsaData ); | ||
218 | + if ( err != 0 ) { | ||
219 | + printf( "Couldn't find a useable winsock.dll.\n" ); | ||
220 | + return -1; | ||
221 | + } | ||
222 | + | ||
223 | + HANDLE hIocp = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 ); | ||
224 | + if( NULL == hIocp ) { | ||
225 | + printf( "CreateIoCompletionPort failed, errno %d\n", WSAGetLastError() ); | ||
226 | + return -1; | ||
227 | + } | ||
228 | + | ||
229 | + SP_TestClient * clientList = (SP_TestClient*)calloc( gClients, sizeof( SP_TestClient ) ); | ||
230 | + | ||
231 | + struct sockaddr_in sin; | ||
232 | + memset( &sin, 0, sizeof(sin) ); | ||
233 | + sin.sin_family = AF_INET; | ||
234 | + sin.sin_addr.s_addr = inet_addr( gHost ); | ||
235 | + sin.sin_port = htons( gPort ); | ||
236 | + | ||
237 | + int totalClients = gClients, i = 0; | ||
238 | + | ||
239 | + printf( "Create %d connections to server, it will take some minutes to complete.\n", gClients ); | ||
240 | + for( i = 0; i < gClients; i++ ) { | ||
241 | + SP_TestClient * client = clientList + i; | ||
242 | + memset( client, 0, sizeof( SP_TestClient ) ); | ||
243 | + | ||
244 | + client->mFd = socket( AF_INET, SOCK_STREAM, 0 ); | ||
245 | + if( client->mFd < 0 ) { | ||
246 | + printf( "socket failed, errno %d, %s\n", errno, strerror( errno ) ); | ||
247 | + spwin32_pause_console(); | ||
248 | + return -1; | ||
249 | + } | ||
250 | + | ||
251 | + if( connect( client->mFd, (struct sockaddr *)&sin, sizeof(sin) ) != 0) { | ||
252 | + printf( "connect failed, errno %d, %s\n", errno, strerror( errno ) ); | ||
253 | + spwin32_pause_console(); | ||
254 | + return -1; | ||
255 | + } | ||
256 | + | ||
257 | + if( NULL == CreateIoCompletionPort( (HANDLE)client->mFd, hIocp, (DWORD)client, 0 ) ) { | ||
258 | + printf( "CreateIoCompletionPort failed, errno %d\n", WSAGetLastError() ); | ||
259 | + return -1; | ||
260 | + } | ||
261 | + | ||
262 | + if( 0 == ( i % 10 ) ) printf( "." ); | ||
263 | + } | ||
264 | + | ||
265 | + for( i = 0; i < gClients; i++ ) { | ||
266 | + SP_TestClient * client = clientList + i; | ||
267 | + on_read( client, &( client->mRecvEvent ) ); | ||
268 | + on_write( client, &( client->mSendEvent ) ); | ||
269 | + } | ||
270 | + | ||
271 | + printf( "\n" ); | ||
272 | + | ||
273 | + time( &gStartTime ); | ||
274 | + | ||
275 | + struct timeval startTime, stopTime; | ||
276 | + | ||
277 | + sp_gettimeofday( &startTime, NULL ); | ||
278 | + | ||
279 | + time_t lastInfoTime = time( NULL ); | ||
280 | + | ||
281 | + // start event loop until all clients are exit | ||
282 | + while( gClients > 0 ) { | ||
283 | + eventLoop( hIocp ); | ||
284 | + | ||
285 | + if( time( NULL ) - lastInfoTime > 5 ) { | ||
286 | + time( &lastInfoTime ); | ||
287 | + printf( "waiting for %d client(s) to exit\n", gClients ); | ||
288 | + } | ||
289 | + } | ||
290 | + | ||
291 | + sp_gettimeofday( &stopTime, NULL ); | ||
292 | + | ||
293 | + double totalTime = (double) ( 1000000 * ( stopTime.tv_sec - startTime.tv_sec ) | ||
294 | + + ( stopTime.tv_usec - startTime.tv_usec ) ) / 1000000; | ||
295 | + | ||
296 | + // show result | ||
297 | + printf( "\n\nTest result :\n" ); | ||
298 | + printf( "Clients : %d, Messages Per Client : %d\n", totalClients, gMsgs ); | ||
299 | + printf( "Failure : send %d, WSASend %d, recv %d, WSARecv %d, GQCS %d\n", | ||
300 | + gStat.mSendFail, gStat.mWSASendFail, gStat.mRecvFail, | ||
301 | + gStat.mWSARecvFail, gStat.mGQCSFail ); | ||
302 | + printf( "ExecTimes : %.6f seconds\n\n", totalTime ); | ||
303 | + | ||
304 | + printf( "client\tSend\tRecv\n" ); | ||
305 | + int totalSend = 0, totalRecv = 0; | ||
306 | + for( i = 0; i < totalClients; i++ ) { | ||
307 | + SP_TestClient * client = clientList + i; | ||
308 | + | ||
309 | + //printf( "client#%d : %d\t%d\n", i, client->mSendMsgs, client->mRecvMsgs ); | ||
310 | + | ||
311 | + totalSend += client->mSendMsgs; | ||
312 | + totalRecv += client->mRecvMsgs; | ||
313 | + | ||
314 | + if( INVALID_HANDLE_VALUE != (HANDLE)client->mFd ) { | ||
315 | + closesocket( client->mFd ); | ||
316 | + } | ||
317 | + } | ||
318 | + | ||
319 | + printf( "total : %d\t%d\n", totalSend, totalRecv ); | ||
320 | + printf( "average : %.0f/s\t%.0f/s\n", totalSend / totalTime, totalRecv / totalTime ); | ||
321 | + | ||
322 | + free( clientList ); | ||
323 | + | ||
324 | + CloseHandle( hIocp ); | ||
325 | + | ||
326 | + spwin32_pause_console(); | ||
327 | + | ||
328 | + return 0; | ||
329 | +} | ||
330 | + |
请
注册
或
登录
后发表评论