⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uditcppacketechosocketserver.pas

📁 楠楠写的DBiocp例子都是源码
💻 PAS
字号:
unit uDITcpPacketEchoSocketServer;

interface

uses
  Windows, Sysutils, uDIBuffer, uIOCompletionPort, uDIClientContext, uDIProtocol,
  uDIIocpTcpServer;
  {$I IOCP.inc}

type

  PTDIDataPakHead = ^TDIDataPakHead;
  TDIDataPakHead = Packed Record  
    _Head:    Byte;              //帧头标志    64
    _Len:     Word;              //数据包长度
  end;

  PTTDIDataPakBody = ^TTDIDataPakBody;
  TTDIDataPakBody = Packed record
    _Sing:      Word;            //客户标识
    _SocketKey: Word;            //Socket标识
    _OP:        Byte;            //控制码   1 回射
  end;

  //.数据.
  PTDIDataPakEnd = ^TDIDataPakEnd;
  TDIDataPakEnd = Packed record
    _CheckSum:        Word;       //校验和
    _End:             Byte;       //帧结束符
  end;

const
  FDataPakHeadLen = SizeOf(TDIDataPakHead);
  FDataPakBodyLen = SizeOf(TTDIDataPakBody);
  FDataPakEndLen = SizeOf(TDIDataPakEnd);

type
  TDITcpPacketEchoSocketServer = class(TDIIocpTcpServer)
  private
    FDataPakHead:   TDIDataPakHead; //包头
    FDataPakBody:   TTDIDataPakBody;//包体
    FDataPakEnd:    TDIDataPakEnd;  //包尾
  private
    procedure NewSocketEvent(FClientContext: TDIClientContext);
    procedure CloseSocketEvent(FClientContext: TDIClientContext);
    procedure RecvCompletedEvent( FClientContext: TDIClientContext;
                                  FDIBuffer: TDIBuffer;
                                  dwIoSize: DWORD );
    procedure SendCompletedEvent( FClientContext: TDIClientContext;
                                  FDIBuffer: TDIBuffer;
                                  dwIoSize: DWORD );

    procedure ProcessDataStream( FClientContext: TDIClientContext;
                                 FDIBuffer: TDIBuffer;
                                 dwIoSize: DWORD );
  public
    procedure ReadEchoPackage(FDIBuffer: TDIBuffer);
    procedure WriteEchoPackage(FDIBuffer: TDIBuffer);
  published
    procedure AppendDisplayMsg(sMsg: String); override;
    procedure AppendLogMessage(sMsg: String); override;
    procedure AppendErrorLogMessage(sMsg: String); override;
    procedure SendMsgToAll;
  public
    constructor Create(IOCompletionPort: TIOCompletionPort);
    destructor Destroy; override;
  end;

implementation
  uses crc16, uDIMonitor, uFileLogger;

constructor TDITcpPacketEchoSocketServer.Create(IOCompletionPort: TIOCompletionPort);
begin
  inherited Create(IOCompletionPort);
  ZeroMemory(@FDataPakHead, SizeOf(FDataPakHead));
  ZeroMemory(@FDataPakBody, SizeOf(FDataPakBody));
  ZeroMemory(@FDataPakEnd, SizeOf(FDataPakEnd));

  OnNewSocketEvent := NewSocketEvent;
  OnCloseSocketEvent := CloseSocketEvent;
  OnRecvCompletedEvent := RecvCompletedEvent;
  OnSendCompletedEvent := SendCompletedEvent;
end;

destructor TDITcpPacketEchoSocketServer.Destroy;
begin
  inherited Destroy;
end;

procedure TDITcpPacketEchoSocketServer.AppendDisplayMsg(sMsg: String);
begin

end;

procedure TDITcpPacketEchoSocketServer.AppendLogMessage(sMsg: String);
begin
  _FileLogger.WriteLogMsg(sMsg);
end;

procedure TDITcpPacketEchoSocketServer.AppendErrorLogMessage(sMsg: String);
begin
  _FileLogger.WriteLogMsg(sMsg);
end;

procedure TDITcpPacketEchoSocketServer.NewSocketEvent(FClientContext: TDIClientContext);
begin
  {$IFDEF _ICOP_DEBUG}
      AppendLogMessage('新客户端连接, IP地址:'+FClientContext.FRemoteIP+
                       ' Socket ID: '+ IntToStr(FClientContext.m_KeyID)+
                       ' m_iNumberOfActiveConnections:'+IntToStr(m_iNumberOfActiveConnections));
  {$ENDIF}
end;

procedure TDITcpPacketEchoSocketServer.CloseSocketEvent(FClientContext: TDIClientContext);
begin
  {
  AppendDisplayMsg('客户端关闭, IP地址:'+GetRemoteIPAddr(FClientContext.FRemoteAddr)+
                           ' Socket ID:'+ IntToStr(FClientContext.m_KeyID));  }
end;

procedure TDITcpPacketEchoSocketServer.RecvCompletedEvent( FClientContext: TDIClientContext;
                                                           FDIBuffer: TDIBuffer;
                                                           dwIoSize: DWORD );
begin
  {$IFDEF _IOCP_MONITOR}
      _DIMonitor.AddRecvByte(dwIoSize);
  {$ENDIF}

  //设置socket
  FClientContext.FContextLock.Lock;
  FDIBuffer.m_Socket := FClientContext.FSocket;
  FClientContext.FContextLock.UnLock;
  
  //处理数据
  ProcessDataStream(FClientContext, FDIBuffer, dwIoSize);
  //投递下一个Buffer
  PostWSARecv(FClientContext);
end;

procedure TDITcpPacketEchoSocketServer.SendCompletedEvent( FClientContext: TDIClientContext;
                                                     FDIBuffer: TDIBuffer;
                                                     dwIoSize: DWORD );
begin
  {$IFDEF _IOCP_MONITOR}
      _DIMonitor.AddSendByte(dwIoSize);
  {$ENDIF}

  if FDIBuffer.GetUsed = dwIoSize then begin
//    {$IFDEF _ICOP_DEBUG}
//        AppendLogMessage('SendCompletedEvent投递完成! Key : '+IntToStr(FClientContext.m_KeyID));
//    {$ENDIF}
  end
  else
  begin
    {$IFDEF _ICOP_DEBUG}
        AppendLogMessage('SendCompletedEvent尚未完成! Key : '+IntToStr(FClientContext.m_KeyID));
    {$ENDIF}
  end;
end;


procedure TDITcpPacketEchoSocketServer.ProcessDataStream( FClientContext: TDIClientContext;
                                                          FDIBuffer: TDIBuffer;
                                                          dwIoSize: DWORD );
begin
  FClientContext.FContextLock.Lock;
  //读数据包
  ReadEchoPackage(FDIBuffer);

  FClientContext.SendBuffer.InitBuffer;
  CopyMemory( Pointer(FClientContext.SendBuffer.GetBuffer),
              Pointer(FDIBuffer.GetBuffer),
              FDIBuffer.GetUsed );
  FClientContext.SendBuffer.SetUsed(FDIBuffer.GetUsed);
  FClientContext.FContextLock.UnLock;

  PostWSASend(FClientContext);
end;

procedure TDITcpPacketEchoSocketServer.ReadEchoPackage(FDIBuffer: TDIBuffer);
var
  sMsg: String;
  m_nBufLen: Integer;
  m_nPackLen: Integer;
  m_nCalLen: Integer;
  
  calCheckSum: Word;
  m_nUsed: Word;
  iDataLen: Integer;
  m_pointPos: Pointer;
  Buffer: array [0..MAX_PACKAGESIZE - 1] of Byte; //用户缓冲
begin
  FSocketServerLock.Lock;

  //得到Buffer长度, 暂不考虑TCP流协议造成的一个数据包未发完的情况。
  //这种情况用环形Buffer拷贝,再次拼即可
  m_nBufLen := FDIBuffer.GetUsed;

  //包头有效情况下
  if m_nBufLen> FDataPakHeadLen then begin
    m_pointPos := FDIBuffer.GetBuffer;
    m_nPackLen := PTDIDataPakHead(m_pointPos)^._Len;
     //判断包长度是否正确
    if m_nPackLen <> m_nBufLen -1 then begin
      AppendLogMessage(Format('客户端Key is %d, 包长度<>m_nPackLen <> m_nBufLen -1, 包不完整,可能需要下次继续拼包.', [FDIBuffer.m_Socket]));
    end;

    AppendLogMessage(Format('客户端Key is %d, PDataPakHead._Head 帧头:%d.', [FDIBuffer.m_Socket, PTDIDataPakHead(m_pointPos)^._Head]));
    AppendLogMessage(Format('客户端Key is %d, PDataPakHead._Len 数据长度:%d.', [FDIBuffer.m_Socket, PTDIDataPakHead(m_pointPos)^._Len]));
  end
  else
  begin
    AppendLogMessage(Format('客户端Key is %d, m_nBufLen<FDataPakHeadLen, 包不完整,可能需要下次继续拼包.', [FDIBuffer.m_Socket]));
    FSocketServerLock.UnLock;
    Exit;
  end;

  //包体有效情况下
  if m_nBufLen> FDataPakHeadLen + FDataPakBodyLen then begin
    m_pointPos := Pointer(LongInt(FDIBuffer.GetBuffer)+FDataPakHeadLen);

    AppendLogMessage(Format('客户端Key is %d, PTTDIDataPakBody._Sing 标志位:%d.', [FDIBuffer.m_Socket, PTTDIDataPakBody(m_pointPos)^._Sing]));
    AppendLogMessage(Format('客户端Key is %d, PTTDIDataPakBody._SocketKey Socket标志:%d.', [FDIBuffer.m_Socket, PTTDIDataPakBody(m_pointPos)^._SocketKey]));
    AppendLogMessage(Format('客户端Key is %d, PTTDIDataPakBody._OP 操作符:%d.', [FDIBuffer.m_Socket, PTTDIDataPakBody(m_pointPos)^._OP]));
  end
  else
  begin
    AppendLogMessage(Format('客户端Key is %d, m_nBufLen<FDataPakHeadLen + FDataPakBodyLen, 包不完整,可能需要下次继续拼包.', [FDIBuffer.m_Socket]));
    FSocketServerLock.UnLock;
    Exit;
  end;

  //包尾有效情况下
  if m_nBufLen> FDataPakHeadLen + FDataPakBodyLen+ FDataPakEndLen then begin
    //计算数据长度
    m_nCalLen := m_nBufLen- FDataPakHeadLen - FDataPakBodyLen- FDataPakEndLen;

    if m_nCalLen<0 then begin
      AppendLogMessage(Format('客户端Key is %d, m_nCalLen<0,可能需要下次继续拼包.', [FDIBuffer.m_Socket]));
      FSocketServerLock.UnLock;
      Exit;
    end;

    //如果计算的长度小于,封包中的长度,则以计算的为准
    iDataLen := m_nPackLen;
    if m_nCalLen<m_nPackLen then iDataLen := m_nCalLen;

    //根据数据长度,得到数据
    FillChar(Buffer, SizeOf(Buffer), 0);

    //拷贝数据
    m_pointPos := Pointer(LongInt(FDIBuffer.GetBuffer) + FDataPakHeadLen + FDataPakBodyLen);

    CopyMemory( @Buffer[1],
                m_pointPos,
                iDataLen );
    sMsg := pchar(@Buffer[1]);
    AppendLogMessage(Format('客户端Key is %d, 数据包: %s.', [FDIBuffer.m_Socket, sMsg]));
    m_pointPos := Pointer(LongInt(FDIBuffer.GetBuffer) + FDataPakHeadLen + FDataPakBodyLen +iDataLen);
    AppendLogMessage(Format('客户端Key is %d, PTDIDataPakEnd._CheckSum 校验和: %d.', [FDIBuffer.m_Socket, PTDIDataPakEnd(m_pointPos)^._CheckSum]));
    AppendLogMessage(Format('客户端Key is %d, PTDIDataPakEnd._SocketKey 帧结束符: %d.', [FDIBuffer.m_Socket, PTDIDataPakEnd(m_pointPos)^._End]));

    
    m_nUsed := FDataPakHeadLen + FDataPakBodyLen +iDataLen;
    calCheckSum := 0;
    CalcCRC16(FDIBuffer.GetBuffer, m_nUsed, calCheckSum);
    if calCheckSum = PTDIDataPakEnd(m_pointPos)^._CheckSum then begin
      AppendLogMessage(Format('客户端Key is %d, PTDIDataPakEnd._CheckSum 校验和正确.', [FDIBuffer.m_Socket]));
    end
    else
    begin
      AppendLogMessage(Format('客户端Key is %d, 客户端检验和: %d, S端计算检验和: %d.', [FDIBuffer.m_Socket, PTDIDataPakEnd(m_pointPos)^._CheckSum, calCheckSum]));
    end;

  end
  else
  begin
    AppendLogMessage('包体不完整,可能需要下次继续拼包.');
  end;
  FSocketServerLock.UnLock;
end;


procedure TDITcpPacketEchoSocketServer.WriteEchoPackage(FDIBuffer: TDIBuffer);
var
  sMsg: String;
  m_nBufSize, m_nUsed: Integer;
  nStrLen: Integer;
begin
  sMsg := 'Hello, DBIOCP. This is first echoPack example.';
  nStrLen := length(sMsg);

  if (nStrLen>0) then begin
    m_nBufSize := nStrLen + FDataPakHeadLen + FDataPakBodyLen +FDataPakEndLen;
    if m_nBufSize>MAX_PACKAGESIZE then Exit;

    FDataPakHead._Head := 64;                         //包头帧 64
    FDataPakHead._Len := m_nBufSize - SizeOf(Byte);   //包长度
    FDataPakBody._Sing := 16;                         //标置位
    FDataPakBody._SocketKey := FDIBuffer.m_Socket;    //Socket标志
    FDataPakBody._OP := 1;                            //回射

    //初始化
    FDIBuffer.InitBuffer;
    //加入包头
    FDIBuffer.CreatePackage(@FDataPakHead, FDataPakHeadLen);
    //加入包体
    FDIBuffer.CreatePackage(@FDataPakBody, FDataPakBodyLen);
    //加入数据
    FDIBuffer.CreatePackage(sMsg);
    //计算校验长度
    m_nUsed := FDataPakHeadLen + FDataPakBodyLen + nStrLen;
    //计算校验和
    FDataPakEnd._CheckSum := 0;
    CalcCRC16(FDIBuffer.GetBuffer, m_nUsed, FDataPakEnd._CheckSum);
    FDataPakEnd._End := 16; //包尾帧 16
    //加入包尾
    FDIBuffer.CreatePackage(@FDataPakEnd, FDataPakEndLen);
  end;
end;

procedure TDITcpPacketEchoSocketServer.SendMsgToAll;
var
  m_pFreeClientContext: TDIClientContext;
  m_pNextClientContext: TDIClientContext;
begin
  FMapClientContextLock.Lock;

  //取单链表头
  m_pFreeClientContext := FMapClientContext.FClientContextList;
  m_pNextClientContext := nil;
    
  while (m_pFreeClientContext<> nil) do begin
    m_pNextClientContext := m_pFreeClientContext.m_pNext;

    m_pFreeClientContext.FContextLock.Lock;
    m_pFreeClientContext.SendBuffer.m_Socket := m_pFreeClientContext.m_Socket;
    WriteEchoPackage(m_pFreeClientContext.SendBuffer);
    m_pFreeClientContext.FContextLock.UnLock;

    PostWSASend(m_pFreeClientContext);
    m_pFreeClientContext := m_pNextClientContext;
  end;

  FMapClientContextLock.UnLock;
end;


end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -