zoukankan      html  css  js  c++  java
  • TDiocpCoderTcpServer数据序列和还原

    TDiocpCoderTcpServer数据序列和还原

    封装在uDIOCPStreamCoder.pas单元中。

    DIOCP tcp默认使用MSGPACK二进制数据序列,MSGPACK序列为流,即可进行网络传输。TCP服务端有使用TBufferLink(内存池)。

    流数据放入内存池中:

    流数据默认做了大小限制,最大10M。

    const
    PACK_FLAG = $D10;

    //PACK_FLAG + CRC_VALUE + STREAM_LEN + STREAM_DATA

    MAX_OBJECT_SIZE = 1024 * 1024 * 10; //最大对象大小 10M , 大于10M 则会认为错误的包。

    procedure TIOCPStreamEncoder.Encode(pvDataObject: TObject;
      const ouBuf: TBufferLink);
    var
      lvPACK_FLAG: WORD;
      lvDataLen, lvWriteIntValue: Integer;
      lvBuf: TBytes;
      lvVerifyValue:Cardinal;
    begin
      lvPACK_FLAG := PACK_FLAG;
    
      TStream(pvDataObject).Position := 0;
    
      if TStream(pvDataObject).Size > MAX_OBJECT_SIZE then
      begin
        raise Exception.CreateFmt('数据包太大,请在业务层分拆发送,最大数据包[%d]!', [MAX_OBJECT_SIZE]);
      end;
    
    
    
    
      //pack_flag
      ouBuf.AddBuffer(@lvPACK_FLAG, 2);
    
      //
      lvDataLen := TStream(pvDataObject).Size;
      // stream data
      SetLength(lvBuf, lvDataLen);
      TStream(pvDataObject).Read(lvBuf[0], lvDataLen);
    
      //veri value
      lvVerifyValue := verifyData(lvBuf[0], lvDataLen);
    
      ouBuf.AddBuffer(@lvVerifyValue, SizeOf(lvVerifyValue));
    
    
      // data_len
      lvWriteIntValue := TByteTools.swap32(lvDataLen);
    
      // stream len
      ouBuf.AddBuffer(@lvWriteIntValue, SizeOf(lvWriteIntValue));
    
    
    
      // stream
      ouBuf.AddBuffer(@lvBuf[0], lvDataLen);  
    end; 

     内存池数据放入流中:

    function TIOCPStreamDecoder.Decode(const inBuf: TBufferLink; pvContext:
        TObject): TObject;
    var
      lvValidCount, lvReadL:Integer;
      lvPACK_FLAG:Word;
      lvDataLen: Integer;
      lvVerifyValue, lvVerifyDataValue:Cardinal;
    begin
      Result := nil;
    
      //如果缓存中的数据长度不够包头长度,
      lvValidCount := inBuf.validCount;   //pack_flag + head_len + buf_len
      if (lvValidCount < SizeOf(Word) + SizeOf(Integer) + SizeOf(Integer)) then
      begin
        Exit;
      end;
    
      //记录读取位置
      inBuf.markReaderIndex;
      inBuf.readBuffer(@lvPACK_FLAG, 2);
    
      if lvPACK_FLAG <> PACK_FLAG then
      begin
        //错误的包数据
        Result := TObject(-1);
        exit;
      end;
    
      //veri value
      inBuf.readBuffer(@lvVerifyValue, SizeOf(lvVerifyValue));
    
      //headlen
      inBuf.readBuffer(@lvReadL, SizeOf(lvReadL));
      lvDataLen := TByteTools.swap32(lvReadL);
    
      if lvDataLen > 0 then
      begin
        //文件头不能过大
        if lvDataLen > MAX_OBJECT_SIZE  then
        begin
          Result := TObject(-1);
          exit;
        end;
    
        if inBuf.validCount < lvDataLen then
        begin
          //返回buf的读取位置
          inBuf.restoreReaderIndex;
          exit;
        end;
    
        Result := TMemoryStream.Create;
        TMemoryStream(Result).SetSize(lvDataLen);
        inBuf.readBuffer(TMemoryStream(Result).Memory, lvDataLen);
        TMemoryStream(Result).Position := 0;
    
        lvVerifyDataValue := verifyData(TMemoryStream(Result).Memory^, lvDataLen);
    
        if lvVerifyValue <> lvVerifyDataValue then
        begin
          Result.Free;
          Result := TObject(-2);
        end;  
      end else
      begin
        Result := nil;
      end;
    end;
    

      

  • 相关阅读:
    Dyanmcis 365调用Action报Entity Reference cannot have Id and Key Attributes empty.错误
    Dynamics 365中使用工作流发邮件让其可以发往文本字段指定的邮箱
    Dynamics 365 Web API分页查询数据
    微软Dynamics CRM 2013介绍系列之三十:筛选查找控件,so easy。
    Power Automate实用常见问题解答(FAQ)
    Dynamics 365使用JavaScript调用Web API批量设置字段的审核属性为禁用。
    Dynamics 365 V9版本新的客户端API Xrm.WebApi.online.execute 使用实例
    Dynamics 365附件的常见控制
    Dynamics 365的存储容量介绍
    请不要在繁忙时候更改用户的业务部门
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/13521333.html
Copyright © 2011-2022 走看看