<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>中文 &#187; susubuhui_</title>
	<atom:link href="http://software.intel.com/zh-cn/blogs/author/susubuhui_/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/zh-cn/blogs</link>
	<description></description>
	<lastBuildDate>Sat, 26 May 2012 06:34:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>高性能的 socket 通讯服务器（完成端口模型--IOCP）</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/02/16/socket-iocp/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/02/16/socket-iocp/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 06:15:58 +0000</pubDate>
		<dc:creator>susubuhui_</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>
		<category><![CDATA[服务器]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/02/16/socket-iocp/</guid>
		<description><![CDATA[很多人费尽心思，都没有找到一个完美的 I/O CP 例程，甚至跟人于误解，先将本人编写的例程公布出来，希望对那些苦苦寻觅的人带来收获。本例程可以作为初学者的学习之用，亦可以作为大型服务程序的通讯模块。其处理速度可以说，优化到了极点。如果理解了本例程的精髓，加上一个高效的通讯协议，你完全可以用它来构建一个高性能的通讯服务器。 在公布代码前，先谈谈I/O CP。对I/O CP的函数不多做说明了，网上很多，都一样。在此本人仅说一些技术上要注意的问题。 一、如何管理内存 1、IO数据缓冲管理 动态分配内存，是一种灵活的方式。但对于系统资源浪费是巨大的。因此本人采用的是预先分配服务器最大需要的内存，用链表来管理。任何时候分配交还都不需要遍历，仅需要互斥而已。 更巧妙的是，将IO发送信息和内存块有机的结合在一起，减少了链表的管理工作。 //IO操作标志 TIOFlag = (IO_ACCEPT, IO_READ, IO_WRITE); //IO操作信息 PIOInfo =^ TIOInfo; TIOInfo = packed record Overlapped: TOverlapped; //重叠结构 DataBuf: TWSABUF; //IO数据信息 Socket: TSocket; Flag: TIOFlag; TickCountSend: DWord; Next: PIOInfo; Prior: PIOInfo; end; PUNode =^ TUNode; TUNode = record Next: Pointer; end; PIOMem =^ TIOMem; TIOMem [...]]]></description>
			<content:encoded><![CDATA[<p>很多人费尽心思，都没有找到一个完美的 I/O CP 例程，甚至跟人于误解，先将本人编写的例程公布出来，希望对那些苦苦寻觅的人带来收获。本例程可以作为初学者的学习之用，亦可以作为大型服务程序的通讯模块。其处理速度可以说，优化到了极点。如果理解了本例程的精髓，加上一个高效的通讯协议，你完全可以用它来构建一个高性能的通讯服务器。</p>
<p>在公布代码前，先谈谈I/O CP。对I/O CP的函数不多做说明了，网上很多，都一样。在此本人仅说一些技术上要注意的问题。</p>
<p>一、如何管理内存<br />
1、IO数据缓冲管理<br />
动态分配内存，是一种灵活的方式。但对于系统资源浪费是巨大的。因此本人采用的是预先分配服务器最大需要的内存，用链表来管理。任何时候分配交还都不需要遍历，仅需要互斥而已。<br />
更巧妙的是，将IO发送信息和内存块有机的结合在一起，减少了链表的管理工作。</p>
<p>//IO操作标志<br />
TIOFlag = (IO_ACCEPT, IO_READ, IO_WRITE);<br />
//IO操作信息<br />
PIOInfo =^ TIOInfo;<br />
TIOInfo = packed record<br />
Overlapped: TOverlapped; //重叠结构<br />
DataBuf: TWSABUF; //IO数据信息<br />
Socket: TSocket;<br />
Flag: TIOFlag;<br />
TickCountSend: DWord;<br />
Next: PIOInfo;<br />
Prior: PIOInfo;<br />
end;</p>
<p>PUNode =^ TUNode;<br />
TUNode = record<br />
Next: Pointer;<br />
end;</p>
<p>PIOMem =^ TIOMem;<br />
TIOMem = packed record<br />
IOInfo: TIOInfo;<br />
Data: array[1..IO_MEM_SIZE] of Byte;<br />
//申请内存的时候，返回的是Data的地址<br />
end;</p>
<p>2、链路数据管理<br />
采用双向链表结构，减少删除节点时遍历消耗的时间</p>
<p>//每个连接的信息<br />
PLink =^ TLink;<br />
TLink = record<br />
Socket: TSocket;<br />
RemoteIP: string[30];<br />
RemotePort: DWord;<br />
//最后收到数据时的系统节拍<br />
TickCountActive: DWord;<br />
//处理该连接的当前线程的信息<br />
Worker: PWorker;<br />
Data: Pointer; //应用层可以设置这个成员，当OnReceive的时候，就不要每次遍历每个连接对应的数据区了<br />
Section: TRTLCriticalSection;<br />
Next: PLink;<br />
Prior: PLink;<br />
end;</p>
<p>二、如何管理线程<br />
每个工作线程创建的时候，调用：OnWorkerThreadCreateEvt，该函数可以返回这个线程对应的信息，比如为该线程创建的数据库连接控件或对应的类等，在OnReceive的可以从Link的Worker访问该成员Worker^.Data。</p>
<p>//工作线程信息<br />
PWorker =^ TWorker;<br />
TWorker = record<br />
ID: THandle;<br />
CompletionPort: THandle;<br />
Data: Pointer; //调用OnWorkerThreadCreateEvt返回的值<br />
//用于反应工作情况的数据<br />
TickCountLong,<br />
TickCountActive: DWord;<br />
ExecCount: Integer;<br />
//线程完成后设置<br />
Finished: THandle;<br />
Next: PWorker;<br />
end;</p>
<p>同理，服务线程也是具有一样的特点。相见源码。</p>
<p>关于线程同步，一直是众多程序头疼的问题。在本例程中，尽量避免了过多的互斥，并有效地防止了死锁现象。用RTLCriticalSection，稍微不注意，就会造成死锁的灾难。哪怕是两行代码的差别，对多线程而言都是灾难的。在本例程中，对数据同步需要操作的是在维护链路链表方面上。服务线程需要计算哪个连接空闲超时了，工作线程需要处理断线情况，应用层主动发送数据时需要对该链路独占，否则一个在发送，一个在处理断线故障，就会发送冲突，导致灾难后果。</p>
<p>在本人的压力测试中，已经有效的解决了这个问题，应用层部分不需要做什么同步工作，可以安心的收发数据了。同时每个线程都支持了数据库连接。</p>
<p>三、到底要创建多少个工作线程合适<br />
很多文章说，有N个CPU就创建N个线程，也有说N*2+2。最不喜欢说话不负责任的人了，本例程可以让刚入门 I/O CP 的人对它有更深入的了解。<br />
例程测试结果：<br />
<a href="http://p.blog.csdn.net/images/p_blog_csdn_net/GuestCode/EntryImages/20090720/200912280372.jpg"><img class="alignnone" src="http://p.blog.csdn.net/images/p_blog_csdn_net/GuestCode/EntryImages/20090720/200912280372.jpg" alt="" width="375" height="373" /></a><br />
四、该不该使用类<br />
有人说，抛弃一切类，对于服务器而言，会为类付出很多代价，从我的观点看，为类付出代价的，主要是动态创建的原因。其实，类成员访问和结构成员访问一样，需要相对地址。如果都是预先创建的，两者没有多大的差别。本例程采用裸奔函数的方式，当然在应用层可以采用类来管理，很难想象，如果没有没有类，需要多做多少工作。</p>
<p>五、缺点<br />
不能发大数据包，只能发不超过固定数的数据包。但对于小数据报而言，它将是优秀的。</p>
<p>时间原因，不能做太多的解释和对代码做太多的注释，需要例程源码的可以和本人联系，免费提供。ＱＱ：４８０９２７８８</p>
<p>例程源码：</p>
<p>http://d.download.csdn.net/down/1546336/guestcode</p>
<p>完成端口通讯服务模块源码：<br />
{******************************************************************************<br />
* UCode 系列组件、控件 *<br />
* 作者：卢益贵 2003～2009 *<br />
* 版权所有 任何未经授权的使用和销售，均保留追究法律责任的权力 *<br />
* *<br />
* UCode 系列由XCtrls－YCtrls－ICtrls－NCode系列演变而来 *<br />
* QQ:48092788 luyigui.blog.gxsky.com *<br />
******************************************************************************}<br />
{******************************************************************************<br />
完成端口模型的socket服务器<br />
******************************************************************************}<br />
unit UTcpServer;<br />
interface<br />
uses<br />
Windows, Classes, UClasses, UWinSock2;<br />
const<br />
//每个IO缓冲区的大小<br />
IO_MEM_SIZE = 2048;<br />
//内存要足够用,可视情况设置<br />
IO_MEM_MAX_COUNT = 1000 * 10;<br />
//最大连接数<br />
SOCK_MAX_COUNT = 3000;<br />
//连接空闲实现,超过这个时间未收到客户端数据则关闭<br />
SOCK_IDLE_OVERTIME = 60;<br />
type<br />
//工作线程信息<br />
PWorker =^ TWorker;<br />
TWorker = record<br />
ID: THandle;<br />
CompletionPort: THandle;<br />
Data: Pointer;<br />
//用于反应工作情况的数据<br />
TickCountLong,<br />
TickCountActive: DWord;<br />
ExecCount: Integer;<br />
//线程完成后设置<br />
Finished: THandle;<br />
Next: PWorker;<br />
end;<br />
//每个连接的信息<br />
PLink =^ TLink;<br />
TLink = record<br />
Socket: TSocket;<br />
RemoteIP: string[30];<br />
RemotePort: DWord;<br />
//最后收到数据时的系统节拍<br />
TickCountActive: DWord;<br />
//处理该连接的当前线程的信息<br />
Worker: PWorker;<br />
Data: Pointer;<br />
Section: TRTLCriticalSection;<br />
Next: PLink;<br />
Prior: PLink;<br />
end;<br />
TOnLinkIdleOvertimeEvt = procedure(Link: PLink);<br />
TOnDisconnectEvt = procedure(Link: PLink);<br />
TOnReceiveEvt = function(Link: PLink; Buf: PByte; Len: Integer): Boolean;<br />
TOnThreadCreateEvt = function(IsWorkerThread: Boolean): Pointer;<br />
//取得链路链表使用情况X%<br />
function GetLinkUse(): real;<br />
//链路链表所占内存<br />
function GetLinkSize(): Integer;<br />
//当前链路数<br />
function GetLinkCount(): Integer;<br />
//空闲链路数<br />
function GetLinkFree(): Integer;<br />
//IO内存使用情况<br />
function GetIOMemUse(): Real;<br />
//IO内存链表占内存数<br />
function GetIOMemSize(): Integer;<br />
//IO内存空闲数<br />
function GetIOMemFree(): Integer;<br />
//交还一个IO内存<br />
procedure FreeIOMem(Mem: Pointer);<br />
//获取一个IO内存区<br />
function GetIOMem(): Pointer;<br />
//获取工作线程的工作情况<br />
function GetWorkerExecInfo(Index: Integer; var TickCount: DWord): Integer;<br />
//获取工作线程的ID<br />
function GetWorkerID(Index: Integer): Integer;<br />
//获取工作线程数量<br />
function GetWorkerCount(): Integer;<br />
//打开一个IP端口,并监听<br />
function StartTcpServer(RemoteIP: String; RemotePort: DWord): Boolean;<br />
//停止并关闭一个IP端口<br />
function StopTcpServer(): Boolean;<br />
//设置响应事件的函数指针,在StartTcpServer之前调用<br />
procedure SetEventProc(OnReceive: TOnReceiveEvt;<br />
OnDisconnect: TOnDisconnectEvt;<br />
OnLinkIdleOvertime: TOnLinkIdleOvertimeEvt;<br />
OnServerThreadCreate: TOnThreadCreateEvt;<br />
OnWorkerThreadCreate: TOnThreadCreateEvt);<br />
//写日志文件<br />
procedure WriteLog(Log: String);<br />
function PostRecv(Link: PLink; IOMem: Pointer): Boolean;<br />
//抛出一个发送事件<br />
function PostSend(Link: PLink; IOMem: Pointer; Len: Integer): Boolean;<br />
//广播数据到所有的链路对方<br />
procedure PostBroadcast(Buf: PByte; Len: Integer);<br />
//当前是否打开<br />
function IsTcpServerActive(): Boolean;<br />
//获取服务线程最后一次工作所占的时间(MS)<br />
function GetServerExecLong(): DWord;<br />
//获取服务线程工作次数<br />
function GetServerExecCount(): Integer;<br />
//获取本地或对外IP地址<br />
function GetLocalIP(IsIntnetIP: Boolean): String;<br />
implementation<br />
uses<br />
IniFiles, SysUtils, ActiveX;<br />
var<br />
ExePath: String = '';<br />
const<br />
HEAP_NO_SERIALIZE = 1; {非互斥, 此标记可允许多个线程同时访问此堆}<br />
HEAP_GENERATE_EXCEPTIONS = 4; {当建立堆出错时, 此标记可激发一个异常并返回异常标识}<br />
HEAP_ZERO_MEMORY = 8; {把分配的内存初始化为 0}<br />
HEAP_REALLOC_IN_PLACE_ONLY = 16; {此标记不允许改变原来的内存位置}<br />
STATUS_ACCESS_VIOLATION = DWORD($C0000005); {参数错误}<br />
STATUS_NO_MEMORY = DWORD($C0000017); {内存不足}<br />
{===============================================================================<br />
IO内存管理<br />
================================================================================}<br />
type<br />
//IO操作标志<br />
TIOFlag = (IO_ACCEPT, IO_READ, IO_WRITE);<br />
//IO操作信息<br />
PIOInfo =^ TIOInfo;<br />
TIOInfo = packed record<br />
Overlapped: TOverlapped; //重叠结构<br />
DataBuf: TWSABUF; //IO数据信息<br />
Socket: TSocket;<br />
Flag: TIOFlag;<br />
TickCountSend: DWord;<br />
Next: PIOInfo;<br />
Prior: PIOInfo;<br />
end;</p>
<p>PUNode =^ TUNode;<br />
TUNode = record<br />
Next: Pointer;<br />
end;</p>
<p>PIOMem =^ TIOMem;<br />
TIOMem = packed record<br />
IOInfo: TIOInfo;<br />
Data: array[1..IO_MEM_SIZE] of Byte;<br />
end;<br />
var<br />
IOMemHead: PIOMem = nil;<br />
IOMemLast: PIOMem = nil;<br />
IOMemUse: Integer = 0;<br />
IOMemSec: TRTLCriticalSection;<br />
IOMemList: array[1..IO_MEM_MAX_COUNT] of Pointer;<br />
function GetIOMem(): Pointer;<br />
begin<br />
//内存要足够用，如果不够，即使是动态分配，神仙也救不了<br />
EnterCriticalSection(IOMemSec);<br />
try<br />
try<br />
Result := @(IOMemHead^.Data);<br />
IOMemHead := PUNode(IOMemHead)^.Next;<br />
IOMemUse := IOMemUse + 1;<br />
except<br />
Result := nil;<br />
WriteLog('GetIOMem: error');<br />
end;<br />
finally<br />
LeaveCriticalSection(IOMemSec);<br />
end;<br />
end;<br />
procedure FreeIOMem(Mem: Pointer);<br />
begin<br />
EnterCriticalSection(IOMemSec);<br />
try<br />
try<br />
Mem := Pointer(Integer(Mem) - sizeof(TIOInfo));<br />
PUNode(Mem).Next := nil;<br />
PUNode(IOMemLast)^.Next := Mem;<br />
IOMemLast := Mem;<br />
IOMemUse := IOMemUse - 1;<br />
except<br />
WriteLog('FreeIOMem: error');<br />
end;<br />
finally<br />
LeaveCriticalSection(IOMemSec);<br />
end;<br />
end;<br />
procedure IniIOMem();<br />
var<br />
i: Integer;<br />
Heap: THandle;<br />
begin<br />
InitializeCriticalSection(IOMemSec);<br />
IOMemHead := HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TIOMem));<br />
IOMemLast := IOMemHead;<br />
IOMemList[1] := IOMemHead;<br />
Heap := GetProcessHeap();<br />
for i := 2 to IO_MEM_MAX_COUNT do<br />
begin<br />
PUNode(IOMemLast)^.Next := HeapAlloc(Heap, HEAP_ZERO_MEMORY, sizeof(TIOMem));<br />
IOMemList[i] := PUNode(IOMemLast)^.Next;<br />
IOMemLast := PUNode(IOMemLast)^.Next;<br />
end;<br />
PUNode(IOMemLast).Next := nil;<br />
end;<br />
function GetIOMemFree(): Integer;<br />
var<br />
IOMems: PUNode;<br />
begin<br />
EnterCriticalSection(IOMemSec);<br />
Result := 0;<br />
IOMems := PUNode(IOMemHead);<br />
while IOMems nil do<br />
begin<br />
Result := Result + 1;<br />
IOMems := IOMems^.Next;<br />
end;<br />
LeaveCriticalSection(IOMemSec);<br />
end;<br />
procedure DeleteIOMem();<br />
var<br />
i: Integer;<br />
Heap: THandle;<br />
begin<br />
Heap := GetProcessHeap();<br />
for i := 1 to IO_MEM_MAX_COUNT do<br />
HeapFree(Heap, HEAP_NO_SERIALIZE, IOMemList[i]);<br />
IOMemUse := 0;<br />
DeleteCriticalSection(IOMemSec);<br />
end;<br />
function GetIOMemSize(): Integer;<br />
begin<br />
Result := IO_MEM_MAX_COUNT * sizeof(TIOMem);<br />
end;<br />
function GetIOMemUse(): Real;<br />
begin<br />
Result := (IOMemUse * 100) / IO_MEM_MAX_COUNT;<br />
end;<br />
{===============================================================================<br />
Socket链路管理<br />
================================================================================}<br />
procedure OnLinkIdleOvertimeDef(Link: PLink);<br />
begin<br />
end;<br />
var<br />
LinkHead: PLink = nil;<br />
LinkLast: PLink = nil;<br />
LinkUse: Integer = 0;<br />
LinkCount: Integer = 0;<br />
LinkSec: TRTLCriticalSection;<br />
LinkList: array[1..SOCK_MAX_COUNT] of PLink;<br />
OnLinkIdleOvertimeEvt: TOnLinkIdleOvertimeEvt = OnLinkIdleOvertimeDef;<br />
LinksHead: PLink = nil;<br />
LinksLast: PLink = nil;<br />
function GetLinkFree(): Integer;<br />
var<br />
Links: PLink;<br />
begin<br />
EnterCriticalSection(LinkSec);<br />
Result := 0;<br />
Links := LinkHead;<br />
while Links nil do<br />
begin<br />
Result := Result + 1;<br />
Links := Links^.Next;<br />
end;<br />
LeaveCriticalSection(LinkSec);<br />
end;<br />
function GetLink(): PLink;<br />
begin<br />
try<br />
//内存要足够用，如果不够，即使是动态分配，神仙也救不了<br />
Result := LinkHead;<br />
LinkHead := LinkHead^.Next;<br />
LinkUse := LinkUse + 1;<br />
LinkCount := LinkCount + 1;<br />
if LinksHead = nil then<br />
begin<br />
LinksHead := Result;<br />
LinksHead^.Next := nil;<br />
LinksHead^.Prior := nil;<br />
LinksLast := LinksHead;<br />
end else<br />
begin<br />
Result^.Prior := LinksLast;<br />
LinksLast^.Next := Result;<br />
LinksLast := Result;<br />
LinksLast^.Next := nil;<br />
end;<br />
with Result^ do<br />
begin<br />
Socket := INVALID_SOCKET;<br />
RemoteIP := '';<br />
RemotePort := 0;<br />
TickCountActive := GetTickCount();<br />
Worker := nil;<br />
Data := nil;<br />
end;<br />
except<br />
Result := nil;<br />
WriteLog('GetLink: error');<br />
end;<br />
end;<br />
procedure FreeLink(Link: PLink);<br />
begin<br />
try<br />
with Link^ do<br />
begin<br />
Link^.Worker := nil;<br />
if Link = LinksHead then<br />
begin<br />
LinksHead := Next;<br />
if LinksLast = Link then<br />
LinksLast := LinksHead<br />
else<br />
LinksHead^.Prior := nil;<br />
end else<br />
begin<br />
Prior^.Next := Next;<br />
if Next nil then<br />
Next^.Prior := Prior;<br />
if Link = LinksLast then<br />
LinksLast := Prior;<br />
end;<br />
Next := nil;<br />
LinkLast^.Next := Link;<br />
LinkLast := Link;<br />
LinkUse := LinkUse - 1;<br />
LinkCount := LinkCount - 1;<br />
end;<br />
except<br />
WriteLog('FreeLink: error');<br />
end;<br />
end;<br />
procedure CloseLink(Link: PLink);<br />
begin<br />
EnterCriticalSection(LinkSec);<br />
with Link^ do<br />
begin<br />
EnterCriticalSection(Section);<br />
if Socket INVALID_SOCKET then<br />
begin<br />
try<br />
CloseSocket(Socket);<br />
except<br />
WriteLog('CloseSocket: error');<br />
end;<br />
Socket := INVALID_SOCKET;<br />
FreeLink(Link);<br />
end;<br />
LeaveCriticalSection(Link^.Section);<br />
end;<br />
LeaveCriticalSection(LinkSec);<br />
end;<br />
procedure CheckLinkLinkIdleOvertime(Data: Pointer);<br />
var<br />
TickCount: DWord;<br />
Long: Integer;<br />
Link: PLink;<br />
begin<br />
EnterCriticalSection(LinkSec);<br />
try<br />
TickCount := GetTickCount();<br />
Link := LinksHead;<br />
while Link nil do<br />
with Link^ do<br />
begin<br />
EnterCriticalSection(Section);<br />
if Socket INVALID_SOCKET then<br />
begin<br />
if TickCount &gt; TickCountActive then<br />
Long := TickCount - TickCountActive<br />
else<br />
Long := $FFFFFFFF - TickCountActive + TickCount;<br />
if SOCK_IDLE_OVERTIME * 1000 0 do<br />
i := i - 1;<br />
if not PostSend(Link, IOMem, Len) then<br />
FreeIOMem(IOMem);<br />
end;<br />
function OnWorkerThreadCreateDef(IsWorkerThread: Boolean): Pointer;<br />
begin<br />
Result := nil;<br />
end;<br />
var<br />
WorkerHead: PWorker = nil;<br />
WorkerCount: Integer = 0;<br />
OnDisconnectEvt: TOnDisconnectEvt = OnDisconnectDef;<br />
OnReceiveEvt: TOnReceiveEvt = OnReceiveDef;<br />
OnWorkerThreadCreateEvt: TOnThreadCreateEvt = OnWorkerThreadCreateDef;<br />
function GetWorkerCount(): Integer;<br />
begin<br />
Result := WorkerCount;<br />
end;<br />
function WorkerThread(Worker: PWorker): DWORD; stdcall;<br />
var<br />
Link: PLink;<br />
IOInfo: PIOInfo;<br />
Bytes: DWord;<br />
CompletionPort: THandle;<br />
begin<br />
Result := 0;<br />
CompletionPort := Worker^.CompletionPort;<br />
with Worker^ do<br />
begin<br />
TickCountActive := GetTickCount();<br />
TickCountLong := 0;<br />
ExecCount := 0;<br />
end;<br />
WriteLog(Format('Worker thread:%d begin', [Worker^.ID]));<br />
CoInitialize(nil);<br />
try<br />
while True do<br />
begin<br />
try<br />
with Worker^ do<br />
TickCountLong := TickCountLong + GetTickCount() - TickCountActive;</p>
<p>if GetQueuedCompletionStatus(CompletionPort, Bytes, DWORD(Link), POverlapped(IOInfo), INFINITE) = False then<br />
begin<br />
if (Link nil) then<br />
with Link^ do<br />
begin<br />
EnterCriticalSection(LinkSec);<br />
EnterCriticalSection(Section);<br />
if Link^.Socket INVALID_SOCKET then<br />
begin<br />
try<br />
CloseSocket(Socket);<br />
except<br />
WriteLog(Format('CloseSocket1:%d error', [Worker^.ID]));<br />
end;<br />
Socket := INVALID_SOCKET;<br />
Link^.Worker := Worker;<br />
try<br />
OnDisconnectEvt(Link);<br />
except<br />
WriteLog(Format('OnDisconnectEvt1:%d error', [Worker^.ID]));<br />
end;<br />
Link^.Worker := nil;<br />
FreeLink(Link);<br />
end;<br />
LeaveCriticalSection(Section);<br />
LeaveCriticalSection(LinkSec);<br />
end;<br />
if IOInfo nil then<br />
FreeIOMem(IOInfo^.DataBuf.buf);<br />
WriteLog(Format('GetQueuedCompletionStatus:%d error', [Worker^.ID]));<br />
continue;<br />
end;</p>
<p>with Worker^ do<br />
begin<br />
TickCountActive := GetTickCount();<br />
ExecCount := ExecCount + 1;<br />
end;<br />
if (Bytes = 0) then<br />
begin<br />
if (Link nil) then<br />
with Link^ do<br />
begin<br />
EnterCriticalSection(LinkSec);<br />
EnterCriticalSection(Section);<br />
if Link^.Socket INVALID_SOCKET then<br />
begin<br />
try<br />
CloseSocket(Socket);<br />
except<br />
WriteLog(Format('CloseSocket2:%d error', [Worker^.ID]));<br />
end;<br />
Socket := INVALID_SOCKET;<br />
Link^.Worker := Worker;<br />
try<br />
OnDisconnectEvt(Link);<br />
except<br />
WriteLog(Format('OnDisconnectEvt2:%d error', [Worker^.ID]));<br />
end;<br />
Link^.Worker := nil;<br />
FreeLink(Link);<br />
end;<br />
LeaveCriticalSection(Section);<br />
LeaveCriticalSection(LinkSec);<br />
if IOInfo.Flag = IO_WRITE then<br />
FreeIOMem(IOInfo^.DataBuf.buf)<br />
else<br />
FreeIOMem(IOInfo^.DataBuf.buf);<br />
continue;<br />
end else<br />
begin<br />
if IOInfo nil then<br />
FreeIOMem(IOInfo^.DataBuf.buf);<br />
break;<br />
end;<br />
end;</p>
<p>if IOInfo.Flag = IO_WRITE then<br />
begin<br />
FreeIOMem(IOInfo^.DataBuf.buf);<br />
continue;<br />
end;</p>
<p>{if IOInfo.Flag = IO_ACCEPT then<br />
begin<br />
......<br />
continue;<br />
end;}<br />
with Link^, IOInfo^.DataBuf do<br />
begin<br />
Link^.Worker := Worker;<br />
try<br />
OnReceiveEvt(Link, buf, Bytes);<br />
except<br />
WriteLog(Format('OnReceiveEvt:%d error', [Worker^.ID]));<br />
end;<br />
Link^.Worker := nil;<br />
TickCountActive := GetTickCount();<br />
if not PostRecv(Link, buf) then<br />
begin<br />
EnterCriticalSection(LinkSec);<br />
EnterCriticalSection(Section);<br />
if Socket INVALID_SOCKET then<br />
begin<br />
try<br />
CloseSocket(Socket);<br />
except<br />
WriteLog(Format('CloseSocket3:%d error', [Worker^.ID]));<br />
end;<br />
Socket := INVALID_SOCKET;<br />
Link^.Worker := Worker;<br />
try<br />
OnDisconnectEvt(Link);<br />
except<br />
WriteLog(Format('OnDisconnectEvt3:%d error', [Worker^.ID]));<br />
end;<br />
Link^.Worker := nil;<br />
FreeLink(Link);<br />
end;<br />
LeaveCriticalSection(Section);<br />
LeaveCriticalSection(LinkSec);<br />
FreeIOMem(buf);<br />
end;<br />
end;<br />
except<br />
WriteLog(Format('Worker thread:%d error', [Worker^.ID]));<br />
end;<br />
end;<br />
finally<br />
CoUninitialize();<br />
WriteLog(Format('Worker thread:%d end', [Worker^.ID]));<br />
SetEvent(Worker^.Finished);<br />
end;<br />
end;<br />
procedure CreateWorkerThread(CompletionPort: THandle);<br />
var<br />
Worker, Workers: PWorker;<br />
i: Integer;<br />
SystemInfo: TSystemInfo;<br />
ThreadHandle: THandle;<br />
begin<br />
GetSystemInfo(SystemInfo);<br />
Workers := nil;<br />
WorkerCount := (SystemInfo.dwNumberOfProcessors * 2 + 2);<br />
for i := 1 to WorkerCount do<br />
begin<br />
Worker := HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TWorker));<br />
if Workers = nil then<br />
begin<br />
Workers := Worker;<br />
WorkerHead := Workers;<br />
end else<br />
begin<br />
Workers^.Next := Worker;<br />
Workers := Worker;<br />
end;<br />
Worker^.CompletionPort := CompletionPort;<br />
Worker^.Data := OnWorkerThreadCreateEvt(False);<br />
Worker^.Finished := CreateEvent(nil, True, False, nil);<br />
ThreadHandle := CreateThread(nil, 0, @WorkerThread, Worker, 0, Worker^.ID);<br />
if ThreadHandle 0 then<br />
CloseHandle(ThreadHandle);<br />
end;<br />
Workers^.Next := nil;<br />
end;<br />
procedure DestroyWorkerThread();<br />
var<br />
Worker, Save: PWorker;<br />
begin<br />
WorkerCount := 0;<br />
Worker := WorkerHead;<br />
while Worker nil do<br />
begin<br />
PostQueuedCompletionStatus(Worker^.CompletionPort, 0, 0, nil);<br />
Worker := Worker^.Next;<br />
end;<br />
Worker := WorkerHead;<br />
while Worker nil do<br />
begin<br />
with Worker^ do<br />
begin<br />
WaitForSingleObject(Worker^.Finished, INFINITE);<br />
CloseHandle(Worker^.Finished);<br />
Save := Worker^.Next;<br />
end;<br />
HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, Worker);<br />
Worker := Save;<br />
end;<br />
end;<br />
function GetWorkerExecInfo(Index: Integer; var TickCount: DWord): Integer;<br />
var<br />
Worker: PWorker;<br />
Count: Integer;<br />
begin<br />
Worker := WorkerHead;<br />
Count := 0;<br />
Result := 0;<br />
while Worker nil do<br />
with Worker^ do<br />
begin<br />
Count := Count + 1;<br />
if Count = Index then<br />
begin<br />
TickCount := TickCountLong;<br />
TickCountLong := 0;<br />
Result := Worker^.ExecCount;<br />
break;<br />
end;<br />
Worker := Worker^.Next;<br />
end;<br />
end;<br />
function GetWorkerID(Index: Integer): Integer;<br />
var<br />
Worker: PWorker;<br />
Count: Integer;<br />
begin<br />
Worker := WorkerHead;<br />
Count := 0;<br />
while Worker nil do<br />
begin<br />
Count := Count + 1;<br />
if Count = Index then<br />
begin<br />
Count := Worker^.ID;<br />
break;<br />
end;<br />
Worker := Worker^.Next;<br />
end;<br />
Result := Count;<br />
end;<br />
{===============================================================================<br />
服务线程<br />
================================================================================}<br />
function OnServerThreadCreateDef(IsWorkerThread: Boolean): Pointer;<br />
begin<br />
Result := nil;<br />
end;<br />
var<br />
ListenSocket: TSocket = INVALID_SOCKET;<br />
SocketEvent: THandle = WSA_INVALID_EVENT;<br />
CompletionPort: THandle = 0;<br />
Terminated: Boolean = False;<br />
ServerThreadID: DWORD = 0;<br />
ServerExecCount: Integer = 0;<br />
ServerExecLong: DWord = 0;<br />
OnServerThreadCreateEvt: TOnThreadCreateEvt = OnServerThreadCreateDef;<br />
ServerFinished: THandle;<br />
function GetServerExecCount(): Integer;<br />
begin<br />
Result := ServerExecCount;<br />
end;<br />
function GetServerExecLong(): DWord;<br />
begin<br />
Result := ServerExecLong;<br />
ServerExecLong := 0;<br />
end;</p>
<p>function ServerThread(Param: Pointer): DWORD; stdcall;<br />
var<br />
AcceptSocket: TSocket;<br />
Addr: TSockAddrIn;<br />
Len: Integer;<br />
Link: PLink;<br />
IOMem: Pointer;<br />
bNodelay: Boolean;<br />
TickCount: DWord;<br />
WR: DWord;<br />
begin<br />
Result := 0;<br />
CoInitialize(nil);<br />
WriteLog('Server thread begin');<br />
TickCount := GetTickCount();<br />
try<br />
while not Terminated do<br />
begin<br />
try<br />
ServerExecLong := ServerExecLong + (GetTickCount() - TickCount);<br />
WR := WaitForSingleObject(SocketEvent, 10000);</p>
<p>ServerExecCount := ServerExecCount + 1;<br />
TickCount := GetTickCount();</p>
<p>if (WAIT_TIMEOUT = WR) then<br />
begin<br />
CheckLinkLinkIdleOvertime(Param);<br />
continue;<br />
end else<br />
if (WAIT_FAILED = WR) then<br />
begin<br />
continue;<br />
end else<br />
begin<br />
Len := SizeOf(TSockAddrIn);<br />
AcceptSocket := WSAAccept(ListenSocket, @Addr, @Len, nil, 0);<br />
if (AcceptSocket = INVALID_SOCKET) then<br />
continue;<br />
if LinkCount &gt;= SOCK_MAX_COUNT then<br />
begin<br />
try<br />
CloseSocket(AcceptSocket);<br />
except<br />
WriteLog('Link count over');<br />
end;<br />
continue;<br />
end;</p>
<p>bNodelay := True;<br />
if SetSockOpt(AcceptSocket, IPPROTO_TCP, TCP_NODELAY,<br />
PChar(@bNodelay), sizeof(bNodelay)) = SOCKET_ERROR then<br />
begin<br />
try<br />
CloseSocket(AcceptSocket);<br />
except<br />
WriteLog('SetSockOpt: error');<br />
end;<br />
continue;<br />
end;<br />
EnterCriticalSection(LinkSec);<br />
Link := GetLink();<br />
with Link^ do<br />
begin<br />
EnterCriticalSection(Section);<br />
RemoteIP := inet_ntoa(Addr.sin_addr);<br />
RemotePort := Addr.sin_port;<br />
TickCountActive := GetTickCount();<br />
Socket := AcceptSocket;<br />
IOMem := GetIOMem();<br />
if (CreateIoCompletionPort(AcceptSocket, CompletionPort, DWORD(Link), 0) = 0) or<br />
(not PostRecv(Link, IOMem)) then<br />
begin<br />
try<br />
CloseSocket(Socket);<br />
except<br />
WriteLog('CreateIoCompletionPort or PostRecv: error');<br />
end;<br />
Socket := INVALID_SOCKET;<br />
FreeLink(Link);<br />
FreeIOMem(IOMem);<br />
end;<br />
LeaveCriticalSection(Section);<br />
end;<br />
LeaveCriticalSection(LinkSec);<br />
end;<br />
except<br />
WriteLog('Server thread error');<br />
end;<br />
end;<br />
finally<br />
CoUninitialize();<br />
WriteLog('Server thread end');<br />
SetEvent(ServerFinished);<br />
end;<br />
end;<br />
function StartTcpServer(RemoteIP: String; RemotePort: DWord): Boolean;<br />
var<br />
NonBlock: Integer;<br />
bNodelay: Boolean;<br />
Addr: TSockAddrIn;<br />
ThreadHandle: THANDLE;<br />
begin<br />
Result := ListenSocket = INVALID_SOCKET;<br />
if not Result then<br />
exit;<br />
IniIOMem();<br />
IniLink();</p>
<p>ListenSocket := WSASocket(AF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED);<br />
Result := ListenSocket INVALID_SOCKET;<br />
if not Result then<br />
begin<br />
DeleteLink();<br />
DeleteIOMem();<br />
exit;<br />
end;<br />
bNodelay := True;<br />
NonBlock := 1;<br />
Addr.sin_family := AF_INET;<br />
Addr.sin_addr.s_addr := inet_addr(PChar(RemoteIP));<br />
Addr.sin_port := htons(RemotePort);<br />
Result := (SetSockOpt(ListenSocket, IPPROTO_TCP, TCP_NODELAY, PChar(@bNodelay), sizeof(bNodelay)) SOCKET_ERROR) and<br />
(ioctlsocket(ListenSocket, Integer(FIONBIO), NonBlock) SOCKET_ERROR) and<br />
(Bind(ListenSocket, @Addr, SizeOf(TSockAddrIn)) SOCKET_ERROR) and<br />
(Listen(ListenSocket, SOMAXCONN) SOCKET_ERROR);<br />
if not Result then<br />
begin<br />
ListenSocket := INVALID_SOCKET;<br />
DeleteLink();<br />
DeleteIOMem();<br />
exit;<br />
end;<br />
SocketEvent := CreateEvent(nil, FALSE, FALSE, nil);<br />
Result := (SocketEvent WSA_INVALID_EVENT);<br />
if (not Result) then<br />
begin<br />
CloseSocket(ListenSocket);<br />
ListenSocket := INVALID_SOCKET;<br />
DeleteLink();<br />
DeleteIOMem();<br />
exit;<br />
end;<br />
Result := (WSAEventSelect(ListenSocket, SocketEvent, FD_ACCEPT) SOCKET_ERROR);<br />
if not Result then<br />
begin<br />
CloseSocket(ListenSocket);<br />
ListenSocket := INVALID_SOCKET;<br />
WSACloseEvent(SocketEvent);<br />
SocketEvent := WSA_INVALID_EVENT;<br />
DeleteLink();<br />
DeleteIOMem();<br />
exit;<br />
end;<br />
CompletionPort := CreateIoCompletionPort(INVALID_HANDLE_value, 0, 0, 0);<br />
Result := CompletionPort 0;<br />
if not Result then<br />
begin<br />
CloseSocket(ListenSocket);<br />
ListenSocket := INVALID_SOCKET;<br />
WSACloseEvent(SocketEvent);<br />
SocketEvent := WSA_INVALID_EVENT;<br />
DeleteLink();<br />
DeleteIOMem();<br />
exit;<br />
end;<br />
WriteLog('Server Start');<br />
CreateWorkerThread(CompletionPort);<br />
ServerFinished := CreateEvent(nil, True, False, nil);<br />
Result := ServerFinished 0;<br />
if not Result then<br />
begin<br />
CloseSocket(ListenSocket);<br />
ListenSocket := INVALID_SOCKET;<br />
WSACloseEvent(SocketEvent);<br />
SocketEvent := WSA_INVALID_EVENT;<br />
DeleteLink();<br />
DeleteIOMem();<br />
exit;<br />
end;<br />
Terminated := False;<br />
ThreadHandle := CreateThread(nil, 0, @ServerThread, OnServerThreadCreateEvt(False), 0, ServerThreadID);<br />
if (ThreadHandle = 0) then<br />
begin<br />
StopTcpServer();<br />
exit;<br />
end;<br />
CloseHandle(ThreadHandle);<br />
end;<br />
function StopTcpServer(): Boolean;<br />
begin<br />
Result := ListenSocket INVALID_SOCKET;<br />
if not Result then<br />
exit;<br />
WriteLog('Server Stop');<br />
Terminated := True;<br />
if ServerFinished 0 then<br />
begin<br />
WaitForSingleObject(ServerFinished, INFINITE);<br />
CloseHandle(ServerFinished);<br />
ServerFinished := 0;<br />
end;<br />
if SocketEvent 0 then<br />
WSACloseEvent(SocketEvent);<br />
SocketEvent := 0;<br />
DestroyWorkerThread();<br />
if ListenSocket INVALID_SOCKET then<br />
CloseSocket(ListenSocket);<br />
ListenSocket := INVALID_SOCKET;<br />
if CompletionPort 0 then<br />
CloseHandle(CompletionPort);<br />
CompletionPort := 0;<br />
ServerExecCount := 0;<br />
ServerExecLong := 0;<br />
DeleteLink();<br />
DeleteIOMem();<br />
end;<br />
function GetLocalIP(IsIntnetIP: Boolean): String;<br />
type<br />
TaPInAddr = Array[0..10] of PInAddr;<br />
PaPInAddr = ^TaPInAddr;<br />
var<br />
phe: PHostEnt;<br />
pptr: PaPInAddr;<br />
Buffer: Array[0..63] of Char;<br />
I: Integer;<br />
begin<br />
Result := '0.0.0.0';<br />
try<br />
GetHostName(Buffer, SizeOf(Buffer));<br />
phe := GetHostByName(buffer);<br />
if phe = nil then<br />
Exit;<br />
pPtr := PaPInAddr(phe^.h_addr_list);<br />
if IsIntnetIP then<br />
begin<br />
I := 0;<br />
while pPtr^[I] nil do<br />
begin<br />
Result := inet_ntoa(pptr^[I]^);<br />
Inc(I);<br />
end;<br />
end else<br />
Result := inet_ntoa(pptr^[0]^);<br />
except<br />
end;<br />
end;<br />
procedure SetEventProc(OnReceive: TOnReceiveEvt;<br />
OnDisconnect: TOnDisconnectEvt;<br />
OnLinkIdleOvertime: TOnLinkIdleOvertimeEvt;<br />
OnServerThreadCreate: TOnThreadCreateEvt;<br />
OnWorkerThreadCreate: TOnThreadCreateEvt);<br />
begin<br />
OnReceiveEvt := OnReceive;<br />
OnDisconnectEvt := OnDisconnect;<br />
OnLinkIdleOvertimeEvt := OnLinkIdleOvertime;<br />
OnServerThreadCreateEvt := OnServerThreadCreate;<br />
OnWorkerThreadCreateEvt := OnWorkerThreadCreate;<br />
end;<br />
function PostRecv(Link: PLink; IOMem: Pointer): Boolean;<br />
var<br />
Flags: DWord;<br />
Bytes: DWord;<br />
IOInfo: PIOInfo;<br />
begin<br />
Result := Link^.Socket INVALID_SOCKET;<br />
if Result then<br />
try<br />
Flags := 0;<br />
Bytes := 0;<br />
IOInfo := PIOInfo(Integer(IOMem) - sizeof(TIOInfo));<br />
with IOInfo^ do<br />
begin<br />
ZeroMemory(IOInfo, sizeof(TIOInfo));<br />
DataBuf.buf := IOMem;<br />
DataBuf.len := IO_MEM_SIZE;<br />
Socket := Link^.Socket;<br />
Flag := IO_READ;<br />
Result := (WSARecv(Socket, @DataBuf, 1, @Bytes, @Flags, @Overlapped, nil) SOCKET_ERROR) or<br />
(WSAGetLastError() = ERROR_IO_PENDING);<br />
end;<br />
except<br />
Result := False;<br />
WriteLog('PostRecv: error');<br />
end;<br />
end;<br />
function PostSend(Link: PLink; IOMem: Pointer; Len: Integer): Boolean;<br />
var<br />
Bytes: DWord;<br />
IOInfo: PIOInfo;<br />
begin<br />
Result := Link^.Socket INVALID_SOCKET;<br />
if Result then<br />
try<br />
Bytes := 0;<br />
IOInfo := PIOInfo(Integer(IOMem) - sizeof(TIOInfo));<br />
with IOInfo^ do<br />
begin<br />
ZeroMemory(IOInfo, sizeof(TIOInfo));<br />
DataBuf.buf := IOMem;<br />
DataBuf.len := Len;<br />
Socket := Link^.Socket;<br />
Flag := IO_WRITE;<br />
Result := (WSASend(Socket, @(DataBuf), 1, @Bytes, 0, @(Overlapped), nil) SOCKET_ERROR) or<br />
(WSAGetLastError() = ERROR_IO_PENDING);<br />
end;<br />
except<br />
Result := False;<br />
WriteLog('PostSend: error');<br />
end;<br />
end;<br />
procedure PostBroadcast(Buf: PByte; Len: Integer);<br />
var<br />
IOMem: Pointer;<br />
Link: PLink;<br />
begin<br />
EnterCriticalSection(LinkSec);<br />
Link := LinksHead;<br />
while Link nil do<br />
with Link^ do<br />
begin<br />
if Socket INVALID_SOCKET then<br />
begin<br />
IOMem := GetIOMem();<br />
CopyMemory(IOMem, Buf, Len);<br />
if not PostSend(Link, IOMem, Len) then<br />
FreeIOMem(IOMem);<br />
end;<br />
Link := Link^.Next;<br />
end;<br />
LeaveCriticalSection(LinkSec);<br />
end;<br />
function IsTcpServerActive(): Boolean;<br />
begin<br />
Result := ListenSocket INVALID_SOCKET;<br />
end;<br />
{===============================================================================<br />
日志管理<br />
================================================================================}<br />
var<br />
LogSec: TRTLCriticalSection;<br />
Inifile: TIniFile;<br />
LogCount: Integer = 0;<br />
LogName: String = '';<br />
procedure WriteLog(Log: String);<br />
begin<br />
EnterCriticalSection(LogSec);<br />
try<br />
LogCount := LogCount + 1;<br />
IniFile.WriteString(LogName,<br />
'Index' + IntToStr(LogCount),<br />
DateTimeToStr(Now()) + ':' + Log);<br />
finally<br />
LeaveCriticalSection(LogSec);<br />
end;<br />
end;<br />
{===============================================================================<br />
初始化Window Socket<br />
================================================================================}<br />
var<br />
WSAData: TWSAData;</p>
<p>procedure Startup;<br />
var<br />
ErrorCode: Integer;<br />
begin<br />
ErrorCode := WSAStartup( {$SK_blogItemTitle$}<br />
{$SK_ItemBody$}</p>
<p>{$SK_blogDiary$} {$SK_blogItemLink$} {$SK_blogItemComm$} {$SK_blogItemQuote$} {$SK_blogItemVisit$}</p>
<p>01, WSAData);<br />
if ErrorCode 0 then<br />
WriteLog('Window Socket init Error!');<br />
end;<br />
procedure Cleanup;<br />
var<br />
ErrorCode: Integer;<br />
begin<br />
ErrorCode := WSACleanup;<br />
if ErrorCode 0 then<br />
WriteLog('Window Socket cleanup error!');<br />
end;<br />
function GetExePath(): String;<br />
var<br />
ModuleName: array[0..1024] of char;<br />
begin<br />
GetModuleFileName(MainInstance, ModuleName, SizeOf(ModuleName));<br />
Result := ExtractFilePath(ModuleName);<br />
end;<br />
initialization<br />
LogName := DateTimeToStr(Now());<br />
InitializeCriticalSection(LogSec);<br />
ExePath := GetExePath();<br />
IniFile := TIniFile.Create(ExePath + 'Logs.Ini');<br />
Startup();<br />
finalization<br />
Cleanup();<br />
DeleteCriticalSection(LogSec);<br />
IniFile.Destroy();</p>
<p>end.</p>
<p>主窗口单元源码：<br />
unit uMainTcpServerIOCP;<br />
interface<br />
uses<br />
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br />
Dialogs, ExtCtrls, StdCtrls, ComCtrls, UTcpServer, Sockets, Grids;<br />
type<br />
TfrmMainUTcpServerIOCP = class(TForm)<br />
Label1: TLabel;<br />
Label2: TLabel;<br />
edtIP: TEdit;<br />
edtPort: TEdit;<br />
btn: TButton;<br />
Timer1: TTimer;<br />
Label3: TLabel;<br />
lbIO: TLabel;<br />
Label5: TLabel;<br />
lbIOU: TLabel;<br />
Label7: TLabel;<br />
lbL: TLabel;<br />
Label9: TLabel;<br />
lbLU: TLabel;<br />
Label11: TLabel;<br />
lbLS: TLabel;<br />
Label13: TLabel;<br />
lbW: TLabel;<br />
Info: TStringGrid;<br />
Label4: TLabel;<br />
lbWC: TLabel;<br />
Label8: TLabel;<br />
lbWU: TLabel;<br />
Label12: TLabel;<br />
lbLF: TLabel;<br />
Label15: TLabel;<br />
lbLFL: TLabel;<br />
Label6: TLabel;<br />
lbIOF: TLabel;<br />
lbIOFL: TLabel;<br />
Label16: TLabel;<br />
Timer2: TTimer;<br />
procedure btnClick(Sender: TObject);<br />
procedure FormCreate(Sender: TObject);<br />
procedure Timer1Timer(Sender: TObject);<br />
procedure FormDestroy(Sender: TObject);<br />
procedure Timer2Timer(Sender: TObject);<br />
private<br />
{ Private declarations }<br />
FTickCount: DWord;<br />
public<br />
{ Public declarations }<br />
end;<br />
var<br />
frmMainUTcpServerIOCP: TfrmMainUTcpServerIOCP;<br />
implementation<br />
{$R *.dfm}<br />
{ TfrmMainUTcpServerIOCP }<br />
procedure TfrmMainUTcpServerIOCP.btnClick(Sender: TObject);<br />
var<br />
i: Integer;<br />
C1: Integer;<br />
C2: DWord;<br />
DT: TDateTime;<br />
begin<br />
if btn.Caption = 'Open' then<br />
begin<br />
StartTcpServer(edtIP.Text, StrToInt(edtPort.Text));<br />
if IsTcpServerActive() then<br />
begin<br />
FTickCount := GetTickCount();<br />
Info.RowCount := GetWorkerCount() + 1;<br />
DT := Now();<br />
for i := 1 to Info.RowCount - 1 do<br />
begin<br />
Info.Cells[0, i] := IntToStr(i);<br />
Info.Cells[1, i] := IntToStr(GetWorkerID(i));<br />
C1 := GetWorkerExecInfo(i, C2);<br />
Info.Cells[2, i] := IntToStr(C1);<br />
Info.Cells[3, i] := '0';<br />
Info.Cells[4, i] := IntToStr(C2);<br />
Info.Cells[5, i] := '0';<br />
Info.Cells[6, i] := DateTimeToStr(DT);<br />
end;<br />
Timer1.Enabled := True;<br />
end;<br />
end else<br />
begin<br />
Timer1.Enabled := False;<br />
StopTcpServer();<br />
end;<br />
if IsTcpServerActive() then<br />
btn.Caption := 'Close'<br />
else<br />
btn.Caption := 'Open';<br />
end;<br />
procedure TfrmMainUTcpServerIOCP.FormCreate(Sender: TObject);<br />
begin<br />
edtIP.Text := GetLocalIP(False);<br />
Info.ColCount := 7;<br />
Info.RowCount := 2;<br />
Info.ColWidths[0] := 30;<br />
Info.ColWidths[1] := 30;<br />
Info.ColWidths[2] := 40;<br />
Info.ColWidths[3] := 40;<br />
Info.ColWidths[4] := 30;<br />
Info.ColWidths[5] := 40;<br />
Info.ColWidths[6] := 110;<br />
Info.Cells[0, 0] := '序号';<br />
Info.Cells[1, 0] := 'ID';<br />
Info.Cells[2, 0] := '计数';<br />
Info.Cells[3, 0] := '次／S';<br />
Info.Cells[4, 0] := '时长';<br />
Info.Cells[5, 0] := '使用率';<br />
Info.Cells[6, 0] := '时间';<br />
end;<br />
procedure TfrmMainUTcpServerIOCP.Timer1Timer(Sender: TObject);<br />
var<br />
i: Integer;<br />
Count1, Count2, Count3, TC, TCC: DWord;<br />
begin<br />
if not IsTcpServerActive() then<br />
begin<br />
Timer1.Enabled := False;<br />
exit;<br />
end;<br />
TC := GetTickCount();<br />
TCC := TC - FTickCount;<br />
if TCC = 0 then<br />
TCC := $FFFFFFFF;<br />
lbWC.Caption := IntToStr(GetServerExecCount());<br />
lbWU.Caption := FloatToStrF(GetServerExecLong() / TCC * 100, ffFixed, 10, 3) + '%';<br />
for i := 1 to Info.RowCount - 1 do<br />
begin<br />
Count1 := GetWorkerExecInfo(i, Count2);<br />
TC := GetTickCount();<br />
TCC := TC - FTickCount;<br />
if TCC = 0 then<br />
TCC := $FFFFFFFF;</p>
<p>Count3 := StrToInt(Info.Cells[2, i]);<br />
if Count1 Count3 then<br />
begin<br />
Info.Cells[2, i] := IntToStr(Count1);<br />
Info.Cells[3, i] := IntToStr(Count1 - Count3);<br />
Info.Cells[4, i] := IntToStr(Count2);<br />
Info.Cells[5, i] := FloatToStrF(Count2 / TCC * 100, ffFixed, 10, 1) + '%';<br />
Info.Cells[6, i] := DateTimeToStr(Now());<br />
end;<br />
end;<br />
FTickCount := TC;<br />
lbIO.Caption := IntToStr(GetIOMemSize());<br />
lbIOU.Caption := FloatToStrF(GetIOMemUse(), ffFixed, 10, 3) + '%';<br />
Count1 := GetIOMemFree();<br />
lbIOF.Caption := IntToStr(Count1);<br />
lbIOFL.Caption := FloatToStrF(Count1 / IO_MEM_MAX_COUNT * 100, ffFixed, 10, 3) + '%';<br />
lbW.Caption := IntToStr(GetWorkerCount());<br />
lbL.Caption := IntToStr(GetLinkSize());<br />
Count1 := GetLinkFree();<br />
lbLF.Caption := IntToStr(Count1);<br />
lbLFL.Caption := FloatToStrF(Count1 / SOCK_MAX_COUNT * 100, ffFixed, 10, 3) + '%';<br />
lbLU.Caption := FloatToStrF(GetLinkUse(), ffFixed, 10, 3) + '%';<br />
lbLS.Caption := IntToStr(GetLinkCount());<br />
end;<br />
procedure TfrmMainUTcpServerIOCP.FormDestroy(Sender: TObject);<br />
begin<br />
StopTcpServer();<br />
end;<br />
procedure TfrmMainUTcpServerIOCP.Timer2Timer(Sender: TObject);<br />
begin<br />
if not IsTcpServerActive() then<br />
begin<br />
Timer1.Enabled := False;<br />
exit;<br />
end;<br />
PostBroadcast(PByte(PChar('这是来自服务器的数据!')), 21);<br />
end;<br />
end.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/02/16/socket-iocp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

