Winsock completes port model - Delphi code

xiaoxiao2021-03-06  39

The original article "Windows Network Programming Technology" Chapter 8 Completed Port Model

Since the original book is attached to C code, I translated it into a Delphi code.

Where winsock2.pas does not bring in Delphi, you have another download http://jungla.dit.upm.es/~bti/files/winsock2.pas

Program completionio;

{$ Apptype console}

Uses sysutils, Winsock2 in 'Winsock2.Pas', MAINS IN 'MAINS.PAS'

Begin main (); end.

// Module Name: iocmplt.cpp //// Description: //// This sample illustrates how to develop a simple echo server Winsock // application using the completeion port I / O model This // sample is implemented as a console. -style application and simply prints // messages when connections are established and removed from the server.// The application listens for TCP connections on port 5150 and accepts them // as they arrive. When this application receives data from a client, it / / Simply echos (this is why we call it an echo server) The Data Back In // It's Original Form Until The Close Closes The connection.//// 2005-2-5 // CPP Convert to Delphi PAS by johnson //

UNIT MAINS;

Interface

Uses Windows, Winsock2, Winsock, Sysutils;

Const port = 5150; data_bufsize = 8192;

type LPVOID = Pointer; LPPER_IO_OPERATION_DATA = ^ PER_IO_OPERATION_DATA; PER_IO_OPERATION_DATA = packed record Overlapped: OVERLAPPED; DataBuf: TWSABUF; Buffer: array [0..DATA_BUFSIZE] of CHAR; BytesSEND: DWORD; BytesRECV: DWORD; end;

LPPER_HANDLE_DATA = ^ per_handle_data; per_handle_data = packet: tsocket;

PROCEDURE main;

IMPLEMENTATION

Function ServerWorkerthRead (CompletionPortid: LPVOID): DWORD; stdcall;

Procedure Printf (FMT: String; Num: Integer); Begin Writeln (Format (FMT, [NUM]); END;

procedure main; var InternetAddr: SOCKADDR_IN; Listen: TSOCKET; Accept: TSOCKET; CompletionPort: THANDLE; SystemInfo: SYSTEM_INFO; PerHandleData: LPPER_HANDLE_DATA; PerIoData: LPPER_IO_OPERATION_DATA; i: Integer; RecvBytes: DWORD; Flags: DWORD; ThreadID: DWORD; wsaData: TWSADATA; RET: DWORD; ThreadHandle: Thandle; Begin Ret: = WSAStartup ($ 0202, WSADATA); IF (RET <> 0) THEN BEGINTF ('WSAStartup Failed with Error% D', RET); End;

// Setup an I / O completion port CompletionPort: = CreateIoCompletionPort (INVALID_HANDLE_VALUE, 0, 0, 0); if (CompletionPort = 0) then begin printf ( 'CreateIoCompletionPort failed with error:% d', GetLastError ());. Exit ;

// DETERMINE How Many Processors Are On The System.

GetSystemInfo (SystemInfo);

.

For i: = 0 to systemInfo.dwnumberofprocessors * 2 - 1 do begin

// Create a server worker thread and pass the completion port to the thread ThreadHandle: = CreateThread (nil, 0, @ServerWorkerThread, Pointer (CompletionPort), 0, ThreadID); if (ThreadHandle = 0) then begin printf ( 'CreateThread. () Failed with error% d ', getLastError ()); EXIT; END;

// Close The Thread Handle CloseHandle (ThreadHandle); END;

// Create a listening socket Listen: = WSASocket (AF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED); if (Listen = INVALID_SOCKET) then begin printf ( 'WSASocket () failed with error% d', WSAGetLastError ()); EXIT;

InternetAddr.sin_family: = AF_INET; InternetAddr.sin_addr.s_addr: = htonl (INADDR_ANY); InternetAddr.sin_port: = htons (PORT); if (bind (Listen, InternetAddr, sizeof (InternetAddr)) = SOCKET_ERROR) then begin printf ( ' Bind () failed with error% d ', wsagetlasterror ()); exit;

// Prepare Socket for Listening

IF (Winsock.Listen (Listen, 5) = Socket_ERROR) THEN BEGINTF ('listen () failed with error% d', wsagetlasterror ()); EXIT; ELSE BEGIN PRINTF ('Server Listen on Port =% D .. . ', Port);

// Accept connections and assign to the completion port while (TRUE) do begin Accept:. = WSAAccept (Listen, nil, nil, nil, 0); if (Accept = SOCKET_ERROR) then begin printf ( 'WSAAccept () failed with error % d ', wsagetlasterror ()); exit;

// Create a socket information structure to associate with the socket PerHandleData: = LPPER_HANDLE_DATA (GlobalAlloc (GPTR, sizeof (PER_HANDLE_DATA))); if (PerHandleData = nil) then begin printf ( 'GlobalAlloc () failed with error% d', WSAGetLastError ());

// Associate The Accepted Socket with The Original Completion Port.

Printf ('socket number% d connection ", accept); perhandaTa.socket: = accept;

IF (CreateiocompletionPort (Accept, Completionport, DWORD (Perhandata), 0) = 0) The begin Printf ('createioCompletionPort () failed with error% d', wsagetlasterror (); exit;

// Create Per I / O Socket Information Structure To Associate With the // Wsarecv Call Below.

PerIoData: = LPPER_IO_OPERATION_DATA (GlobalAlloc (GPTR, sizeof (PER_IO_OPERATION_DATA))); if (PerIoData = nil) then begin printf ( 'GlobalAlloc () failed with error% d', WSAGetLastError ()); exit; end; ZeroMemory (@PerIoData .Overlapped); periodata.bytessend: = 0; Periodata.bytesRecv: = 0; Periodata.Databuf.len: = DATA_BUFSIZE; Periodata.DATABUF.BUF: = @ periodata.buffer;

Flags: = 0; IF (Wsarecv (Accept, @ (Periodata.Database), 1, @recvbytes, @flags, @ (PERIODATA.OVERLAPPED), NIL) = SOCKET_ERROR) THEN BEGIN IF (Wsagetlasterror () " Begin Printf ('wsarecv () failed with error% d', wsagetlasterror ()); exit; end end;

END;

function ServerWorkerThread (CompletionPortID: LPVOID): DWORD; stdcall; var CompletionPort: THANDLE; BytesTransferred: DWORD; // Overlapped: POVERLAPPED; PerHandleData: LPPER_HANDLE_DATA; PerIoData: LPPER_IO_OPERATION_DATA; SendBytes, RecvBytes: DWORD; Flags: DWORD; begin CompletionPort: = THANDLE CompletionPortID;

Result: = 0;

While (True) Do Begin

if (GetQueuedCompletionStatus (CompletionPort, BytesTransferred, DWORD (PerHandleData), POverlapped (PerIoData), INFINITE) = False) then begin printf ( 'GetQueuedCompletionStatus failed with error% d', GetLastError ()); exit; end;

.

if (BytesTransferred = 0) then begin printf ( 'Closing socket% d /', PerHandleData.Socket); if (closesocket (PerHandleData.Socket) = SOCKET_ERROR) then begin printf ( 'closesocket () failed with error% d', WSAGetLastError ());

GlobalFree (DWORD (PerhandaTa)); GlobalFree (DWORDATA); Continue; End;

// Check to see if the BytesRECV field equals zero. If this is so, then // this means a WSARecv call just completed so update the BytesRECV field // with the BytesTransferred value from the completed WSARecv () call.

IF (Periodata.bytesRecv = 0) The begin Periodata.bytesRecv: = bytestransferred; periodata.bytessend: = 0; Else Begin Periodata.bytessend: = periodata.bytessend bytestransferred; end;

IF (Periodata.BytesRecv> Periodata.bytessend) THEN Begin

// Post Another Wsasend () Request. // Since Wsasend () IS NOT Gauranteed To send all of the bytes request, // Continue Posting wsasend () Calls UnTil All Received Bytes Are SENT.

ZeromeMory (@ (periodata.overlapped), sizeof (overlapped));

Periodata.DatabaseBuf.buf: = periodata.buffer periodata.bytessend; periodata.Databasesend;

if (WSASend (PerHandleData.Socket, @ (PerIoData.DataBuf), 1, @SendBytes, 0, @ (PerIoData.Overlapped), nil) = SOCKET_ERROR) then begin if (WSAGetLastError () <> ERROR_IO_PENDING) then begin printf ( ' Wsasend () failed with error% d ', wsagetlasterror ()); exit; end; end; end else begin periodata.bytesRecv: = 0; // Now That there is no moretes to send post another wsarecv () Request.

Flags: = 0; ZeromeMory (@ (periodata.overlapped), sizeof (overlapped);

Periodata.Database; = data_bufsize; periodata.databasef.buf: = @ periodata.buffer;

if (WSARecv (PerHandleData.Socket, @ (PerIoData.DataBuf), 1, @RecvBytes, @Flags, @ (PerIoData.Overlapped), nil) = SOCKET_ERROR) then begin if (WSAGetLastError () <> ERROR_IO_PENDING) then begin printf ( 'Wsarecv () failed with error% d', wsagetlasterror ()); EXIT; END; end; end; end;

End.

转载请注明原文地址:https://www.9cbs.com/read-59924.html

New Post(0)