DIOCP开源项目出炉,附带<IOCP退出资源的管控研究代码>

简介: 经过对一段时间对IOCP的学习和研究。对IOCP的流程有了一定的了解。 后面对一段时间的IOCP优化和实际项目的使用,在DIOCP中加入了日志文件记录功能,利用api编写了一个客户端通信类,等解决了很多bug,并已使用在公司的项目中,现运行稳定。

经过对一段时间对IOCP的学习和研究。对IOCP的流程有了一定的了解。

后面对一段时间的IOCP优化和实际项目的使用,在DIOCP中加入了日志文件记录功能,利用api编写了一个客户端通信类,等解决了很多bug,并已使用在公司的项目中,现运行稳定。今天对IOCP退出时资源的释放,做了最后一步研究和优化。

 

 

为了方便大家学习,我把这个项目命名为DIOCP,上传在google的SVN项目中

https://code.google.com/p/diocp/

大家可以通过svn下载代码,里面我写了一个Echo的测试Demo,准备后续加入聊天等Demo。

特地为DIOCP开设了一个群:320641073,欢迎学习的IOCP的童鞋进入讨论。

--IOCP退出资源的管控研究

现在在项目中使用的IOCP退出的过程是。

procedure TIOCPConsole.close;
begin
  //关闭服务端端口
  FIOCPObject.closeSSocket;

  //停止监听
  stopListener;

  //断开所有连接
  FIOCPObject.DisconnectAllClientContext;

  //等待资源的回归
  FIOCPObject.WaiteForResGiveBack;

  //停止工作线程
  stopWorkers;

  //标志状态
  FActive := false;
end;

 

 

对IO内存池也进行了一些优化,主要加入了资源回归的监控 

unit uMemPool;

interface

uses
  JwaWinsock2, Windows, SyncObjs, uIOCPProtocol;


type
  TIODataMemPool = class(TObject)
  private
    //全部归还的信号灯
    FCanCloseSingle: THandle;

    FCs: TCriticalSection;

    //第一个可用的内存块
    FHead: POVERLAPPEDEx;

    //最后一个可用的内存卡
    FTail: POVERLAPPEDEx;

    //可用的内存个数
    FUseableCount:Integer;

    //正在使用的个数
    FUsingCount:Integer;

    /// <summary>
    ///   将一个内存块添加到尾部
    /// </summary>
    /// <param name="pvIOData"> (POVERLAPPEDEx) </param>
    procedure AddData2Pool(pvIOData:POVERLAPPEDEx);

    /// <summary>
    ///   得到一块可以使用的内存
    /// </summary>
    /// <returns> POVERLAPPEDEx
    /// </returns>
    function getUsableData: POVERLAPPEDEx;

    /// <summary>
    ///   创建一块内存空间
    /// </summary>
    /// <returns> POVERLAPPEDEx
    /// </returns>
    function InnerCreateIOData: POVERLAPPEDEx;

    procedure clearMemBlock(pvIOData:POVERLAPPEDEx);

    //释放所有的内存块
    procedure FreeAllBlock;
  public
    class function instance: TIODataMemPool;
    constructor Create;
    destructor Destroy; override;

    function waiteForGiveBack: Boolean;

    //借一块内存
    function borrowIOData: POVERLAPPEDEx;

    //换会一块内存
    procedure giveBackIOData(const pvIOData: POVERLAPPEDEx);

    function getCount: Cardinal;
    function getUseableCount: Cardinal;
    function getUsingCount:Cardinal;

  end;

implementation

uses
  uIOCPFileLogger;

var
  __IODATA_instance:TIODataMemPool;

constructor TIODataMemPool.Create;
begin
  inherited Create;
  FCs := TCriticalSection.Create();
  FUseableCount := 0;
  FUsingCount := 0;
  FCanCloseSingle := CreateEvent(nil, True, True, nil);
end;

destructor TIODataMemPool.Destroy;
begin
  CloseHandle(FCanCloseSingle);
  FreeAllBlock;
  FCs.Free;
  inherited Destroy;
end;

{ TIODataMemPool }

procedure TIODataMemPool.AddData2Pool(pvIOData:POVERLAPPEDEx);
begin
  if FHead = nil then
  begin
    FHead := pvIOData;
    FHead.next := nil;
    FHead.pre := nil;
    FTail := pvIOData;
  end else
  begin
    FTail.next := pvIOData;
    pvIOData.pre := FTail;
    FTail := pvIOData;
  end;
  Inc(FUseableCount);
end;

function TIODataMemPool.InnerCreateIOData: POVERLAPPEDEx;
begin
  Result := POVERLAPPEDEx(GlobalAlloc(GPTR, sizeof(OVERLAPPEDEx)));

  GetMem(Result.DataBuf.buf, MAX_OVERLAPPEDEx_BUFFER_SIZE);

  Result.DataBuf.len := MAX_OVERLAPPEDEx_BUFFER_SIZE;

  //清理一块内存
  clearMemBlock(Result);
end;

function TIODataMemPool.borrowIOData: POVERLAPPEDEx;
begin
  FCs.Enter;
  try
    Result := getUsableData;
    if Result = nil then
    begin
      //生产一个内存块
      Result := InnerCreateIOData;

      //直接借走<增加使用计数器>
      Inc(FUsingCount);
    end;

    //变成没有信号
    if FUsingCount > 0 then
      ResetEvent(FCanCloseSingle);

  finally
    FCs.Leave;
  end;
end;

procedure TIODataMemPool.clearMemBlock(pvIOData: POVERLAPPEDEx);
begin
  //清理一块内存
  pvIOData.IO_TYPE := 0;

  pvIOData.WorkBytes := 0;
  pvIOData.WorkFlag := 0;

  //ZeroMemory(@pvIOData.Overlapped, sizeof(OVERLAPPED));

  //还原大小<分配时的大小>
  pvIOData.DataBuf.len := MAX_OVERLAPPEDEx_BUFFER_SIZE;

  //ZeroMemory(pvIOData.DataBuf.buf, pvIOData.DataBuf.len);
end;

procedure TIODataMemPool.FreeAllBlock;
var
  lvNext, lvData:POVERLAPPEDEx;
begin
  lvData := FHead;
  while lvData <> nil do
  begin
    //记录下一个
    lvNext := lvData.next;

    //释放当前Data
    FreeMem(lvData.DataBuf.buf, lvData.DataBuf.len);
    GlobalFree(Cardinal(lvData));

    //准备释放下一个
    lvData := lvNext;
  end;

  FHead := nil;
  FTail := nil;

  FUsingCount := 0;
  FUseableCount := 0; 

end;

function TIODataMemPool.getCount: Cardinal;
begin
  Result := FUseableCount + FUsingCount;
end;

procedure TIODataMemPool.giveBackIOData(const pvIOData:
    POVERLAPPEDEx);
begin
  FCs.Enter;
  try
    if (pvIOData.pre <> nil) or (pvIOData.next <> nil) or (pvIOData = FHead) then
    begin
      TIOCPFileLogger.logErrMessage('回收内存块是出现了异常,该内存块已经回收!');

    end else
    begin
      //清理内存块
      clearMemBlock(pvIOData);

      //加入到可以使用的内存空间
      AddData2Pool(pvIOData);

      //减少使用计数器
      Dec(FUsingCount);
    end;

    //有信号
    if FUsingCount = 0 then SetEvent(FCanCloseSingle);
  finally
    FCs.Leave;
  end;
end;

function TIODataMemPool.getUsableData: POVERLAPPEDEx;
var
  lvPre:POVERLAPPEDEx;
begin
  if FTail = nil then
  begin
    Result := nil;
  end else  
  begin   
    Result := FTail;

    lvPre := FTail.pre;
    if lvPre <> nil then
    begin
      lvPre.next := nil;
      FTail := lvPre;
    end else  //FTail是第一个也是最后一个,只有一个
    begin
      FHead := nil;
      FTail := nil;
    end;  

    Result.next := nil;
    Result.pre := nil;

    Dec(FUseableCount);
    Inc(FUsingCount);
  end;
end;

function TIODataMemPool.getUseableCount: Cardinal;
begin
  Result := FUseableCount;
end;

function TIODataMemPool.getUsingCount: Cardinal;
begin
  Result := FUsingCount;
end;

class function TIODataMemPool.instance: TIODataMemPool;
begin
  Result := __IODATA_instance;
end;

function TIODataMemPool.waiteForGiveBack: Boolean;
var
  lvRet:DWORD;
begin
  Result := false;
  lvRet := WaitForSingleObject(FCanCloseSingle, INFINITE);
  if lvRet = WAIT_OBJECT_0 then
  begin
    Result := true;
  end;
end;


initialization
  __IODATA_instance := TIODataMemPool.Create;

finalization
  if __IODATA_instance <> nil then
  begin
    __IODATA_instance.Free;
    __IODATA_instance := nil;
  end;

end.

 

目录
相关文章
|
4月前
|
数据处理 Kotlin
掌握这项Kotlin技能,让你的数据流管理不再头疼!Flow的秘密你解锁了吗?
【9月更文挑战第12天】随着移动应用发展,数据流管理日益复杂。Kotlin Flow作为一种基于协程的异步数据流处理框架应运而生,它可解耦数据的生产和消费过程,简化数据流管理,并支持背压机制以防应用崩溃。本文通过四个问题解析Kotlin Flow的基础概念、创建方式、复杂数据流处理及背压实现方法,助您轻松掌握这一高效工具,在实际开发中更从容地应对各种数据流挑战,提升应用性能。
64 8
|
4月前
|
消息中间件 数据采集 数据库
庆祝吧!Python IPC让进程间的合作,比团队游戏还默契
【9月更文挑战第7天】在这个数字化时代,软件系统日益复杂,单进程已难以高效处理海量数据。Python IPC(进程间通信)技术应运而生,使多进程协作如同训练有素的电竞战队般默契。通过`multiprocessing`模块中的Pipe等功能,进程间可以直接传递数据,无需依赖低效的文件共享或数据库读写。此外,Python IPC还提供了消息队列、共享内存和套接字等多种机制,适用于不同场景,使进程间的合作更加高效、精准。这一技术革新让开发者能轻松应对复杂挑战,构建更健壮的软件系统。
48 1
|
4月前
|
消息中间件 安全 数据库
动手实操!Python IPC机制,打造高效协同的进程军团
【9月更文挑战第10天】在软件开发领域,进程间的高效协作对应用性能与稳定性至关重要。Python提供了多种进程间通信(IPC)机制,如管道、消息队列、套接字、共享内存等,帮助开发者构建高效协同的系统。本文将通过动手实践,使用`multiprocessing`模块演示如何利用队列实现进程间通信。示例代码展示了如何创建一个工作进程从队列接收并处理数据,从而实现安全高效的进程交互。通过实际操作,读者可以深入了解Python IPC的强大功能,提升系统的并发处理能力。
64 0
|
6月前
|
人工智能 程序员
|
6月前
|
数据库连接 数据库 Python
Python 大神教你一招鲜:自定义上下文管理器,让资源管理变得如此轻松惬意🍵
【7月更文挑战第3天】在Python中,自定义上下文管理器是高效资源管理的关键,它们确保了如文件和数据库连接等资源的正确打开和关闭。通过`__enter__`和`__exit__`方法,可以创建简洁的代码,避免冗余的异常处理。例如,自定义的`DatabaseConnectionManager`和`FileManager`类使得数据库操作和文件读取更整洁,使用`with`语句自动处理资源生命周期,提升代码可读性和可靠性。
52 0
|
SQL 敏捷开发 监控
好文赏析:一文读懂运行时应用程序自我保护(RASP)
RASP作为一种新型的、有效的、实时的应用保护手段,正被越来越多的企业使用,本文用浅显易懂的文字讲解了RASP技术、RASP与WAF的关系,并提供了应用解决方案,快来阅读吧~
406 0
|
Linux 调度 开发者
Linux系统编程第五节——进程创建、终止、等待(通俗易懂快速上手版本)
关于非阻塞式等待的用法,我们可以使用轮回询问的方式,即使用循环的方式,不断的询问子进程此时是否退出。而非阻塞式的等待使得父进程在子进程运行时,自己可以不用傻傻的等着,也可以做自己的事情。
284 0
Linux系统编程第五节——进程创建、终止、等待(通俗易懂快速上手版本)
|
域名解析 前端开发 程序员
一键托管程序员的做菜神器,隔离食用手册--5
一键托管程序员的做菜神器,隔离食用手册--5
155 0
|
程序员
一键托管程序员的做菜神器,隔离食用手册---2
一键托管程序员的做菜神器,隔离食用手册---2
132 0
|
域名解析 前端开发 程序员
一键托管程序员的做菜神器,隔离食用手册--4
一键托管程序员的做菜神器,隔离食用手册--4
116 0