onlyou13

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  1 unit Unit1;  
  2   
  3 interface  
  4   
  5 uses  
  6   WinSock2, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  
  7   Dialogs, StdCtrls, ExtCtrls;  
  8   
  9 type  
 10   //单IO数据结构  
 11   LPER_IO_OPERATION_DATA = ^TPER_IO_OPERATION_DATA;  
 12   TPER_IO_OPERATION_DATA = packed record  
 13     Overlapped: WSAOverlapped;  
 14     DataBuf: WSABuf;  
 15     Buff: array [0..10] of Char;  
 16     BytesSend: DWORD;  
 17     BytesRecv: DWORD;  
 18   end;  
 19   
 20   //单句柄数据结构  
 21   LPER_HANDLE_DATA = ^TPER_HANDLE_DATA;  
 22   TPER_HANDLE_DATA = packed record  
 23     Socket: TSocket;  
 24   end;  
 25   
 26   TListenThread = class(TThread)  
 27   private  
 28   protected  
 29     procedure Execute;override;  
 30   public  
 31     constructor Create;  
 32   end;  
 33   
 34   TForm1 = class(TForm)  
 35     Memo1: TMemo;  
 36     Button1: TButton;  
 37     procedure FormCreate(Sender: TObject);  
 38   private  
 39     { Private declarations }  
 40   public  
 41     { Public declarations }  
 42   end;  
 43   
 44 var  
 45   Form1: TForm1;  
 46   ServerSocket: TSocket;  
 47   
 48 implementation  
 49   
 50 {$R *.dfm}  
 51   
 52 //工作者线程  
 53 function WorkThread(CompletionPortID: Pointer):DWORD; stdcall;  
 54 var  
 55   CompletionPort: THandle;  
 56   BytesTransferred: DWORD;  
 57   PerHandleData: LPER_HANDLE_DATA;  
 58   PerIOData: LPER_IO_OPERATION_DATA;  
 59   Flags: DWORD;  
 60   RecvBytes: DWORD;  
 61 begin  
 62   CompletionPort:= THandle(CompletionPortID);  
 63   
 64   while True do  
 65   begin  
 66     //获取完成端口上的队列的完成状态  
 67     GetQueuedCompletionStatus(CompletionPort, BytesTransferred, DWORD(PerHandleData),  
 68       POverlapped(PerIOData), INFINITE);  
 69   
 70     //判断是客户端发来的数据还是服务端发出的数据  
 71     if PerIOData.BytesRecv = 0 then  
 72     begin  
 73       PerIOData.BytesRecv:= BytesTransferred;  
 74       PerIOData.BytesSend:= 0;  
 75     end else  
 76       PerIOData.BytesSend:= PerIOData.BytesSend + BytesTransferred;  
 77   
 78     if PerIOData.BytesRecv > PerIOData.BytesSend then  
 79     begin  
 80       ZeroMemory(@(PerIOData.Overlapped), SizeOf(WSAOverlapped));  
 81       PerIOData.DataBuf.buf:= PerIOData.Buff + PerIOData.BytesSend;  
 82       PerIOData.DataBuf.len:= PerIOData.BytesRecv - PerIOData.BytesSend;  
 83   
 84       //显示收到的数据,这样做是不安全的,示例而已 :)  
 85       Form1.Memo1.Lines.Add(PerIOData.Buff);  
 86     end;  
 87   
 88     //重置数据  
 89     PerIOData.BytesRecv:= 0;  
 90     PerIOData.DataBuf.len:= 22;  
 91     PerIOData.DataBuf.buf:= @PerIOData.Buff;  
 92   
 93     //再次投递  
 94     WSARecv(PerHandleData.Socket, @(PerIOData.DataBuf), 1, RecvBytes, Flags,  
 95       @(PerIOData.Overlapped), nil);  
 96   end;  
 97 end;  
 98   
 99 { TWorkThread }  
100   
101 constructor TListenThread.Create;  
102 begin  
103   inherited Create(False);  
104   FreeOnTerminate:= True;  
105 end;  
106   
107 procedure TListenThread.Execute;  
108 var  
109   WSData: TWSAData;  
110   CompletionPort: THandle;  
111   lpSystemInfo: TSystemInfo;  
112   Idx: Integer;  
113   ThreadID: DWORD;  
114   LocalAddr: TSockaddr;  
115   ClientAddr: TSockaddr;  
116   ClientSocket: TSocket;  
117   
118   PER_HANDLE_DATA: LPER_HANDLE_DATA;  
119   PER_IO_OPERATION_DATA: LPER_IO_OPERATION_DATA;  
120   
121   RecvBytes: DWORD;  
122   Flags: DWORD;  
123 begin  
124   inherited;  
125   
126   //初始化Winsock  
127   WSAStartUp($202, WSData);  
128   //创建完成端口  
129   CompletionPort:= CreateIOCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);  
130   //根据处理器数量创建工作者线程的数量(网上流传的说法是线程数量=cpu数量*2+2)  
131   GetSystemInfo(lpSystemInfo);  
132   for Idx := 1 to lpSystemInfo.dwNumberOfProcessors *2 + 2 do  
133     //创建工作者线程,并将完成端口句柄传递给线程  
134     CreateThread(nil, 0, @WorkThread, Pointer(CompletionPort), 0, ThreadID);  
135   //创建监听套接字  
136   ServerSocket:= WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nil, 0, WSA_FLAG_OVERLAPPED);  
137   //设置LocalAddr的参数  
138   LocalAddr.sin_family:= AF_INET;   //IPV4族  
139   LocalAddr.sin_addr.S_addr:= INADDR_ANY;//这里不能写Inet_addr('127.0.0.1'),否则会绑定失败,不清楚原因是什么;  
140   LocalAddr.sin_port:= Htons(1077); //Host To Net Short,主机字节顺序转为网络字节顺序  
141   //绑定本机IP地址、端口,绑定之前先设置好LocalAddr的参数  
142   Bind(ServerSocket, @LocalAddr, SizeOf(LocalAddr));  
143   //开始监听  
144   Listen(ServerSocket, 5);  
145   
146   while not Terminated do  
147   begin  
148     ClientSocket:= WSAAccept(ServerSocket, ClientAddr, nil, nil, 0);  
149     //创建TPER_HANDLE_DATA结构的变量保存客户端Socket  
150     PER_HANDLE_DATA:= LPER_HANDLE_DATA(GlobalAlloc(GPTR, SizeOf(TPER_HANDLE_DATA)));  
151     PER_HANDLE_DATA.Socket:= ClientSocket;  
152     //把完成端口和客户端套接字关联起来  
153     CreateIOCompletionPort(ClientSocket, CompletionPort, DWORD(PER_HANDLE_DATA), 0);  
154     //创建TPER_IO_OPERATION_DATA结构的变量,关联WSARecv函数  
155     PER_IO_OPERATION_DATA:= LPER_IO_OPERATION_DATA(GlobalAlloc(GPTR, SizeOf(TPER_IO_OPERATION_DATA)));  
156     ZeroMemory(@PER_IO_OPERATION_DATA.Overlapped, SizeOf(WSAOverlapped));  
157     PER_IO_OPERATION_DATA.BytesSend:= 0;  
158     PER_IO_OPERATION_DATA.BytesRecv:= 0;  
159     PER_IO_OPERATION_DATA.DataBuf.len:= 22;  
160     PER_IO_OPERATION_DATA.DataBuf.buf:= @PER_IO_OPERATION_DATA.Buff;  
161   
162     WSARecv(ClientSocket, @(PER_IO_OPERATION_DATA.DataBuf), 1, RecvBytes,  
163       Flags, @(PER_IO_OPERATION_DATA.Overlapped), nil);  
164   end;  
165 end;  
166   
167   
168 procedure TForm1.FormCreate(Sender: TObject);  
169 begin  
170   //创建监听线程  
171   TListenThread.Create();  
172 end;  
173   
174   
175 end.  

该代码仅仅是练习IOCP的函数使用和大体的实现步骤,里面很多细节并不是唯一的方法,例如单IO数据结构和单句柄数据结构的定义等等。

 

本文转载自http://blog.csdn.net/dropme/article/details/4562171

posted on 2013-11-14 20:45  onlyou13  阅读(170)  评论(0编辑  收藏  举报