系列目录
第01篇 主线程与工作线程的分工
第02篇 Reactor模式
第03篇 一个服务器程序的架构介绍
第04篇 如何将socket设置为非阻塞模式
第05篇 如何编写高性能日志
第06篇 关于网络编程的一些实用技巧和细节
第07篇 开源一款即时通讯软件的源码
第08篇 高性能服务器架构设计总结1
第09篇 高性能服务器架构设计总结2
第10篇 高性能服务器架构设计总结3
第11篇 高性能服务器架构设计总结4
再看filezilla,一款ftp工具的服务器端,它采用的是Windows的WSAAsyncSelect模型(代码下载地址:https://github.com/baloonwj/filezilla):
1//Processes event notifications sent by the sockets or the layers
2 static LRESULT CALLBACK WindowProc(HWND hWnd,
3 UINT message,
4 WPARAM wParam,
5 LPARAM lParam)
6 {
7 if (message>=WM_SOCKETEX_NOTIFY)
8 {
9 //Verify parameters
10 ASSERT(hWnd);
11 CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)
12 GetWindowLongPtr(hWnd, GWLP_USERDATA);
13 ASSERT(pWnd);
14 if (!pWnd)
15 return 0;
16 //Index is within socket storage
17 if (message < static_cast<UINT>(WM_SOCKETEX_NOTIFY+pWnd->m_nWindowDataSize))
18 {
19 //Lookup socket and verify if it's valid
20 CAsyncSocketEx *pSocket=pWnd->m_pAsyncSocketExWindowData[message - WM_SOCKETEX_NOTIFY].m_pSocket;
21 SOCKET hSocket = wParam;
22 if (!pSocket)
23 return 0;
24 if (hSocket == INVALID_SOCKET)
25 return 0;
26 if (pSocket->m_SocketData.hSocket != hSocket)
27 return 0;
28
29 int nEvent = lParam & 0xFFFF;
30 int nErrorCode = lParam >> 16;
31
32 //Dispatch notification
33 if (!pSocket->m_pFirstLayer) {
34 //Dispatch to CAsyncSocketEx instance
35 switch (nEvent)
36 {
37 case FD_READ:
38#ifndef NOSOCKETSTATES
39 if (pSocket->GetState() == connecting && !nErrorCode)
40 {
41 pSocket->m_nPendingEvents |= FD_READ;
42 break;
43 }
44 else if (pSocket->GetState() == attached)
45 pSocket->SetState(connected);
46 if (pSocket->GetState() != connected)
47 break;
48
49 // Ignore further FD_READ events after FD_CLOSE has been received
50 if (pSocket->m_SocketData.onCloseCalled)
51 break;
52#endif //NOSOCKETSTATES
53
54#ifndef NOSOCKETSTATES
55 if (nErrorCode)
56 pSocket->SetState(aborted);
57#endif //NOSOCKETSTATES
58 if (pSocket->m_lEvent & FD_READ) {
59 pSocket->OnReceive(nErrorCode);
60 }
61 break;
62 case FD_FORCEREAD: //Forceread does not check if there's data waiting
63#ifndef NOSOCKETSTATES
64 if (pSocket->GetState() == connecting && !nErrorCode)
65 {
66 pSocket->m_nPendingEvents |= FD_FORCEREAD;
67 break;
68 }
69 else if (pSocket->GetState() == attached)
70 pSocket->SetState(connected);
71 if (pSocket->GetState() != connected)
72 break;
73#endif //NOSOCKETSTATES
74 if (pSocket->m_lEvent & FD_READ)
75 {
76#ifndef NOSOCKETSTATES
77 if (nErrorCode)
78 pSocket->SetState(aborted);
79#endif //NOSOCKETSTATES
80 pSocket->OnReceive(nErrorCode);
81 }
82 break;
83 case FD_WRITE:
84#ifndef NOSOCKETSTATES
85 if (pSocket->GetState() == connecting && !nErrorCode)
86 {
87 pSocket->m_nPendingEvents |= FD_WRITE;
88 break;
89 }
90 else if (pSocket->GetState() == attached && !nErrorCode)
91 pSocket->SetState(connected);
92 if (pSocket->GetState() != connected)
93 break;
94#endif //NOSOCKETSTATES
95 if (pSocket->m_lEvent & FD_WRITE)
96 {
97#ifndef NOSOCKETSTATES
98 if (nErrorCode)
99 pSocket->SetState(aborted);
100#endif //NOSOCKETSTATES
101 pSocket->OnSend(nErrorCode);
102 }
103 break;
104 case FD_CONNECT:
105#ifndef NOSOCKETSTATES
106 if (pSocket->GetState() == connecting)
107 {
108 if (nErrorCode && pSocket->m_SocketData.nextAddr)
109 {
110 if (pSocket->TryNextProtocol())
111 break;
112 }
113 pSocket->SetState(connected);
114 }
115 else if (pSocket->GetState() == attached && !nErrorCode)
116 pSocket->SetState(connected);
117#endif //NOSOCKETSTATES
118 if (pSocket->m_lEvent & FD_CONNECT)
119 pSocket->OnConnect(nErrorCode);
120#ifndef NOSOCKETSTATES
121 if (!nErrorCode)
122 {
123 if ((pSocket->m_nPendingEvents&FD_READ) &&
124 pSocket->GetState() == connected)
125 pSocket->OnReceive(0);
126 if ((pSocket->m_nPendingEvents&FD_FORCEREAD) &&
127 pSocket->GetState() == connected)
128 pSocket->OnReceive(0);
129 if ((pSocket->m_nPendingEvents&FD_WRITE) &&
130 pSocket->GetState() == connected)
131 pSocket->OnSend(0);
132 }
133 pSocket->m_nPendingEvents = 0;
134#endif
135 break;
136 case FD_ACCEPT:
137#ifndef NOSOCKETSTATES
138 if (pSocket->GetState() != listening &&
139 pSocket->GetState() != attached)
140 break;
141#endif //NOSOCKETSTATES
142 if (pSocket->m_lEvent & FD_ACCEPT)
143 pSocket->OnAccept(nErrorCode);
144 break;
145 case FD_CLOSE:
146#ifndef NOSOCKETSTATES
147 if (pSocket->GetState() != connected &&
148 pSocket->GetState() != attached)
149 break;
150
151 // If there are still bytes left to read,
152 // call OnReceive instead of
153 // OnClose and trigger a new OnClose
154 DWORD nBytes = 0;
155 if (!nErrorCode && pSocket->IOCtl(FIONREAD, &nBytes))
156 {
157 if (nBytes > 0)
158 {
159 // Just repeat message.
160 pSocket->ResendCloseNotify();
161 pSocket->m_SocketData.onCloseCalled = true;
162 pSocket->OnReceive(WSAESHUTDOWN);
163 break;
164 }
165 }
166
167 pSocket->SetState(nErrorCode ? aborted : closed);
168#endif //NOSOCKETSTATES
169 pSocket->OnClose(nErrorCode);
170 break;
171 }
172 }
173 else //Dispatch notification to the lowest layer
174 {
175 if (nEvent == FD_READ)
176 {
177 // Ignore further FD_READ events after FD_CLOSE has been received
178 if (pSocket->m_SocketData.onCloseCalled)
179 return 0;
180
181 DWORD nBytes;
182 if (!pSocket->IOCtl(FIONREAD, &nBytes))
183 nErrorCode = WSAGetLastError();
184 if (pSocket->m_pLastLayer)
185 pSocket->m_pLastLayer->CallEvent(nEvent, nErrorCode);
186 }
187 else if (nEvent == FD_CLOSE)
188 {
189 // If there are still bytes left to read,
190 // call OnReceive instead of
191 // OnClose and trigger a new OnClose
192 DWORD nBytes = 0;
193 if (!nErrorCode && pSocket->IOCtl(FIONREAD, &nBytes))
194 {
195 if (nBytes > 0)
196 {
197 // Just repeat message.
198 pSocket->ResendCloseNotify();
199 if (pSocket->m_pLastLayer)
200 pSocket->m_pLastLayer->CallEvent(FD_READ, 0);
201 return 0;
202 }
203 }
204 pSocket->m_SocketData.onCloseCalled = true;
205 if (pSocket->m_pLastLayer)
206 pSocket->m_pLastLayer->CallEvent(nEvent, nErrorCode);
207 }
208 else if (pSocket->m_pLastLayer)
209 pSocket->m_pLastLayer->CallEvent(nEvent, nErrorCode);
210 }
211 }
212 return 0;
213 }
214 else if (message == WM_USER) //Notification event sent by a layer
215 {
216 //Verify parameters, lookup socket and notification message
217 //Verify parameters
218 ASSERT(hWnd);
219 CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)
220 GetWindowLongPtr(hWnd, GWLP_USERDATA);
221 ASSERT(pWnd);
222 if (!pWnd)
223 return 0;
224 //Index is within socket storage
225 if (wParam >= static_cast<UINT>(pWnd->m_nWindowDataSize))
226 {
227 return 0;
228 }
229
230 CAsyncSocketEx *pSocket = pWnd->m_pAsyncSocketExWindowData[wParam].m_pSocket;
231 CAsyncSocketExLayer::t_LayerNotifyMsg *pMsg = (CAsyncSocketExLayer::t_LayerNotifyMsg *)lParam;
232 if (!pMsg || !pSocket || pSocket->m_SocketData.hSocket != pMsg->hSocket)
233 {
234 delete pMsg;
235 return 0;
236 }
237 int nEvent=pMsg->lEvent&0xFFFF;
238 int nErrorCode=pMsg->lEvent>>16;
239
240 //Dispatch to layer
241 if (pMsg->pLayer)
242 pMsg->pLayer->CallEvent(nEvent, nErrorCode);
243 else
244 {
245 //Dispatch to CAsyncSocketEx instance
246 switch (nEvent)
247 {
248 case FD_READ:
249#ifndef NOSOCKETSTATES
250 if (pSocket->GetState() == connecting && !nErrorCode)
251 {
252 pSocket->m_nPendingEvents |= FD_READ;
253 break;
254 }
255 else if (pSocket->GetState() == attached && !nErrorCode)
256 pSocket->SetState(connected);
257 if (pSocket->GetState() != connected)
258 break;
259#endif //NOSOCKETSTATES
260 if (pSocket->m_lEvent & FD_READ)
261 {
262#ifndef NOSOCKETSTATES
263 if (nErrorCode)
264 pSocket->SetState(aborted);
265#endif //NOSOCKETSTATES
266 pSocket->OnReceive(nErrorCode);
267 }
268 break;
269 //Forceread does not check if there's data waiting
270 case FD_FORCEREAD:
271#ifndef NOSOCKETSTATES
272 if (pSocket->GetState() == connecting && !nErrorCode)
273 {
274 pSocket->m_nPendingEvents |= FD_FORCEREAD;
275 break;
276 }
277 else if (pSocket->GetState() == attached && !nErrorCode)
278 pSocket->SetState(connected);
279 if (pSocket->GetState() != connected)
280 break;
281#endif //NOSOCKETSTATES
282 if (pSocket->m_lEvent & FD_READ)
283 {
284#ifndef NOSOCKETSTATES
285 if (nErrorCode)
286 pSocket->SetState(aborted);
287#endif //NOSOCKETSTATES
288 pSocket->OnReceive(nErrorCode);
289 }
290 break;
291 case FD_WRITE:
292#ifndef NOSOCKETSTATES
293 if (pSocket->GetState() == connecting && !nErrorCode)
294 {
295 pSocket->m_nPendingEvents |= FD_WRITE;
296 break;
297 }
298 else if (pSocket->GetState() == attached && !nErrorCode)
299 pSocket->SetState(connected);
300 if (pSocket->GetState() != connected)
301 break;
302#endif //NOSOCKETSTATES
303 if (pSocket->m_lEvent & FD_WRITE)
304 {
305#ifndef NOSOCKETSTATES
306 if (nErrorCode)
307 pSocket->SetState(aborted);
308#endif //NOSOCKETSTATES
309 pSocket->OnSend(nErrorCode);
310 }
311 break;
312 case FD_CONNECT:
313#ifndef NOSOCKETSTATES
314 if (pSocket->GetState() == connecting)
315 pSocket->SetState(connected);
316 else if (pSocket->GetState() == attached && !nErrorCode)
317 pSocket->SetState(connected);
318#endif //NOSOCKETSTATES
319 if (pSocket->m_lEvent & FD_CONNECT)
320 pSocket->OnConnect(nErrorCode);
321#ifndef NOSOCKETSTATES
322 if (!nErrorCode)
323 {
324 if (((pSocket->m_nPendingEvents&FD_READ) &&
325 pSocket->GetState() == connected) &&
326 (pSocket->m_lEvent & FD_READ))
327 pSocket->OnReceive(0);
328 if (((pSocket->m_nPendingEvents&FD_FORCEREAD) &&
329 pSocket->GetState() == connected) &&
330 (pSocket->m_lEvent & FD_READ))
331 pSocket->OnReceive(0);
332 if (((pSocket->m_nPendingEvents&FD_WRITE) &&
333 pSocket->GetState() == connected) &&
334 (pSocket->m_lEvent & FD_WRITE))
335 pSocket->OnSend(0);
336 }
337 pSocket->m_nPendingEvents = 0;
338#endif //NOSOCKETSTATES
339 break;
340 case FD_ACCEPT:
341#ifndef NOSOCKETSTATES
342 if ((pSocket->GetState() == listening || pSocket->GetState() == attached) && (pSocket->m_lEvent & FD_ACCEPT))
343#endif //NOSOCKETSTATES
344 {
345 pSocket->OnAccept(nErrorCode);
346 }
347 break;
348 case FD_CLOSE:
349#ifndef NOSOCKETSTATES
350 if ((pSocket->GetState() == connected ||
351 pSocket->GetState() == attached) &&
352 (pSocket->m_lEvent & FD_CLOSE))
353 {
354 pSocket->SetState(nErrorCode?aborted:closed);
355#else
356 {
357#endif //NOSOCKETSTATES
358 pSocket->OnClose(nErrorCode);
359 }
360 break;
361 }
362 }
363 delete pMsg;
364 return 0;
365 }
366 else if (message == WM_USER+1)
367 {
368 // WSAAsyncGetHostByName reply
369
370 // Verify parameters
371 ASSERT(hWnd);
372 CAsyncSocketExHelperWindow *pWnd = (CAsyncSocketExHelperWindow *)
373 GetWindowLongPtr(hWnd, GWLP_USERDATA);
374 ASSERT(pWnd);
375 if (!pWnd)
376 return 0;
377
378 CAsyncSocketEx *pSocket = NULL;
379 for (int i = 0; i < pWnd->m_nWindowDataSize; ++i) {
380 pSocket = pWnd->m_pAsyncSocketExWindowData[i].m_pSocket;
381 if (pSocket && pSocket->m_hAsyncGetHostByNameHandle &&
382 pSocket->m_hAsyncGetHostByNameHandle == (HANDLE)wParam &&
383 pSocket->m_pAsyncGetHostByNameBuffer)
384 break;
385 }
386 if (!pSocket || !pSocket->m_pAsyncGetHostByNameBuffer)
387 return 0;
388
389 int nErrorCode = lParam >> 16;
390 if (nErrorCode) {
391 pSocket->OnConnect(nErrorCode);
392 return 0;
393 }
394
395 SOCKADDR_IN sockAddr{};
396 sockAddr.sin_family = AF_INET;
397 sockAddr.sin_addr.s_addr = ((LPIN_ADDR)((LPHOSTENT)pSocket->m_pAsyncGetHostByNameBuffer)->h_addr)->s_addr;
398
399 sockAddr.sin_port = htons(pSocket->m_nAsyncGetHostByNamePort);
400
401 BOOL res = pSocket->Connect((SOCKADDR*)&sockAddr, sizeof(sockAddr));
402 delete [] pSocket->m_pAsyncGetHostByNameBuffer;
403 pSocket->m_pAsyncGetHostByNameBuffer = 0;
404 pSocket->m_hAsyncGetHostByNameHandle = 0;
405
406 if (!res)
407 if (GetLastError() != WSAEWOULDBLOCK)
408 pSocket->OnConnect(GetLastError());
409 return 0;
410 }
411 else if (message == WM_USER + 2)
412 {
413 //Verify parameters, lookup socket and notification message
414 //Verify parameters
415 if (!hWnd)
416 return 0;
417
418 CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)
419 GetWindowLongPtr(hWnd, GWLP_USERDATA);
420 if (!pWnd)
421 return 0;
422
423 if (wParam >= static_cast<UINT>(pWnd->m_nWindowDataSize)) //Index is within socket storage
424 return 0;
425
426 CAsyncSocketEx *pSocket = pWnd->m_pAsyncSocketExWindowData[wParam].m_pSocket;
427 if (!pSocket)
428 return 0;
429
430 // Process pending callbacks
431 std::list<t_callbackMsg> tmp;
432 tmp.swap(pSocket->m_pendingCallbacks);
433 pSocket->OnLayerCallback(tmp);
434
435 for (auto & cb : tmp) {
436 delete [] cb.str;
437 }
438 }
439 else if (message == WM_TIMER)
440 {
441 if (wParam != 1)
442 return 0;
443
444 ASSERT(hWnd);
445 CAsyncSocketExHelperWindow *pWnd=(CAsyncSocketExHelperWindow *)
446 GetWindowLongPtr(hWnd, GWLP_USERDATA);
447 ASSERT(pWnd && pWnd->m_pThreadData);
448 if (!pWnd || !pWnd->m_pThreadData)
449 return 0;
450
451 if (pWnd->m_pThreadData->layerCloseNotify.empty())
452 {
453 KillTimer(hWnd, 1);
454 return 0;
455 }
456 CAsyncSocketEx* socket = pWnd->m_pThreadData->layerCloseNotify.front();
457 pWnd->m_pThreadData->layerCloseNotify.pop_front();
458 if (pWnd->m_pThreadData->layerCloseNotify.empty())
459 KillTimer(hWnd, 1);
460
461 if (socket)
462 PostMessage(hWnd,
463 socket->m_SocketData.nSocketIndex + WM_SOCKETEX_NOTIFY,
464 socket->m_SocketData.hSocket,
465 FD_CLOSE);
466 return 0;
467 }
468 return DefWindowProc(hWnd, message, wParam, lParam);
469 }
关于单个服务程序的框架,我已经介绍完了,如果你能完全理解我要表达的意思,我相信你也能构建出一套高性能服务程序来。
系列目录
第01篇 主线程与工作线程的分工
第02篇 Reactor模式
第03篇 一个服务器程序的架构介绍
第04篇 如何将socket设置为非阻塞模式
第05篇 如何编写高性能日志
第06篇 关于网络编程的一些实用技巧和细节
第07篇 开源一款即时通讯软件的源码
第08篇 高性能服务器架构设计总结1
第09篇 高性能服务器架构设计总结2
第10篇 高性能服务器架构设计总结3
第11篇 高性能服务器架构设计总结4