日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Delphi-IOCP学习笔记三====工作线程和Listener

發布時間:2023/12/15 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Delphi-IOCP学习笔记三====工作线程和Listener 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

接第一次代碼繼續分析

usesJwaWinsock2, Windows, SysUtils;constDATA_BUFSIZE = 1024;IO_TYPE_Accept = 1;IO_TYPE_Recv = 2;type//(1):單IO數據結構LPVOID = Pointer;LPPER_IO_OPERATION_DATA = ^PER_IO_OPERATION_DATA ;PER_IO_OPERATION_DATA = packed recordOverlapped: OVERLAPPED;IO_TYPE: Cardinal;DataBuf: TWSABUF;Buffer: array [0..1024] of CHAR;end;

剛開始結存iocp的時候可能無法理解為什么要申明這樣一個結構。

解釋下,這個結構是GetQueuedCompletionStatus,PostQueuedCompletionStatus,WSARecv,WSASend,時需要用到一個POverlapped類型的參數。

也許還會有疑惑,為什么不直接使用系統自帶的類型呢?

POverlapped = ^TOverlapped;
_OVERLAPPED = record
? Internal: DWORD;
? InternalHigh: DWORD;
? Offset: DWORD;
? OffsetHigh: DWORD;
? hEvent: THandle;
end;

///我可以解釋下.是為了在PostQueuedCompletionStatus,WSARecv,WSASend盡可能多傳遞一下信息給GetQueuedCompletionStatus,所以一般都會擴展這一機構體

//再啰嗦下。定義的結構體,Overlapped: OVERLAPPED;必須放在第一個.你懂的。

//PostQueuedCompletionStatus,WSARecv,WSASend會觸發工作線程的GetQueuedCompletionStatus返回<上一筆記有提到>

?

?

?

?

?

下面片段是Listen過程

//下面循環進行循環獲取客戶端的請求。while (TRUE) dobegin//當客戶端有連接請求的時候,WSAAccept函數會新創建一個套接字cSocket。這個套接字就是和客戶端通信的時候使用的套接字。cSocket:= WSAAccept(sSocket, nil, nil, nil, 0);//判斷cSocket套接字創建是否成功,如果不成功則退出。if (cSocket= SOCKET_ERROR) thenbeginclosesocket(sSocket);exit;end;//將套接字、完成端口綁定在一起。// 最開始的時候沒有明白為什么還要調用一次createIoCompletionPort//// 后來經過google,和測試//// 是將新的套接字(socket)加入到iocp端口<綁定>// 這樣工作線程才能處理這個套接字(socket)的數據包//如果把下面注釋掉,WSARecv這個套接字時,GetQueuedCompletionStatus無法處理到收到的數據包 // 2013年4月19日 09:56:00 // 注意第三個參數也需要進行綁定, 否則在工作線程中GetQueuedCompletionStatus時completionKey會取不到cSocket值 lvPerIOPort := CreateIoCompletionPort(cSocket, lvIOPort, cSocket, 0);if (lvPerIOPort = 0) thenbeginExit;end;//初始化數據包PerIoData := LPPER_IO_OPERATION_DATA(GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA)));ZeroMemory(@PerIoData.Overlapped, sizeof(OVERLAPPED));//數據包中的IO類型:有連接請求PerIoData.IO_TYPE := IO_TYPE_Accept;//通知工作線程,有新的套接字連接<第三個參數>PostQueuedCompletionStatus(lvIOPort, 0, cSocket, POverlapped(PerIOData));end;

?

?

下面是IOCP工作線程

?

function ServerWorkerThread(pData:Pointer): Integer; stdcall; varCompletionPort:THANDLE;BytesTransferred:Cardinal;PerIoData:LPPER_IO_OPERATION_DATA;cSocket:TSocket;Flags:Cardinal;RecvBytes:Cardinal;lvResultStatus:BOOL;lvRet:Integer;beginCompletionPort:=THandle(pData);//得到創建線程是傳遞過來的IOCPwhile(TRUE) dobegin//工作者線程會停止到GetQueuedCompletionStatus函數處,直到接受到數據為止lvResultStatus := GetQueuedCompletionStatus(CompletionPort,BytesTransferred,cSocket,POverlapped(PerIoData), INFINITE); if (lvResultStatus = False) thenbegin//當客戶端連接斷開或者客戶端調用closesocket函數的時候,函數GetQueuedCompletionStatus會返回錯誤。如果我們加入心跳后,在這里就可以來判斷套接字是否依然在連接。if cSocket<>0 thenbeginclosesocket(cSocket);end;if PerIoData<>nil thenbeginGlobalFree(DWORD(PerIoData));end;continue;end;if PerIoData = nil thenbeginclosesocket(cSocket);Break;end else if (PerIoData<>nil) thenbeginshutdown(PerHandleData.Socket, 1);if PerIoData.IO_TYPE = IO_TYPE_Accept then //連接請求beginGlobalFree(DWORD(PerIoData));end else if PerIoData.IO_TYPE = IO_TYPE_Recv thenbegin 可以在這里處理數據…… GlobalFree(DWORD(PerIoData));end;/分配內存<可以加入內存池>PerIoData := LPPER_IO_OPERATION_DATA(GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA)));ZeroMemory(@PerIoData.Overlapped, sizeof(OVERLAPPED));Flags := 0;/進入投遞收取動作PerIoData.IO_TYPE := IO_TYPE_Recv;PerIoData.DataBuf.len:=DATA_BUFSIZE;ZeroMemory(@PerIoData.Buffer,sizeof(@PerIoData.Buffer));PerIoData.DataBuf.buf := @PerIoData.Buffer;/異步收取數據WSARecv(cSocket,@PerIoData.DataBuf,1,RecvBytes,Flags,@PerIoData^, nil);if (WSAGetLastError() <> ERROR_IO_PENDING) thenbeginclosesocket(cSocket);if PerIoData <> nil thenbeginGlobalFree(DWORD(PerIoData));end;Continue;end;end;end; end;

總結

以上是生活随笔為你收集整理的Delphi-IOCP学习笔记三====工作线程和Listener的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。