Delphi-IOCP学习笔记<八>=======服务端的数据发送和JSonStreamObject的编码器

现在IOCP的功能还剩下服务端数据的返回。

还是采用netty的方式。netty返回数据的调用是这样的contenxt.write(<TObject> obj);这样将obj对象发送给客户端。

 

1.将回传的对象进行编码成buffer

2.通过socket进行传送.

 

>>>>>>>>>>>>>>

下面我贴出回传数据的过程.

procedure TClientContext.writeObject(const pvDataObject:TObject);
var
  lvOutBuffer:TBufferLink;
begin
  lvOutBuffer := TBufferLink.Create;
  try
    TContextFactory.instance.FEncoder.Encode(pvDataObject, lvOutBuffer);
    TIOCPTools.SendBuffer(self.FSocket, lvOutBuffer);
  finally
    lvOutBuffer.Free;
  end;
end;

 

在数据处理的时候,我尝试调用这段代码

procedure TClientContext.dataReceived(const pvDataObject:TObject);
var
  lvJsonStream:TJSonStreamObject;
  lvFile:String;
begin
  lvJsonStream := TJSonStreamObject(pvDataObject);

  //客户端发送文件
  if lvJsonStream.JSon.I['cmdIndex'] = 102 then
  begin
    lvFile := ExtractFilePath(ParamStr(0)) + 'tempFile\';
    ForceDirectories(lvFile);
    lvFile := lvFile + lvJsonStream.JSon.S['file'];
    TMemoryStream(lvJsonStream.Stream).Position := 0;
    TMemoryStream(lvJsonStream.Stream).SaveToFile(lvFile);
  end else
  begin
    //返回数据
    writeObject(lvJsonStream);
  end;


  TLogClientWrapper.logINfo(lvJsonStream.JSon.AsJSon(True));

end;

 

在IOCP的工作线程中如果数据发送完成,回收内存块。

end else if PerIoData.IO_TYPE = IO_TYPE_Send then
          begin    //发送完成数据<WSASend>完成
            
            //回收数据块
            TIODataMemPool.instance.giveBackIOData(PerIoData);
          end;

 

TIOCPTools.SendBuffer代码

unit IOCPTools;

interface

uses
  uBuffer, JwaWinsock2, uMemPool, Windows;

const
  IO_TYPE_Accept = 1;
  IO_TYPE_Recv = 2;
  IO_TYPE_Send = 3;   //发送数据

type
  TIOCPTools=class(TObject)
  public
    class procedure SendBuffer(pvSocket: TSocket; const ouBuf: TBufferLink);
  end;

implementation

class procedure TIOCPTools.SendBuffer(pvSocket: TSocket; const ouBuf:
    TBufferLink);
var
  lvIOData:LPPER_IO_OPERATION_DATA;
  lvRet:Cardinal;
begin
  while ouBuf.validCount > 0 do
  begin
    lvIOData := TIODataMemPool.instance.borrowIOData;
    lvIOData.IO_TYPE := IO_TYPE_Send;
    //这里我改变了内存块的大小,每次发送的长度不能超过设定的内存块大小。但是数据不够的情况下
    //Databuf.len是指定了要发送内存块的大小。在回收内存块的时候,需要还原大小。
    lvIOData.DataBuf.len := ouBuf.readBuffer(lvIOData.DataBuf.buf, lvIOData.DataBuf.len);

    if (WSASend(pvSocket,
       @lvIOData.DataBuf,
       1,
       lvIOData.WorkBytes,
       lvIOData.WorkFlag,
       @lvIOData^, nil) = SOCKET_ERROR) then
    begin
      lvRet := GetLastError();
      //重叠IO,出现ERROR_IO_PENDING是正常的,
      //表示数据尚未接收完成,如果有数据接收,GetQueuedCompletionStatus会有返回值
      if (lvRet <> ERROR_IO_PENDING) then
      begin
        closesocket(pvSocket);
        Break;
      end;
    end;
  end;


end;

end.

 

 

//编码器代码,负责将发送的对象转换成流

unit uJSonStreamEncoder;

interface


uses
  uIOCPDecoder, uBuffer, Classes, superobject, SysUtils;

type
  TJSonStreamEncoder = class(TIOCPEncoder)
  public
    /// <summary>
    ///   编码要发送的对象
    /// </summary>
    /// <param name="pvDataObject"> 要进行编码的对象 </param>
    /// <param name="ouBuf"> 编码好的数据 </param>
    procedure Encode(pvDataObject:TObject; const ouBuf: TBufferLink); override;
  end;

implementation

uses
  uJSonStreamObject, Windows;

procedure TJSonStreamEncoder.Encode(pvDataObject:TObject; const ouBuf:
    TBufferLink);
var
  lvJSonStreamObject:TJSonStreamObject;
  lvJSonLength:Integer;
  lvStreamLength:Integer;
  sData:String;
  lvStream:TStream;
  lvTempBuf:PAnsiChar;
begin
  if pvDataObject = nil then exit;
  lvJSonStreamObject := TJSonStreamObject(pvDataObject);

  sData := lvJSonStreamObject.JSon.AsJSon(True);
  lvJSonLength := Length(sData);
  lvStream := lvJSonStreamObject.Stream;

  ouBuf.AddBuffer(@lvJSonLength, SizeOf(lvJSonLength));


  if lvStream <> nil then
  begin
    lvStreamLength := lvStream.Size;
  end else
  begin
    lvStreamLength := 0;
  end;

  ouBuf.AddBuffer(@lvStreamLength, SizeOf(lvStreamLength));


  //json bytes
  ouBuf.AddBuffer(@sData[1], lvJSonLength);
  if lvStreamLength > 0 then
  begin
    //stream bytes
    GetMem(lvTempBuf, lvStreamLength);
    try
      lvStream.Position := 0;
      lvStream.ReadBuffer(lvTempBuf^, lvStreamLength);
      ouBuf.AddBuffer(lvTempBuf, lvStreamLength);
    finally
      FreeMem(lvTempBuf, lvStreamLength);
    end;
  end;
end;



end.

 

>>>>>好了关键性的代码我都贴出来了。这次就不提供demo了。如果有需要的请留言

下一次学习的主题是做一个压力测试的demo

posted @ 2013-04-24 10:36  D10.天地弦  阅读(1387)  评论(0编辑  收藏  举报