王朝网络
分享
 
 
 

Winsock完成端口模型-Delphi代码

王朝delphi·作者佚名  2006-01-09
宽屏版  字体: |||超大  

原文出处 《Windows网络编程技术》第8章 完成端口模型

由于原书附的是C代码,我把其翻译成Delphi代码。

其中winsock2.pas在delphi中不带,要另外下载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 client 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 = packed record

Socket: TSocket;

end;

procedure main;

implementation

function ServerWorkerThread(CompletionPortID: LPVOID): DWORD; stdcall; forward;

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

begin

printf('WSAStartup failed with error %d', Ret);

Exit;

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;

end;

// Determine how many processors are on the system.

GetSystemInfo(SystemInfo);

// Create worker threads based on the number of processors available on the

// system. Create two worker threads for each processor.

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;

end;

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;

end;

// Prepare socket for listening

if (Winsock.listen(Listen, 5) = SOCKET_ERROR) then

begin

printf('listen() failed with error %d', WSAGetLastError());

exit;

end

else

begin

printf('Server listen on port = %d ...', PORT);

end;

// 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;

end;

// 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());

exit;

end;

// Associate the accepted socket with the original completion port.

printf('Socket number %d connected', Accept);

PerHandleData.Socket := Accept;

if (CreateIoCompletionPort(Accept, CompletionPort, DWORD(PerHandleData), 0) = 0) then

begin

printf('CreateIoCompletionPort() failed with error %d', WSAGetLastError());

exit;

end;

// 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, sizeof(OVERLAPPED));

PerIoData.BytesSEND := 0;

PerIoData.BytesRECV := 0;

PerIoData.DataBuf.len := DATA_BUFSIZE;

PerIoData.DataBuf.buf := @PerIoData.Buffer;

Flags := 0;

if (WSARecv(Accept, @(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;

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;

// First check to see if an error has occured on the socket and if so

// then close the socket and cleanup the SOCKET_INFORMATION structure

// associated with the socket.

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());

exit;

end;

GlobalFree(DWORD(PerHandleData));

GlobalFree(DWORD(PerIoData));

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) then

begin

PerIoData.BytesRECV := BytesTransferred;

PerIoData.BytesSEND := 0;

end

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 requested,

// continue posting WSASend() calls until all received bytes are sent.

ZeroMemory(@(PerIoData.Overlapped), sizeof(OVERLAPPED));

PerIoData.DataBuf.buf := PerIoData.Buffer + PerIoData.BytesSEND;

PerIoData.DataBuf.len := PerIoData.BytesRECV - PerIoData.BytesSEND;

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 are no more bytes to send post another WSARecv() request.

Flags := 0;

ZeroMemory(@(PerIoData.Overlapped), sizeof(OVERLAPPED));

PerIoData.DataBuf.len := DATA_BUFSIZE;

PerIoData.DataBuf.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;

end.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有