Winsock完成端口模型-Delphi代码
原文出处 《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.
http://www.cnblogs.com/qiubole/archive/2006/04/06/368296.html
Winsock完成端口模型-Delphi代码的更多相关文章
- winsock编程IOCP模型实现代码
winsock编程IOCP模型实现代码 话不多说,上代码.借鉴<windows核心编程>部分源码和CSDN小猪部分代码. stdafx.h依赖头文件: #include <iostr ...
- WinSock 完成端口模型
之前写了关于Winsock的重叠IO模型,按理来说重叠IO模型与之前的模型相比,它的socket即是非阻塞的,也是异步的,它基本上性能非常高,但是它主要的缺点在于,即使我们使用历程来处理完成通知,但是 ...
- winsock编程WSAAsyncSelect模型
winsock编程WSAAsyncSelect模型 WSAAsyncSelect模型也称异步选择模型,其核心函数是WSAAsyncSelect.它可以用来在一个socket上接收以windows消息为 ...
- winsock编程select模型
winsock编程select模型 网络服务端连接数量过多时,为每一个连接申请一个线程会让机器性能急剧下降(大多说是因为线程在用户态和内核态之间切换会占用大量的CPU时间片).为了解决多线程带来的性能 ...
- winsock I/O模型的分析
几种winsock I/O模型的分析 套接字是通信的基础,是支持网络协议数据通信的基本接口.Winsocket 提供了一些有趣的I/O模型,有助于应用程序通过一种“异步”方式,一次对一个或者多个套接字 ...
- winsock的io模型(终极篇)
最近在看服务器框架的搭建,看了不少,都是零零碎碎的,觉得看的差不多了,可以写点最后的总结了,然后,竟然发现了这篇文章,总结做的特别好,肯定比我总结写要好多了,所以我也就不写了,直接转吧...... 套 ...
- WinSock 重叠IO模型
title: WinSock 重叠IO模型 tags: [WinSock 模型, 网络编程, 重叠IO模型] date: 2018-06-29 20:26:13 categories: Windows ...
- EF自动生成的模型edmx代码分析
edmx代码分析 本文分析Entity Framework从数据库自动生成的模型文件代码(扩展名为edmx). 1. 概述 本文使用的数据库结构尽量简单,只有2个表,一个用户表和一个分公司表(相当于部 ...
- Delphi代码中嵌入ASM代码
前言 Delphi作为一个快速高效的开发平台,使用的人越来越多,但熟悉在Delphi代码中嵌入ASM代码的程序员我想不多,因为这方面的资料太少了,另一方面,它还需要有基本的汇编语言知识,关於汇编语言的 ...
随机推荐
- 如何查看 Apache 的版本
查看 Apache 服务器版本的命令行为: httpd -v 或者 apachectl -v 例如:用 Xshell 连接到服务器后,输入:httpd -v 或者:apachectl -v 返回: S ...
- Azure IaaS for IT Pros Online Event 总结
微软一个为期4天的一个有关于Azure的介绍,主要总结了些Azure现有的技术以及将会推出东西 主题链接 http://channel9.msdn.com/Events/Microsoft-Azure ...
- C# 命名参数【转】
命名参数(Named Arguments)就是说在调用函数时可以通过指定参数名称的方式来调用参数.它最大的好处就是方便调用参数时按调用者的需要来排列顺序,而不必死守函数声明时的顺序(相对于“位置参数” ...
- 获得当前时间的PRO
1.没有参数的存储过程 create or replace procedure get_timeas cur_time varchar2(10);begin select to_char(sy ...
- Rac & DG
Rac环境: RAC版本异同:[10R2,11R1(和10类似)],11R2,12c: 目录: 10.2的ASM需要单独的目录(oracle home):rdbms home,asm home, cr ...
- 4-2.矩阵乘法的Strassen算法详解
题目描述 请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法. 思路分析 根据wikipedia上的介绍:两个矩阵的乘法仅当第一个矩阵B的列数和另一个矩阵A的行数相等时才能定义.如A是m×n矩阵和B ...
- Swift学习:闭包(Closures)
/* 闭包(Closures)* 闭包是自包含的功能代码块,可以在代码中使用或者用来作为参数传值.* 在Swift中的闭包与C.OC中的blocks和其它编程语言(如Python)中的lambdas类 ...
- 键盘样式风格有关设置-iOS开发
一.键盘风格 UIKit框架支持8种风格键盘. typedef enum { UIKeyboardTypeDefault, // 默认键盘:支持所有字符 UIKey ...
- 语音识别之梅尔频谱倒数MFCC(Mel Frequency Cepstrum Coefficient)
语音识别之梅尔频谱倒数MFCC(Mel Frequency Cepstrum Coefficient) 原理 梅尔频率倒谱系数:一定程度上模拟了人耳对语音的处理特点 预加重:在语音信号中,高频部分的能 ...
- API网关
API网关 最开始只是想找个API网关防止API被恶意请求,找了一圈发现基于Nginx的OpenResty(Lua语言)扩展模块Orange挺好(也找了Kong,但是感觉复杂了点没用),还偷懒用Vag ...