最精简的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. oraclede chuangjian yu dajian(zhuan)

    http://wenku.baidu.com/link?url=pIKLZJ4sAurjNGjwgChqjRMhCXfn77qy1K_EW3nlGn4eN4roDN8mhSG0GakYbrTBcsD4 ...

  2. php redis扩展

    安装redis扩展,一定要弄清楚自己的php版本 echo phpinfo(); 查看php信息. 页面搜索Compiler,可以获取自己的VC版本

  3. HBase 系统架构

    HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问.HBase的目标是存储并处理大型的数据.HBase是一个开源的,分布式的,多版本的,面向列的存储模型.它存储的是 ...

  4. JBPM4入门——6.流程实例的创建和执行

    本博文只是简要对JBPM4进行介绍,如需更详细内容请自行google 链接: JBPM入门系列文章: JBPM4入门——1.jbpm简要介绍 JBPM4入门——2.在eclipse中安装绘制jbpm流 ...

  5. Scala下载安装配置(Mac)

    ---恢复内容开始--- 1.访问scala的官网这里下载最新版的scala. 2.解压缩文件包,可将其移动至/usr/local/share下 1 mv /download/scalapath /u ...

  6. jQuery autoComplete 样式

    前提:使用了jQuery-ui 官网:http://jqueryui.com/autocomplete/ /*** autocomplete ***/ .ui-widget-content { bac ...

  7. 使用Nodejs+mongodb开发地图瓦片服务器

    原先地图瓦片服务器采用的是arcgisserver发布的地图服务并进行切片,但ags发布的地图服务很占内存,发布太多的话服务器压力很大.再一个就是ags价太高了. 学习Nodejs之后,发现这是一个可 ...

  8. 对话框式Activity的设置

    <activity android:name=".OtherActivity" android:label="@string/app_name" andr ...

  9. java读取目录下所有csv文件数据,存入三维数组并返回

    package dwzx.com.get; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; ...

  10. SSD Cloud Hosting - Linode的配置和部署,搭建Java环境

    0.发牢骚 前一个月在淘宝购买了个Jsp空间,挺便宜的,才38元/年.部署了程序,然后ALIMAMA验证网站,一直提示验证失败.最后找卖家,他说可能是因为空间太慢,照他的推荐换了最好的空间,138元/ ...