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

简介: 现在IOCP的功能还剩下服务端数据的返回。 还是采用netty的方式。netty返回数据的调用是这样的contenxt.write( obj);这样将obj对象发送给客户端。   1.将回传的对象进行编码成buffer 2.

现在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

目录
相关文章
|
14天前
|
存储 Python
Python网络编程基础(Socket编程)接收和发送数据
【4月更文挑战第9天】在UDP服务器编程中,我们已经创建了一个UDP套接字并绑定了地址和端口。接下来,服务器需要能够接收来自客户端的数据,并能够对这些数据进行处理和响应。下面,我们将详细讲解如何在UDP服务器中接收和发送数据。
|
3月前
|
API 数据安全/隐私保护
jrtplib开源库系列之三:jrtplib发送接收数据流程
前面2篇文章主要说明了如何安装jrtplib库,以及对example1进行了说明,这篇文章主要说下jrtplib库数据的收发流程。
74 0
|
存储 设计模式 网络协议
Socket通信原理及模型实现
Socket通信原理及模型实现
212 0
|
存储 Java
Java网络编程-服务端程序实现
Java网络编程-服务端程序实现
92 0
Java网络编程-服务端程序实现
|
存储 网络协议 C语言
服务端编程示例|学习笔记
快速学习服务端编程示例
服务端编程示例|学习笔记
|
网络协议 Python
Python 技术篇-socket套接字实现服务器客户端消息传递实例演示,UDP实现
Python 技术篇-socket套接字实现服务器客户端消息传递实例演示,UDP实现
232 0
Python 技术篇-socket套接字实现服务器客户端消息传递实例演示,UDP实现
|
网络协议 Python
Python 技术篇-socket套接字实现两个窗口间消息传递实例演示,TCP实现
Python 技术篇-socket套接字实现两个窗口间消息传递实例演示,TCP实现
248 0
Python 技术篇-socket套接字实现两个窗口间消息传递实例演示,TCP实现
|
C# Windows
C# 套接字编程:Scoket,我用Scoket做的C# Windows应用程序如下:
首先请允许我做一个截图: 以上,是我服务端设计 我们知道:服务器端口数最大可以有65535个,但是实际上常用的端口才几十个,由此可以看出未定义的端口相当多。因此,我们可以通过程序随机获取一个当前可用的端口 我将此方法写成了一个类,如下: using System; using System.
1056 0