DELPHI高性能大容量SOCKET并发(二):IOCP完成端口控件封装

[C++ 网络协议] IOCP(Input Output Completion Port) IOCP的介绍 阅读详情

IOCP完成端口介绍:

完成端口模型是Windows平台下SOCKET端口模型最为复杂的一种I/O模型。如果一个应用程序需要同时管理为数众多的套接字,而且希望随着系统内安装的CPU数量的增多,应用程序的性能也可以线性提升,采用完成端口模型,往往可以达到最佳的系统性能。

完成端口可以管理成千上万的连接,长连接传文件可以支持5000个以上,长连接命令交互可以支持20000个以上。这么大并发的连接,更需要考虑的是应用场景,按照100M的网卡传输速度12.5MB/S,如果是5000个传文件连接,则每个连接能分到的速度2.56KB/S;如果是20000个命令交互连接,则每个连接分到的吞吐量是655B/S,这种速度的吞吐量对很多应用是不满足,这时就要考虑加大网卡的传输速度或实现水平扩展,这个我们后续会介绍。

完成端口是由系统内核管理多个线程之间的切换,比外部实现线程池性能要高,CPU利用率上内核和用户态可以达到1:1,很多应用线程池是无法达到的。因此同等连接数的情况下,完成端口要比INDY的TCPServer传输速度要快,吞吐量更高。

要使用完成端口,主要是以下三个函数的使用:CreateIoCompletionPort、GetQueuedCompletionStatus、PostQueuedCompletionStatus。

CreateIoCompletionPort的功能是:1、创建一个完成端口对象;2、将一个句柄和完成端口关联在一起;GetQueuedCompletionStatus是获取完成端口状态,是阻塞式调用,在指定时间内如果没有事件通知,会一直等待;PostQueuedCompletionStatus用于向完成端口投递一个完成事件通知。

function CreateIoCompletionPort(FileHandle, ExistingCompletionPort: THandle; CompletionKey, NumberOfConcurrentThreads: DWORD): THandle; stdcall;NumberOfConcurrentThreads参数定义了在一个完成端口上,同时允许执行的线程数量。将NumberOfConcurrentThreads设为0表示每个处理器各自负责一个线程的运行,为完成端口提供服务,避免过于频繁的线程场景切换。因此可以使用下列语句来创建一个完成端口FIocpHandle := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);

执行线程个数

创建完成端口后,就可以将套接字句柄与对象关联在一起,这时就需要创建工作者线程,以便在完成端口收到数据后,为完成端口提供处理数据线程。到底创建多少个线程为完成端口服务,这个是完成端口最为复杂的一方面,创建多了线程会造成频繁的线程场景切换;创建少了线程如果某一个处理非常耗时,如连接数据库、读写文件,又会造成完成端口拥塞,因此这个参数需要提供设置,并根据最终的应用场景反复测试得出一个结果。一般的经验值是设置为CPU的个数*2+4;

IOCP完成端口一般使用步骤

1、创建一个完成端口;

2、判断系统内安装了多少个处理器;

3、创建工作者线程;

4、创建一个SOCKET套接字开始监听;

5、使用Accept接收连接;

6、调用CreateIoCompletionPort将连接和完成端口绑定在一起;

7、投递接收数据请求

8、工作者线程调用GetQueuedCompletionStatus获取事件通知,处理数据;

IOCP控件核心代码

第1步到第4步实现代码:

procedure TIocpServer.Open;
var
  WsaData: TWsaData;
  iNumberOfProcessors, i, iWorkThreadCount: Integer;
  WorkThread: TWorkThread;
  Addr: TSockAddr;
begin
  if WSAStartup($0202, WsaData) <> 0 then  //初始化SOCKET
    raise ESocketError.Create(GetLastWsaErrorStr);
  FIocpHandle := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);  //创建一个完成端口
  if FIocpHandle = 0 then
    raise ESocketError.Create(GetLastErrorStr);
  FSocket := WSASocket(PF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED); //创建一个SOCKET句柄
  if FSocket = INVALID_SOCKET then
    raise ESocketError.Create(GetLastWsaErrorStr);
  FillChar(Addr, SizeOf(Addr), 0);
  Addr.sin_family := AF_INET;
  Addr.sin_port := htons(FPort);
  Addr.sin_addr.S_addr := htonl(INADDR_ANY); //在任何地址上监听,如果有多块网卡,会每块都监听,也可以指定只监听某一个IP地址
  if bind(FSocket, @Addr, SizeOf(Addr)) <> 0 then //把SOCKET句柄绑定端口
    raise ESocketError.Create(GetLastWsaErrorStr);
  if listen(FSocket, MaxInt) <> 0 then 
     raise ESocketError.Create(GetLastWsaErrorStr);
  iNumberOfProcessors := GetCPUCount; //获取CPU个数
  iWorkThreadCount := iNumberOfProcessors * 2 + 4; //由于服务器处理可能比较费时间,因此线程设为CPU*2+4
  if iWorkThreadCount < FMinWorkThrCount then //限定最大工作者线程和最小工作者线程
    iWorkThreadCount := FMinWorkThrCount;
  if iWorkThreadCount > FMaxWorkThrCount then
    iWorkThreadCount := FMaxWorkThrCount;
  for i := 0 to iWorkThreadCount - 1 do //创建工作者线程
  begin
    WorkThread := TWorkThread.Create(Self, True);
    FWorkThreads.Add(WorkThread);
    WorkThread.Resume;
  end;
  FAcceptThreadPool.Active := True; //启动监听线程池
  FAcceptThread := TAcceptThread.Create(Self, True); //启动监听线程
  FAcceptThread.Resume;
end;
第5步和第6步实现代码:
procedure TIocpServer.AcceptClient;
var
  ClientSocket: TSocket;
begin
  ClientSocket := WSAAccept(FSocket, nil, nil, nil, 0); //接收连接
  if ClientSocket <> INVALID_SOCKET then
  begin
    if not FActive then
    begin
      closesocket(ClientSocket);
      Exit;
    end;
    FAcceptThreadPool.PostSocket(ClientSocket); //这里使用线程池主要作用是为了判断发送的第一个字节身份标识,用来是判断协议类型
  end;
end;
FAcceptThreadPool是一个用完成端口实现的线程池TIocpThreadPool,主要是有TCheckThread来判断完成端口的返回,并检测是否6S内有发送标志位上来,主要实现过程是响应OnConnect事件,并在OnConnect事件中判断是否允许连接。
procedure TIocpServer.CheckClient(const ASocket: TSocket);
var
  SocketHandle: TSocketHandle;
  iIndex: Integer;
  ClientSocket: PClientSocket;
begin
  SocketHandle := nil;
  if not DoConnect(ASocket, SocketHandle) then //如果不允许连接,则退出
  begin
    closesocket(ASocket);
    Exit;
  end;
  FSocketHandles.Lock; //加到列表中
  try
    iIndex := FSocketHandles.Add(SocketHandle);
    ClientSocket := FSocketHandles.Items[iIndex];
  finally
    FSocketHandles.UnLock;
  end;
  if CreateIoCompletionPort(ASocket, FIOCPHandle, DWORD(ClientSocket), 0) = 0 then //将连接和完成端口绑定在一起
  begin
    DoError('CreateIoCompletionPort', GetLastWsaErrorStr);
    FSocketHandles.Lock; //如果投递到列表中失败,则删除
    try
      FSocketHandles.Delete(iIndex);
    finally
      FSocketHandles.UnLock;
    end;
  end
  else
  begin
    SocketHandle.PreRecv(nil); //投递接收请求
  end;
end;

procedure TDMDispatchCenter.IcpSvrConnect(const ASocket: Cardinal;
  var AAllowConnect: Boolean; var SocketHandle: TSocketHandle);
var
  BaseSocket: TBaseSocket;
  chFlag: Char;

  function GetSocket(const AEnable: Boolean; BaseSocketClass: TBaseSocketClass): TBaseSocket;
  begin
    if AEnable then
      Result := BaseSocketClass.Create(IcpSvr, ASocket)
    else
      Result := nil;
  end;
begin
  if (GIniOptions.MaxSocketCount > 0) and (IcpSvr.SocketHandles.Count >= GIniOptions.MaxSocketCount) then
  begin
    AAllowConnect := False;
    Exit;
  end;
  if IcpSvr.ReadChar(ASocket, chFlag, 6*1000) then //必须在6S内收到标志
  begin
    case TSocketFlag(Byte(chFlag)) of
      sfSQL: BaseSocket := GetSocket(GIniOptions.SQLProtocol, TSQLSocket);
      sfUpload: BaseSocket := GetSocket(GIniOptions.UploadProtocol, TUploadSocket);
      sfDownload: BaseSocket := GetSocket(GIniOptions.DownloadProtocol, TDownloadSocket);
      sfControl: BaseSocket := GetSocket(GIniOptions.ControlProtocol, TControlSocket);
      sfLog: BaseSocket := GetSocket(GIniOptions.LogProtocol, TLogSocket);
    else
      BaseSocket := nil;;
    end;
    if BaseSocket <> nil then
    begin
      SocketHandle := BaseSocket;
      WriteLogMsg(ltDebug, Format('Client Connect, Local Address: %s:%d; Remote Address: %s:%d',
        [SocketHandle.LocalAddress, SocketHandle.LocalPort, SocketHandle.RemoteAddress, SocketHandle.RemotePort]));
      WriteLogMsg(ltDebug, Format('Client Count: %d', [IcpSvr.SocketHandles.Count + 1]));
      AAllowConnect := True;
    end
    else
      AAllowConnect := False;
  end
  else
    AAllowConnect := False;
end;
其中ReadChar函数是用于判断指定时间是否有数据上来,函数实现过程用Select函数检测:
function TIocpServer.ReadChar(const ASocket: TSocket; var AChar: Char; const ATimeOutMS: Integer): Boolean;
var
  iRead: Integer;
begin
  Result := CheckTimeOut(ASocket, ATimeOutMS);
  if Result then
  begin
    iRead := recv(ASocket, AChar, 1, 0);
    Result := iRead = 1; 
  end;
end;

function TIocpServer.CheckTimeOut(const ASocket: TSocket;
  const ATimeOutMS: Integer): Boolean;
var
  tmTo: TTimeVal;
  FDRead: TFDSet;
begin
  FillChar(FDRead, SizeOf(FDRead), 0);
  FDRead.fd_count := 1;
  FDRead.fd_array[0] := ASocket;
  tmTo.tv_sec := ATimeOutMS div 1000;
  tmTo.tv_usec := (ATimeOutMS mod 1000) * 1000;
  Result := Select(0, @FDRead, nil, nil, @tmTO) = 1;
end;
第7步实现代码

接收连接之后要投递接收数据请求,实现代码:

procedure TSocketHandle.PreRecv(AIocpRecord: PIocpRecord);
var
  iFlags, iTransfer: Cardinal;
  iErrCode: Integer;
begin
  if not Assigned(AIocpRecord) then
  begin
    New(AIocpRecord);
    AIocpRecord.WsaBuf.buf := @FIocpRecvBuf;
    AIocpRecord.WsaBuf.len := MAX_IOCPBUFSIZE;
    FIocpRecv := AIocpRecord;
  end;
  AIocpRecord.Overlapped.Internal := 0;
  AIocpRecord.Overlapped.InternalHigh := 0;
  AIocpRecord.Overlapped.Offset := 0;
  AIocpRecord.Overlapped.OffsetHigh := 0;
  AIocpRecord.Overlapped.hEvent := 0;
  //AIocpRecord.WsaBuf.buf := @FIocpRecvBuf;
  //AIocpRecord.WsaBuf.len := MAX_IOCPBUFSIZE;
  AIocpRecord.IocpOperate := ioRead;
  iFlags := 0;
  if WSARecv(FSocket, @AIocpRecord.WsaBuf, 1, iTransfer, iFlags, @AIocpRecord.Overlapped,
    nil) = SOCKET_ERROR then
  begin
    iErrCode := WSAGetLastError;
    if iErrCode = WSAECONNRESET then //客户端被关闭
      FConnected := False;
    if iErrCode <> ERROR_IO_PENDING then //不抛出异常,触发异常事件
    begin
      FIocpServer.DoError('WSARecv', GetLastWsaErrorStr);
      ProcessNetError(iErrCode);
    end;
  end;
end;
第8步实现代码:
function TIocpServer.WorkClient: Boolean;
var
  ClientSocket: PClientSocket;
  IocpRecord: PIocpRecord;
  iWorkCount: Cardinal;
begin
  IocpRecord := nil;
  iWorkCount := 0;
  ClientSocket := nil;
  Result := False;
  if not GetQueuedCompletionStatus(FIocpHandle, iWorkCount, DWORD(ClientSocket),
    POverlapped(IocpRecord), INFINITE) then //此处有可能多个线程处理同一个SocketHandle对象,因此需要加锁
  begin  //客户端异常断开
    if Assigned(ClientSocket) and Assigned(ClientSocket.SocketHandle) then
    begin
      ClientSocket.SocketHandle.FConnected := False;
      Exit;
    end;
  end;
  if Cardinal(IocpRecord) = SHUTDOWN_FLAG then
    Exit;
  if not FActive then
    Exit;
  Result := True;
  if Assigned(ClientSocket) and Assigned(ClientSocket.SocketHandle) then
  begin
    if ClientSocket.SocketHandle.Connected then
    begin
      if iWorkCount > 0 then
      begin
        try
          ClientSocket.Lock.Enter;
          try
            if Assigned(ClientSocket.SocketHandle) then
              ClientSocket.SocketHandle.ProcessIOComplete(IocpRecord, iWorkCount);
          finally
            ClientSocket.Lock.Leave;
          end;
          if Assigned(ClientSocket.SocketHandle) and (not ClientSocket.SocketHandle.Connected) then
          begin
            ClientSocket.Lock.Enter;
            try
              if Assigned(ClientSocket.SocketHandle) then
                FreeSocketHandle(ClientSocket.SocketHandle);
            finally
              ClientSocket.Lock.Leave;
            end;
          end;
        except
          on E: Exception do
            DoError('ProcessIOComplete', E.Message);
        end;
      end
      else //如果完成个数为0,且状态为接收,则释放连接
      begin
        if IocpRecord.IocpOperate = ioRead then
        begin
          ClientSocket.Lock.Enter;
          try
            if Assigned(ClientSocket.SocketHandle) then
              FreeSocketHandle(ClientSocket.SocketHandle);
          finally
            ClientSocket.Lock.Leave;
          end;
        end
        else
          DoError('WorkClient', 'WorkCount = 0, Code: ' + IntToStr(GetLastError) + ', Message: ' + GetLastErrorStr);
      end;
    end
    else //断开连接
    begin
      ClientSocket.Lock.Enter;
      try
        if Assigned(ClientSocket.SocketHandle) then
          FreeSocketHandle(ClientSocket.SocketHandle);
      finally
        ClientSocket.Lock.Leave;
      end;
    end;
  end
  else //WorkCount为0表示发生了异常,记录日志
    DoError('GetQueuedCompletionStatus', 'Return SocketHandle nil');
end;
第8步主要是使用GetQueuedCompletionStatus函数来获取完成端口事件通知,如果有事件完成,则可以通过lpCompletionKey来知道是哪个句柄有数据收到。

这里有个技巧是我们在绑定的时候使用如下语句:CreateIoCompletionPort(ASocket, FIOCPHandle, DWORD(ClientSocket), 0),用lpCompletionKey来传递了一个指针,这其中就包含了一个锁和服务对象,定义结构如下:

{* 客户端对象和锁 *}
  TClientSocket = record
    Lock: TCriticalSection;
    SocketHandle: TSocketHandle;
  end;
  PClientSocket = ^TClientSocket;
因而我们在收到事件通知后,就可以直接调用TSocketHandle对象来完成分包解包以及后续的逻辑处理。
这样一个完成端口的整体骨架就有了,后续还有收发数据、分包解包和业务逻辑处理,以及对象和锁分离等细节处理。更详细代码见示例代码的IOCPSocket单元。

V1版下载地址:http://download.youkuaiyun.com/detail/sqldebug_fan/4510076,需要资源10分,有稳定性问题,可以作为研究稳定性用;

V2版下载地址:http://download.youkuaiyun.com/detail/sqldebug_fan/5560185,不需要资源分,解决了稳定性问题和提高性能;免责声明:此代码只是为了演示IOCP编程,仅用于学习和研究,切勿用于商业用途。水平有限,错误在所难免,欢迎指正和指导。邮箱地址:fansheng_hx@163.com


DELPHI高性能大容量SOCKET并发(九):稳定性问题解决 IOCP接收缓存导致的内存错乱 在用IOCP控件写了一个ERP服务器后,服务器会发生运行3天后,出现莫名的内存错误,用FastMM检测,是本没有内存错误的地方,而且内存错误出现的地方也不固定。这是一个不可重现的Bug,后续通过打日志把错误范围缩小后发现,每次出现内存错误之前都是由于有链接断开释放,因此就加了日志逐步定位到是TSocketHandle释放引起的,具体原因是:在IOCP中,每个S 阅读详情

相关推荐

Delphi IOCP端口通信实例.rar

该源码是Delphi7写的一个IOCP简单例子,主要是演示IOCP的应用基础,以及帮助大家理解IOCP,便于初学者学习和理解IOCP到底是怎么一回事,是怎么实现网络通信的。 主程序由客户端和服务端组成,服务端完成端口操作定义、消息接收发送、建立通信通道等,相关定义可看代码:   TIocpOperate = (ioNone, ioCon, ioRead, ioWrite, ioStream, ioExit);   PIocpRecord = ^TIocpRecord;   TIocpRecord = record   Overlapped: TOverlapped; //完成ICOP端口重叠结构   WsaBuf: TWsaBuf; //完成端口的缓冲区定义   IocpOperate: TIOCPOperate; //当前操作类型   客户端就简单了,主要是连接服务端,建立通信,发消息等。

IOCP技术详解

这几周我接触了Windows网络通讯中的IOCP模型,自己在网上找了相关的知识进行学习,自己又下了好多服务器端的代码,但都运行不了,也是自己菜,能力还需加强。幸好我师父资助了我一个能运行的服务端IOCP代码,自己参照网上的相关知识后又与这个能运行的代码做了参照,算是勉强理解了构造IOCP的一般方法,对IOCP的使用也有了很大的心得。接下来我就把自己对IOCP相关知识的理解记录下来,方便自己以后的复习,当然这篇文章如果对正在阅读的你有帮助也算是很好的。...

StarWang的博客 5795

DELPHI diocp通讯框架双向通讯

DELPHI diocp通讯框架双向通讯 可以做聊天软件等操作 操作方法:https://blog.youkuaiyun.com/z123191456/article/details/88546978

【网络】IO多路复用之IOCP

IOCP(Input/Output Completion Ports,输入输出完成端口)是Windows操作系统中一种高效的网络和文件I/O处理机制。它允许应用程序以异步方式处理多个I/O操作,同时能够减少线程的使用和提高系统的可扩展性。

abclui的专栏 2435

DELPHI版IOCP完整源码及实例

DELPHI版IOCP完整源码及实例,源码均有详细的中文说明。

【电驱动】永磁同步电机工作原理及分类

永磁同步电机工作原理及分类

星Yeah 的博客 7323

DELPHI高性能大容量SOCKET并发(一):IOCP完成端口例子介绍

例子主要包括IOCP控件封装、服务端实现、传输协议和日志、控制、SQL查询、上传、下载等协议实现,并包括一些初步的性能测试结果。 服务端: 界面截图如下: 提供服务和桌面方式运行,桌面方式可直接打开程序,方便日常调试,可以使用命令行注册或卸载服务,在CMD中输入D:\DEMO\IOCPDemo\Bin\IOCPDemoSvr.exe -install来注册服务,在CMD输入D:\DE

SQLDebug_Fan的专栏 3万+

实战篇(一):从零构建领域知识图谱——基于Protege的本体建模与知识表示

本文详细介绍了如何从零构建领域知识图谱,重点讲解了基于Protege的本体建模与知识表示方法。通过游戏和电影领域的实战案例,展示了类层次结构设计、属性关系定义、推理验证等关键步骤,帮助读者掌握知识图谱构建的核心技术。

weixin_42613501的博客 481

高性能大容量SOCKET并发(二):IOCP完成端口控件封装

http://blog.youkuaiyun.com/sqldebug_fan/article/details/7884239 IOCP完成端口介绍: 完成端口模型是Windows平台下SOCKET端口模型最为复杂的一种I/O模型。如果一个应用程序需要同时管理为数众多的套接字,而且希望随着系统内安装的CPU数量的增多,应用程序的性能也可以线性提升,采用完成端口模型,往往可以达到最佳的系统性能。 完成

l799623787的专栏 1155

XGBoost算法案例 - 红酒品质分类

数据集共包含 11 个特征,共计 3269 条数据. 我们通过训练模型来预测红酒的品质, 品质共有 6 个各类别,分别使用数字: 0、1、2、3、4、5 来表示。

YIAN爱学习的博客 449

Android 12 HAL开发避坑实录:手把手教你用AIDL在Native层实现一个可开机自启动的Service

本文详细介绍了在Android 12 HAL开发中,如何通过AIDL在Native层实现一个可开机自启动的Service。从环境准备、AIDL接口定义、服务实现到VINTF集成与SELinux策略配置,提供了完整的实战指南,帮助开发者避开常见陷阱,提升开发效率。

weixin_28314575的博客 321

DELPHI高性能大容量SOCKET并发:IOCP完成端口例子介绍

文章来源:http://blog.youkuaiyun.com/sqldebug_fan/article/details/7881793 例子主要包括IOCP控件封装、服务端实现、传输协议和日志、控制、SQL查询、上传、下载等协议实现,并包括一些初步的性能测试结果。 服务端: 界面截图如下: 提供服务和桌面方式运行,桌面方式可直接打开程序,方便日常调试,可以使用命令行注册或

$firecat利白的代码足迹$ 3393

MCNP 减方差技巧(最全)

MCNP的减方差技巧,核心在于不显著增加计算时间的前提下,通过修改模拟过程来降低结果的统计误差。尤其适用于,这类问题中粒子很难到达探测器区域,直接模拟效率极低栅元重要性是常用的减方差技巧,该方法主要对计算模型的不同区域定义不同的重要性数值。当粒子从重要性低的区域废物重要性高的区域,产生更多粒子,增大统计量;当从重要性高的区域进入重要性低的区域,会进行,增快计算效率。n= 中子,N;光子,P;电子 Exi= 栅元i的重要性I=栅元总数项目IMP卡是必须的,除非使用了WWN卡如果粒子进入0。

chencheng1127的博客 925

Windows下的IOCP模型(一):介绍与简单使用

一、IOCP简介 IOCP(I/O Completion Port,I/O完成端口)是Windows操作系统中伸缩性最好的一种I/O模型。     I/O完成端口是应用程序使用线程池处理异步I/O请求的一种机制。处理多个并发异步I/O请求时,使用I/O完成端口比在I/O请求时创建线程更快更高效。 二、IOCP的优势     I/O完成端口可以充分利用Windows内核来进行I/O调度,相较于传统的Winsock模型,IOCP在机制上有明显的优势。 模型 机制 特性 select模型 通过

Summer_night_star的博客 1万+

云架构师进阶【SAP迁移方案设计】手把手教您玩转SAP上云

一,项目背景介绍 今天又接到了北京某制造企业SAP迁移的场景,先简单说明一下,好好的SAP在运行着为什么要做迁移这类大动作呢?众所周知SAP的ERP是企业的绝对核心系统,尤其对于制造业更是核心的系统,这样一套核心系统还是生产环境在迁移的过程中必然要面临比较大的挑战,如果有任何问题的话,都会对企业的绩效产生很大的影响。 经过跟客户沟通才得知,客户的SAP原来的系统是托管在运营商机房里,近期感染了勒索病毒,导致业务宕机,SAP应用服务器无法启动,仅有的数据库服务器可以运行。基于上述情况公司领导当机立断决定迅

bdsh818的博客 4220

Flow Match 原理 及应用

Flow Matching(流匹配)是生成模型的范式革命——用确定性ODE替代随机扩散过程,在自动驾驶轨迹预测中实现10倍采样加速和更高生成质量。更快的采样速度:通常只需 10-50 步就能生成高质量样本更稳定的训练:避免了传统扩散模型中复杂的噪声调度理论基础:基于连续正规化流(Continuous Normalizing Flows)核心思想:Flow Matching 通过学习一个 向量场(vector field) 来直接建模从噪声分布到目标分布的连续变换路径。

@bangbang的博客 98

IOCP 从初学者角度最简化的说明(delphi示例)

IOCP最简化说明 IOCP越说越复杂,我想尝试简明的从初学者的概念来说明,把最迷惑的部分简要说明: 关键点一:完全IO端口返回的消息,是系统保存在队列里的!不是直接给你返回!因为需要够快,所以建立完全端口后,完全端口自己会处理完所以连接、接收的动作,并把处理好的消息保存到队列里!它不管你需不需要,只要合法的都存好!所以我们关键的动作也就是要从队列去消息出来处理! 关键点二:它的关键函数:到队列去取数据的函数,它是阻塞式的。你执行了这个函数,如果队列里没有消息,它会停住等到有消息之后才往下走(当然..

m0_60908963的博客 933

雷达参数的设置

采样率又可以叫做采样速率或者,顾名思义就是每秒采集的次数。该值越高,单位时间内对信号的采集越多,采样率的单位可以用Hz或者sps表示(sps是采样率,是每秒采样点的数量,sp表示采样点数),一般1sps=1Hz。采样时间是采样点数和采样周期的乘积得到的结果。假设实际采样率为4560ksps,采样点数为256,那么采样周期为1/4560(ms),那么ADC的采样时间就为256*(1/4560)(ms)=0.056ms=56微秒。

qq_50974341的博客 1912

什么是IOCP

关于什么是IOCP的描述

weixin_40301728的博客 4255

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

IOCP简单了解

IOCP是Input/Output Completion Ports的简称,中文翻译为完成端口,完成是应用程序向系统发起一个IO操作,系统会在操作结束后,将IO操作完成结果通知应用程序,端口指的是机制。

m0_46486963的博客 1183

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

IOCP 完成端口的最简说明 - 附DELPHI源码

IOCP 完成端口最简说明 IOCP越说越复杂,我想尝试简明的从初学者的概念来说明,把最迷惑的部分简要说明: 关键点一:完成IO端口返回的消息,系统会自动保存在队列里!不是触发或者立刻返回!因为服务器需要快,所以完成端口自己先把处理好的消息全部保存到队列里!它不管你现在干嘛,只要合法的它都帮你存好!用不用你取出来再判断!所以我们关键的动作是从完成端口的队列去把消息取出来并处理! 关键点二:它的关键函数:到队列去取数据的函数,它是阻塞式的。你执行了这个函数,如果队列里没有消息,它会停住等到有消息..

m0_60908963的博客 946

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

c++——iocp模型

IOCP有一个队列,当你要发数据时,收数据和连接时,都交由IOCP队列处理,不会与操作系统底层交互。  该函数实际用于两个明显有别的目的: 5.4.3 向IOCP队列投递接受连接的请求 5.4.4 检测队列,从队列中取出完成的请求 5.4.5 投递一个队列完成状态 6. 示例 服务端 客户端...

www_dong的博客 5667

DELPHI高性能大容量SOCKET并发(十):IOCP完成端口性能优化

IOCP性能优化主要是集中在每个处理接收数据和发送数据的对象锁,如果能降低锁的调用次数和提高锁的效率,对IOCP的整理效率和吞吐量都非常有帮助。有很多开发人员在优化IOCP的时候,对于如何提高锁的效率,有使用原子操作来加锁,这样做的效率比较调用Windows的锁效率,因而吞吐率也更高。我们不讨论提高锁的效率,我们这次的优化是降低锁的调用次数。 服务端优化 IOCP是异步线程通知方式,有

SQLDebug_Fan的专栏 9931

DELPHI Winsock完成端口[转]

用DELPHI开发网络代码已经有一段时间了!我发现在网上用VC来实现完成端口(IOCP)的代码很多,但是使用DELPHI来实现的就比较少了。对IOCP讲的清楚的就更少了。在这里我把自己编写DELPHI下的IOCP写出来,希望对刚学完成端口的朋友有个帮助。首先我们来了解一些在使用IOCP的时候需要使用的一些结构!(1):单IO数据结构 LPVOID = Pointer; LPPER_IO_OPE...

weixin_30492601的博客 299

网络编程:IOCP与异步IO模型深度解析

IOCP(I/O Completion Port)是Windows操作系统提供的一种高效处理异步I/O请求的机制,它通过预分配的线程池和完成事件通知来提升多处理器系统上的I/O处理效率。与Linux中的Reactor模型不同,IOCP模型将I/O检测和操作都交由内核完成,用户线程只需等待完成通知。

平平无奇的小甜菜 1378

深入剖析IOCP:从原理到实践

IOCP(Input/Output Completion Ports,输入/输出完成端口)是Windows操作系统中一种用于处理高效异步I/O操作的机制。它广泛应用于服务器端应用程序,如Web服务器和数据库服务器,能够有效处理大量的并发I/O请求。

人心有反复,好在山水有重逢。 2213
上一篇: DELPHI高性能大容量SOCKET并发(一):IOCP完成端口例子介绍
下一篇: DELPHI高性能大容量SOCKET并发(三):接收、发送、缓存
SQLDebug_Fan
博客等级 码龄17年 710粉丝 26原创
评论 18
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值