最精简的IOCP封装,DELPHI XE8直接编译通过。Winsock2.pas即使用DELPHI自带的,相信XE7也能编译,或者XE6,XE5也能。

单说Winsock2.pas,我见过无数种版本的了,各版本WINSOCK 2的API的方法的参数的数据类型居然都有出入,使用不同人封装的Winsock2.pas源码都要进行相应的调整,

否则无法编译通过,我认为还是使用DELPHI官方的最为靠谱。

要用于实际应用的话,还要进行“粘包处理”。

我在DELPHI XE8下测试OK。

unit Unit1;

interface

uses
Winsock2, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;

const
BUF_SIZE=1024;

type
//单IO数据结构
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;

//单句柄数据结构
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}

//工作者线程
function WorkThread(CompletionPortID: Pointer):DWORD; stdcall;
var
CompletionPort: THandle;
BytesTransferred: DWORD;
PerHandleData: LPER_HANDLE_DATA;
PerIOData: LPER_IO_DATA;
Flags: DWORD;
RecvBytes: DWORD;
begin
CompletionPort:= THandle(CompletionPortID);

while True do
begin
//获取完成端口上的队列的完成状态
GetQueuedCompletionStatus(CompletionPort, BytesTransferred, ULONG_PTR(PerHandleData), POverlapped(PerIOData), INFINITE);
//判断是客户端发来的数据还是服务端发出的数据
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;

//显示收到的数据,这样做是不安全的,示例而已 :)
Form1.Memo1.Lines.Add(string(PerIOData.Buf));
end;

//重置数据
PerIOData.RecvBytes:= 0;
PerIOData.DataBuf.len:= BUF_SIZE;
PerIOData.DataBuf.buf:= @PerIOData.Buf;

//再次投递
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

//初始化Winsock
WSAStartUp($202, WSData);
//创建完成端口
CompletionPort:= CreateIOCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
//根据处理器数量创建工作者线程的数量
GetSystemInfo(SI);
for Idx := 1 to SI.dwNumberOfProcessors do
//创建工作者线程,并将完成端口句柄传递给线程
CreateThread(nil, 0, @WorkThread, Pointer(CompletionPort), 0, ThreadID);
//创建监听套接字
ServerSocket:= WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nil, 0, WSA_FLAG_OVERLAPPED);
//设置LocalAddr的参数
LocalAddr.sin_family:= AF_INET; //IPV4族
LocalAddr.sin_addr.S_addr:= INADDR_ANY;//这里不能写Inet_addr('127.0.0.1'),否则会绑定失败,不清楚原因是什么;
LocalAddr.sin_port:= Htons(8000); //Host To Net Short,主机字节顺序转为网络字节顺序
//绑定本机IP地址、端口,绑定之前先设置好LocalAddr的参数
Bind(ServerSocket, sockaddr(LocalAddr), SizeOf(LocalAddr));
//开始监听
Listen(ServerSocket, 5);

while not Terminated do
begin
ClientSocket:= WSAAccept(ServerSocket,@ClientAddr, nil, nil, 0);
//创建TPER_HANDLE_DATA结构的变量保存客户端Socket
PER_HANDLE_DATA:= LPER_HANDLE_DATA(GlobalAlloc(GPTR, SizeOf(TPER_HANDLE_DATA)));
PER_HANDLE_DATA.Socket:= ClientSocket;
//把完成端口和客户端套接字关联起来
CreateIOCompletionPort(ClientSocket, CompletionPort, ulong_ptr(PER_HANDLE_DATA), 0);
//创建TPER_IO_DATA结构的变量,关联WSARecv函数
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
//创建监听线程
TListenThread.Create();
end;

end.

最精简的IOCP封装的更多相关文章

  1. [分享] RT7LITE精简后无法封装解决办法

    eagleonly 发表于 2016-6-9 11:00:01  https://www.itsk.com/forum.php?mod=viewthread&tid=368090&hi ...

  2. 采用完成端口(IOCP)实现高性能网络服务器(Windows c++版)

    前言 TCP\IP已成为业界通讯标准.现在越来越多的程序需要联网.网络系统分为服务端和客户端,也就是c\s模式(client \ server).client一般有一个或少数几个连接:server则需 ...

  3. c++ 网络编程(八) LINUX-epoll/windows-IOCP下 socket opoll函数用法 优于select方法的epoll 以及windows下IOCP 解决多进程服务端创建进程资源浪费问题

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9622548.html 锲子:关于并发服务器中的I/O复用实现方式,前面在网络编程系列四还是五来 ...

  4. Java 代码精简

    Java 代码精简 利用语法 利用三元表达式 普通 String title; if (isMember(phone)) { title = "会员"; } else { titl ...

  5. 高性能、高可用性Socket通讯库介绍 - 采用完成端口、历时多年调优!(附文件传输程序)

    前言 本人从事编程开发十余年,因为工作关系,很早就接触socket通讯编程.常言道:人在压力下,才可能出非凡的成果.我从事的几个项目都涉及到通讯,为我研究通讯提供了平台,也带来了动力.处理socket ...

  6. 端口快速扫描程序(c#版 一次可发起1000个连接)

    前言 为了探测本机或对方开放了哪些端口,需要用到端口扫描程序.扫描端口的原理很简单:就是尝试连接对方:如果成功,对方就开放了此端口.扫描程序的关键是速度,如果一次只能发起几个连接,显然速度太慢.如果对 ...

  7. windows 精简/封装/部署

    给一个精简过的Windows7安装net35,提示自己到『打开或关闭Windows功能』里打开,然而发现并没有,只有一个ie9的功能.搜索尝试各种办法,显然都不行.用dism部署功能的工具,挂载一个完 ...

  8. 对百度WebUploader的二次封装,精简前端代码之图片预览上传(两句代码搞定上传)

    前言 本篇文章上一篇: 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传) 此篇是在上面的基础上扩展出来专门上传图片的控件封装. 首先我们看看效果: 正文 使用方式同 ...

  9. 对MBProgressHUD进行二次封装并精简使用

    对MBProgressHUD进行二次封装并精简使用 https://github.com/jdg/MBProgressHUD 几个效果图: 以下源码是MBProgressHUD支持最新的iOS8的版本 ...

随机推荐

  1. ISO中AFN的使用步骤

    1.依赖的框架 * MobileCoreServices.framework * SystemConfiguration.framework * Security.framework 2.主头文件:A ...

  2. erl0005 - mnesia 分布式部署

    http://www.iteye.com/topic/643187 1.启动两个互通的节点a.b: 2.在a节点net_adm:ping(b) 查看ab之间是否联通(nodes()). 3.在保持通的 ...

  3. 【C#学习笔记】文本复制到粘贴板

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  4. 【英语】Bingo口语笔记(24) - L的发音技巧

    舌头往上跑

  5. python numpy argsort函数用法

    numpy.argsort numpy.argsort(a, axis=-1, kind='quicksort', order=None)[source] Returns the indices th ...

  6. 大数据分析的众包平台—Kaggle

    众包(Jeff Howe,2006)是一种在互联网蓬勃发展的背景下产生的一种创新的生产组织形式.在这样的商业模式下,企业利用网络将工作分配出去,通过让更合适的人群参与其中来发现创意和解决技术问题.比较 ...

  7. $(document).Ready()方法 VS OnLoad事件 VS $(window).load()方法

    $(document).Ready()方法 VS OnLoad事件 VS $(window).load()方法接触JQuery一般最先学到的是何时启动事件.在曾经很长一段时间里,在页面载入后引发的事件 ...

  8. linux 下按在sqllite

    1 安装 去sqlite主页http://www.sqlite.org/.跳转到下载也http://www.sqlite.org/download.html.源码下载sqlite-amalgamati ...

  9. 更新的packages.config所有的软件包?

    1. 你NuGet.exe的恢复你的包.运行的每个项目. nuget install packages.config 或用NuGet的2.7可以恢复所有包中的行. nuget restore Your ...

  10. boost的link 和 runtime-link,搭配shared 和 static

    转自:http://blog.csdn.net/yasi_xi/article/details/8660549 link:生成动态链接库/静态链接库.生成动态链接库需使用shared方式,生成静态链接 ...