• QQ
  • nahooten@sina.com
  • 常州市九洲新世界花苑15-2

游戏开发

DIOCP开源项目-定义本人要发送的数据构造(MyObje

原创内容,转载请注明原文网址:http://homeqin.cn/a/wenzhangboke/jishutiandi/youxikaifa/2019/0413/455.html

DIOCP开源项目-定义本人要发送的数据构造(MyObject)

印象中网络程序都是sendBuffer和recvBuffer来发送数据和接纳数据,本次Demo演示如何定义定义一个本人的对象,然后我们依照OO的思想直接停止对象的发送和接纳,先上个流程图。

 
下面是
常州微信公众平台客户端发送和接纳的测试代码。

 
下面我们来看看细致的设计。
第一步(TMyObject):首先我们需求设计一个需求停止传输的对象.
type 
  TMyObject = class(TObject) 
  private 
    FDataString:String; 
    FOle:OleVariant; 
  public 
    property DataString:String read FDataString write FDataString; 
    property Ole:OleVariant read FOle write FOle; 
  end;
对象很简单,一个DataString,和Ole。Ole能够寄存各种数据。
 
第二步:编写客户端发送和接纳过程
发送对象:
    把对象变成能够传送的格式,然后用IdTcpClient停止发送,编码的格式为:字符串长度+ole数据流长度 + 字符串数据 + Ole流数据,代码很简单如下。
 
class function TMyObjectCoderTools.Encode(pvSocket: TIdTcpClient; 
  pvObject: TObject): Integer; 
var 
  lvMyObj:TMyObject; 
  lvOleStream:TMemoryStream; 
  lvOleLen, lvStringLen:Integer; 
begin 
  lvMyObj := TMyObject(pvObject);
  lvOleStream := TMemoryStream.Create; 
  try 
    WriteOleVariant(lvMyObj.Ole, lvOleStream); 
    lvOleLen := lvOleStream.Size; 
    lvOleStream.Position := 0;
    //字符串长度+ole长度 + 字符串数据 + Ole数据 
    lvStringLen := Length(AnsiString(lvMyObj.DataString));
    Result := 0; 
    Result := Result + sendBuffer(pvSocket,@lvStringLen,sizeOf(Integer)); 
    Result := Result + sendBuffer(pvSocket,@lvOleLen,sizeOf(Integer)); 
    Result := Result + sendBuffer(pvSocket,PAnsiChar(AnsiString(lvMyObj.DataString)), lvStringLen); 
    Result := Result + sendBuffer(pvSocket,lvOleStream.Memory, lvOleLen); 
    //result 发送长度 
  finally 
    lvOleStream.Free; 
  end; 
end;
 
接纳对象:
   用IdTcpClient接纳数据,把
常州微信小程序开发接纳到的数据依照协议格式停止拆分,放入到对象的属性中,依次读取字符串长度+ole长度 + 字符串数据 + Ole数据,代码如下
class function TMyObjectCoderTools.Decode(pvSocket: TIdTcpClient; 
  pvObject: TObject): Boolean; 
var 
  lvStringLength, lvStreamLength:Integer; 
  lvData, lvTemp:AnsiString; 
  lvStream:TStream;
  l, lvRemain:Integer; 
  lvBufData:PAnsiChar; 
begin 
  Result := false; 
  lvStringLength := 0; 
  lvStreamLength := 0; 
  recvBuffer(pvSocket, @lvStringLength, SizeOf(Integer)); 
  recvBuffer(pvSocket, @lvStreamLength, SizeOf(Integer)); 
  if (lvStringLength = 0) and (lvStreamLength = 0) then exit;
//读取json字符串 
  if lvStringLength > 0 then 
  begin 
    SetLength(lvData, lvStringLength); 
    l := recvBuffer(pvSocket, PAnsiChar(lvData), lvStringLength); 
    TMyObject(pvObject).DataString := lvData; 
  end;
  //读取Ole值 
  if lvStreamLength > 0 then 
  begin 
    GetMem(lvBufData, lvStreamLength); 
    try 
      recvBuffer(pvSocket, lvBufData, lvStreamLength); 
      lvStream := TMemoryStream.Create; 
      try 
        lvStream.WriteBuffer(lvBufData^, lvStreamLength); 
        lvStream.Position := 0;
        TMyObject(pvObject).Ole := ReadOleVariant(lvStream); 
      finally 
        lvStream.Free; 
      end; 
    finally 
      FreeMem(lvBufData, lvStreamLength); 
    end; 
  end;
  Result := true; 
end;
 
 
第三步:效劳端的接纳和发送,效劳端接纳到数据后也需求解码,返回数据也需求编码。在效劳端需求编写编码器,过程与客户端的发送和接纳相似。
 
接纳的解码器。
TMyObjectDecoder = class(TIOCPDecoder) 
public 
  ///
 
  ///   解码收到的数据,假如有接纳到数据,调用该办法,停止解码 
  ///  
  /// 
 
  ///   返回解码好的对象 
  ///  
  /// 接纳到的流数据  
  function Decode(const inBuf: TBufferLink): TObject; override; 
end;
 
function TMyObjectDecoder.Decode(const inBuf: TBufferLink): TObject; 
var 
  lvStringLen, lvStreamLength:Integer; 
  lvData:AnsiString; 
  lvBuffer:array of Char; 
  lvBufData:PAnsiChar; 
  lvStream:TMemoryStream; 
  lvValidCount:Integer; 
  lvBytes:TIOCPBytes; 
begin 
  Result := nil;
  //假如缓存中的数据长度不够包头长度,解码失败<字符串长度,Ole流长度> 
  lvValidCount := inBuf.validCount; 
  if (lvValidCount < SizeOf(Integer) + SizeOf(Integer)) then 
  begin 
    Exit; 
  end;
  //记载读取位置 
  inBuf.markReaderIndex; 
  inBuf.readBuffer(@lvStringLen, SizeOf(Integer)); 
  inBuf.readBuffer(@lvStreamLength, SizeOf(Integer));

  //假如缓存中的数据不够json的长度和流长度<阐明数据还没有收取终了>解码失败 
  lvValidCount := inBuf.validCount; 
  if lvValidCount < (lvStringLen + lvStreamLength) then 
  begin 
    //返回buf的读取位置 
    inBuf.restoreReaderIndex; 
    exit; 
  end else if (lvStringLen + lvStreamLength) = 0 then 
  begin 
    //两个都为0<两个0>客户端能够用来作为自动重连运用 
    TIOCPFileLogger.logDebugMessage('接纳到一次[00]数据!'); 
    Exit; 
  end;
 
  //解码胜利 
  Result := TMyObject.Create;
  //读取json字符串 
  if lvStringLen > 0 then 
  begin 
    SetLength(lvData, lvStringLen); 
    inBuf.readBuffer(PAnsiChar(lvData), lvStringLen); 
    TMyObject(Result).DataString := lvData; 
  end;
  //读取Ole值 
  if lvStreamLength > 0 then 
  begin 
    GetMem(lvBufData, lvStreamLength); 
    try 
      inBuf.readBuffer(lvBufData, lvStreamLength); 
      lvStream := TMemoryStream.Create; 
      try 
        lvStream.WriteBuffer(lvBufData^, lvStreamLength); 
        lvStream.Position := 0;
        TMyObject(Result).Ole := ReadOleVariant(lvStream); 
      finally 
        lvStream.Free; 
      end; 
    finally 
      FreeMem(lvBufData, lvStreamLength); 
    end; 
  end; 
end;
 
发送的编码器
TMyObjectEncoder = class(TIOCPEncoder) 
public 
  ///
 
  ///   编码常州游戏开发培训要发送的对象 
  ///  
  /// 要停止编码的对象  
  /// 编码好的数据 
  ///   字符串长度+ole长度 + 字符串数据 + Ole数据 
  ///  
  procedure Encode(pvDataObject:TObject; const ouBuf: TBufferLink); override; 
end;
 

procedure TMyObjectEncoder.Encode(pvDataObject: TObject; 
  const ouBuf: TBufferLink); 
var 
  lvMyObj:TMyObject; 
  lvOleStream:TMemoryStream; 
  lvOleLen, lvStringLen:Integer; 
begin 
  lvMyObj := TMyObject(pvDataObject);
  lvOleStream := TMemoryStream.Create; 
  try 
    WriteOleVariant(lvMyObj.Ole, lvOleStream); 
    lvOleLen := lvOleStream.Size; 
    lvOleStream.Position := 0;
    //字符串长度+ole长度 + 字符串数据 + Ole数据 
    lvStringLen := Length(AnsiString(lvMyObj.DataString));
    ouBuf.AddBuffer(@lvStringLen,sizeOf(Integer));
    ouBuf.AddBuffer(@lvOleLen,sizeOf(Integer));
    ouBuf.AddBuffer(PAnsiChar(AnsiString(lvMyObj.DataString)), lvStringLen);
    ouBuf.AddBuffer(lvOleStream.Memory, lvOleLen); 
  finally 
    lvOleStream.Free; 
  end; 
end;
 
然后在启动IOCP的之前注册编码器和解码器
FDecoder := TMyObjectDecoder.Create; 
FEncoder := TMyObjectEncoder.Create;
//注册解码器 
TIOCPContextFactory.instance.registerDecoder(FDecoder);
//注册编码器 
TIOCPContextFactory.instance.registerEncoder(FEncoder);
 
效劳端然后就能够在ClientContext中编写相应的逻辑处置代码就行了
procedure TClientContext.dataReceived(const pvDataObject:TObject); 
var 
  lvMyObject:TMyObject; 
begin 
  lvMyObject := TMyObject(pvDataObject); 
  try 
    //直接回传 
    writeObject(lvMyObject); 
  except 
    on E:Exception do 
    begin 
      lvMyObject.DataString := E.Message; 
      writeObject(lvMyObject); 
    end; 
  end; 
end;
 


上篇:上一篇:U3D Shader之遮挡透明效果
下篇:下一篇:帧同步在网游应用