正在显示
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 | + | ... | ... |
请
注册
或
登录
后发表评论