Lazarus中文社区

 找回密码
 立即注册(注册审核可向QQ群索取)

QQ登录

只需一步,快速开始

版权申明
查看: 5157|回复: 3

完成端口-Delphi应用(1)

[复制链接]

该用户从未签到

发表于 2010-3-13 07:27:03 | 显示全部楼层 |阅读模式
{*******************************************************}
{定义重叠IO的结构体和IO池,便于大量收发并行处理}
{*******************************************************}

unit u_iocp;

interface
 uses Windows,winsock2,WinSock,Classes,SysUtils,ComCtrls,Contnrs,u_wimp_def,
 u_imgComm,u_Share_RingBuffer;

//==============================================================================
// 定义完成端口的重叠IO数据结构
//==============================================================================
const
  DATABUF_MAXSIZE    = 4096; //包最大长度
  BUF_HEADSIZE       = 6;    //包头长度
  MAX_DESTADDR       = 10;  //最大同时操作客户端数量

Const
  APP_OPERTYPE_RECV  =  1;   //接收操作
  APP_OPERTYPE_SEND  =  2;   //发送操作
  APP_OPERTYPE_POST  =  3;   //Post操作,是一个socket给另一个socket转发但还没有发出的
  APP_OPERTYPE_CLOSE =  4;   //关闭socket资源

const
  APP_NODEICON_CS         = 0;  //系统根节点图标索引
  APP_NODEICON_FE_ONLINE  = 1;  //节点图标前端设备上线索引
  APP_NODEICON_FE_OFFLINE = 2;  //节点图标前端设备下线索引
  APP_NODEICON_SECTION    = 3;  //节点图标分区索引
  APP_NODEICON_MS_ONLINE  = 4;  //节点图标监控主机上线索引
  APP_NODEICON_MS_OFFLINE = 5;  //节点图标监控主机下线索引
  APP_NODEICON_RC_ONLINE  = 6;  //节点图标远程客户端上线索引
  APP_NODEICON_RC_OFFLINE = 7;  //节点图标远程客户端下线索引

type

  PTreeNodeInfo = ^TtreeNodeInfo;
  TtreeNodeInfo= packed record
    NodeType : Byte;     //节点类型
    Item     : Pointer;  //节点信息指针
  end;

type
  {需要缓冲在完成端口关联的Socket发送列表中的对象}
  TSendObject = class
      public
         SrcSocket : TSocket;
         DstSocket : TSocket;
         Buf       : array[0..DATABUF_MAXSIZE - 1] of Char;
         Len       : Integer;
  end;
 
const
  //工作状态
  WK_NONE      = 0;
  WK_CONNECTED = 1;
  WK_RUNNING   = 2;
  WK_CLOSE     = 3;
  WK_IMGTRANS  = 4;

type
   EMemoryBuffer = class(Exception);
   TMemoryBuffer = class;

   //视频相关定义
   LPImgHandleData = ^PerImgHandelData;
   PerImgHandelData = packed record
        Socket :TSocket;
        Logintype:integer;                                     //登录类型 0 = 底层终端  1=上层主机
        Source_Addr : string[7];
        Dest_Client : TThreadList;                              //图像接收端地址列表,仅仅前端设备有此项
        Img_Client  : LPImgHandleData;                          //图片文件收发客户端
        ConnectTime : TDateTime;                                //当前连接时间
        WorkState  : Byte;                                      //工作状态
        MEDIA_VEDIO_AUDIO:TSP_MEDIA_VEDIO_AUDIO;                //音视频参数
        MemoryBuffer:TMemoryBuffer; //结构体和内存池
        RingBuffer:TRingBuffer;  //环形缓冲
        isCompletePac:Boolean;
        RevBuffer: array [0..DATABUF_MAXSIZE - 1] of Byte;
        isCloseFree:Boolean; //是否释放
   end;

   LPImgIOData = ^TImgIOData;
   TImgIOData = packed record
        Overlapped   : OVERLAPPED;                              //完成端口的重叠IO结构
        WSABuffer    : TWSABUF;
        OperType     : Byte;                                    //上次命令完成的类型 0:接收 1:发送
        IsUse: Boolean;
        Buffer: array [0..DATABUF_MAXSIZE - 1] of Byte;
    end;

  PBlock = ^TBlock;
  TBlock = packed record //相当于一个PBLOCK开辟的内存块=4096+n个字节
    Data: TImgIOData;
    IsUse: Boolean;
  end;

  TMemoryBuffer = class
  private
    FList: TList;
    FLock: TRTLCriticalSection;
    function GetCount: Integer;
    function GetBlock(const Index: Integer): PBlock;
  protected
    property Count: Integer read GetCount;
    property Blocks[const Index: Integer]: PBlock read GetBlock;
  public
    constructor Create(); overload;
    constructor Create(BlockCount: Integer); overload;
    destructor Destroy; override;
    function AllocBlock: PBlock;
    procedure RemoveBlock(Block: PBlock);
  end;

  LPPerHandelData = ^PerHandelData;

  {完成键需要关联的句柄(CompletKey),由此判断是由哪个Socket关联的数据}
  PerHandelData = packed record
      Socket: TSocket;                                        //保留接入的客户端socket句柄
      OperType     : Byte;                                    //上次命令完成的类型 0:接收 1:发送
      PDstAlarmCount: Byte;                           //报警目标地址数量
      PDstAddrs:array[0..MAX_DESTADDR] of String[7];  //目标地址列表
      PRoutors:array[0..MAX_DESTADDR] of TSocket;     //当该链路的报警信息到,转发的目标路由列表,最多定义两个
      PItemPt:TTreeNode;                   //指向原地址树状元素的指针
      PSrcSectionID:Integer;               //原地址所在分区号
      PSrcType : Byte;                     //原地址接入类型 1:前端登录类型  2:远程用户端登录 3:监控主机登录
      PSrcAddr : string[7];                //原设备地址
      PSrcName:string[20];                 //原地址的名称
      MemoryBuffer:TMemoryBuffer; //结构体和内存池
      RingBuffer:TRingBuffer;  //环形缓冲
  end;

  {心跳计数类型}
  TCounterObject = class
      PerHandelData     : LPPerHandelData; //设备TCP链路指针
      SrcAddr           : String[7];       //设备地址
      FTimeOut          : ShortInt;        //已经超时的秒数 <=60 秒
      FTimeOutCn        : ShortInt;        //已经超时的次数 <=3 次
      isTimOut          : Boolean;         //是否已经超时
  end;

Const
    DEFAULTBLOCKCN = 100;
    BlockSize: Word = SizeOf(TBlock);
implementation

constructor TMemoryBuffer.Create();
begin
  Create(DEFAULTBLOCKCN);
end;

constructor TMemoryBuffer.Create(BlockCount: Integer);
var
  I: Integer;
  P: PBlock;
begin
  inherited Create;
  InitializeCriticalSection(FLock);
  FList := TList.Create;
  for I := 0 to BlockCount - 1 do
  begin
    New(P);
    FillChar(P^, BlockSize, 0);
    FList.Add(P);
  end;
end;    

destructor TMemoryBuffer.Destroy;
var
  I: Integer;
begin
  try
    EnterCriticalSection(FLock);

    for I := FList.Count - 1 downto 0  do
      FreeMem(FList[I]);
    FList.Free;
  finally
    LeaveCriticalSection(FLock);
    DeleteCriticalSection(FLock);
  end;
  inherited Destroy;
end;

function TMemoryBuffer.AllocBlock: PBlock;
var
  I: Integer;
begin
  EnterCriticalSection(FLock);
  try
    Result := nil;
    //FList.Pack;
    for I := FList.Count - 1 downto 0 do
    begin
      Result := FList[I];
      if not Result.IsUse then
        break;
    end;
    if not Assigned(Result) or Result.IsUse then
    begin
      New(Result);
      FList.Add(Result);
    end;
    FillChar(Result^.Data, SizeOf(Result^.Data), 0);
    Result^.IsUse := True;
  finally
    LeaveCriticalSection(FLock);
  end;
end;

//回收内存块到内存池中,可以继续使用
procedure TMemoryBuffer.RemoveBlock(Block: PBlock);
begin
  EnterCriticalSection(FLock);
  try
    Block.IsUse := False;
  finally
    LeaveCriticalSection(FLock);
  end;
end;

function TMemoryBuffer.GetCount: Integer;
begin
  Result := FList.Count;
end;

function TMemoryBuffer.GetBlock(const Index: Integer): PBlock;
begin
  if (Index >= Count) or (Index <= -1) then
    raise EMemoryBuffer.CreateFmt('需要不正确', [Index])
  else
    Result := FList[Index];
end;

end.
 
回复

使用道具 举报

该用户从未签到

发表于 2012-6-4 14:54:53 | 显示全部楼层
能用在三层midas结构上吗
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2012-6-5 15:21:18 | 显示全部楼层
能在Lazarus上使用吗
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2012-9-24 11:08:23 | 显示全部楼层
学习一下。
回复 支持 反对

使用道具 举报

*滑块验证:

本版积分规则

QQ|手机版|小黑屋|Lazarus中国|Lazarus中文社区 ( 鄂ICP备16006501号-1 )

GMT+8, 2025-5-2 22:22 , Processed in 0.028225 second(s), 10 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表