The most streamlined IOCP package, DELPHI XE8 directly compiled through. Winsock2.pas is the use of Delphi, I believe XE7 can also compile, or xe6,xe5 can also.
Winsock2.pas, I have seen countless versions of the version of the Winsock 2 API method parameters of the data types are actually different, the use of various people encapsulated Winsock2.pas source code should be adjusted accordingly,
Otherwise can not be compiled through, I think it is the most reliable use of Delphi official.
To be used in practical applications, it is also necessary to carry out "sticky packet processing".
I am under the Delphi XE8 test OK.
Unit Unit1;
Interface
Uses
Winsock2, Windows, Messages, sysutils, variants, Classes, Graphics, Controls, Forms,
Dialogs, Stdctrls, Extctrls;
Const
buf_size=1024;
Type
Single IO data structure
Lper_io_data = ^tper_io_data;
Tper_io_data = Packed record
overlapped:wsaoverlapped;
Databuf:wsabuf;
Buf:array [0..buf_size-1] of Ansichar;
Sendbytes:dword;
Recvbytes:dword;
End
Data structure of the handle
Lper_handle_data = ^tper_handle_data;
Tper_handle_data = Packed record
Socket:tsocket;
End
Tlistenthread = Class (TThread)
Private
Protected
Procedure Execute;override;
Public
Constructor Create;
End
TForm1 = Class (Tform)
Memo1:tmemo;
Procedure Formcreate (Sender:tobject);
Private
{Private declarations}
Public
{Public declarations}
End
Var
Form1:tform1;
Serversocket:tsocket;
Implementation
{$R *.DFM}
Worker threads
function Workthread (completionportid:pointer):D word; stdcall;
Var
Completionport:thandle;
Bytestransferred:dword;
Perhandledata:lper_handle_data;
Periodata:lper_io_data;
Flags:dword;
Recvbytes:dword;
Begin
completionport:= Thandle (Completionportid);
While True does
Begin
Gets the completion status of the queue on the completion port
GetQueuedCompletionStatus (Completionport, bytestransferred, Ulong_ptr (Perhandledata), POverlapped (PerIOData), INFINITE);
Determine whether the data is sent from the client or the server
If periodata.recvbytes = 0 Then
Begin
Periodata.recvbytes:= bytestransferred;
periodata.sendbytes:= 0;
End Else
periodata.sendbytes:= periodata.sendbytes + bytestransferred;
If periodata.recvbytes > Periodata.sendbytes Then
Begin
ZeroMemory (@ (periodata.overlapped), SizeOf (wsaoverlapped));
periodata.databuf.buf:= periodata.buf + periodata.sendbytes;
Periodata.databuf.len:= periodata.recvbytes-periodata.sendbytes;
It is unsafe to display the received data, and it is an example:)
Form1.Memo1.Lines.Add (String (periodata.buf));
End
Resetting data
periodata.recvbytes:= 0;
Periodata.databuf.len:= buf_size;
periodata.databuf.buf:= @PerIOData. buf;
Re-delivery
WSARecv (Perhandledata.socket, @ (PERIODATA.DATABUF), 1, recvbytes, Flags,
@ (periodata.overlapped), nil);
End
End
{Tworkthread}
Constructor Tlistenthread.create;
Begin
Inherited Create (False);
Freeonterminate:= True;
End
Procedure Tlistenthread.execute;
Var
Wsdata:twsadata;
Completionport:thandle;
Si:tsysteminfo;
Idx:integer;
Threadid:dword;
localaddr:sockaddr_in;
CLIENTADDR:SOCKADDR;
Clientsocket:tsocket;
Per_handle_data:lper_handle_data;
Per_io_data:lper_io_data;
Recvbytes:dword;
Flags:dword;
Begin
//Initialize Winsock
WSAStartup ($202, wsdata);
//Create completion Port
completionport:= CreateIoCompletionPort (invalid_ Handle_value, 0, 0, 0);
//number of worker threads created based on number of processors
GetSystemInfo (SI);
for IDX: = 1 to Si.dwnumberofprocessors do
//create worker threads, and pass the completion port handle to the thread
CreateThread (nil, 0, @WorkThread, Pointer (Completionport), 0, ThreadID);
//Create a listening socket
Serversocket:= WSASocket (Af_inet, Sock_stream, ipproto_tcp, nil, 0, wsa_flag_overlapped);
//Set parameters for Localaddr
localaddr.sin_family:= af_inet;//ipv4 family
Localaddr.sin_addr. S_addr:= inaddr_any;//here can not write inet_addr (' 127.0.0.1 '), otherwise will bind failed, not clear what is the reason;
localaddr.sin_port:= Htons (8000)//host to net short, host byte order to network byte order
//Bind the IP address of the machine, port, first set the LOCALADDR parameters before binding
Bind (ServerSocket, sockaddr (LOCALADDR), SizeOf (LOCALADDR));
//Start listening
Listen (ServerSocket, 5);
While not Terminated do
Begin
clientsocket:= wsaaccept (ServerSocket, @ClientAddr, nil, nil, 0);
Create a variable for the TPER_HANDLE_DATA structure save client socket
per_handle_data:= Lper_handle_data (GlobalAlloc (Gptr, SizeOf (Tper_handle_data)));
Per_handle_data. Socket:= Clientsocket;
Associating the completion port with the client socket
CreateIoCompletionPort (Clientsocket, Completionport, Ulong_ptr (Per_handle_data), 0);
Creating variables for Tper_io_data structures, associating WSARECV functions
per_io_data:= Lper_io_data (GlobalAlloc (Gptr, SizeOf (Tper_io_data)));
ZeroMemory (@PER_IO_DATA. Overlapped, SizeOf (wsaoverlapped));
Per_io_data. sendbytes:= 0;
Per_io_data. recvbytes:= 0;
Per_io_data. Databuf.len:= buf_size;
Per_io_data. Databuf.buf:= @PER_IO_DATA. Buf;
WSARecv (Clientsocket, @ per_io_data. DATABUF), 1, Recvbytes,
Flags, @ (per_io_data. Overlapped), nil);
End
End
Procedure Tform1.formcreate (Sender:tobject);
Begin
Creating a listener thread
Tlistenthread.create ();
End
End.
The most streamlined IOCP package