TCP中间件_Delphi_client

1、界面

  1.1、formMain.pas

    1.1.1、

object frmMain: TfrmMainLeft = 191Top = 103Width = 542Height = 466Caption = 'frmMain'Color = clBtnFaceFont.Charset = DEFAULT_CHARSETFont.Color = clWindowTextFont.Height = -11Font.Name = 'MS Sans Serif'Font.Style = []OldCreateOrder = FalsePosition = poDesktopCenterOnCreate = FormCreateDesignSize = (534439)PixelsPerInch = 96TextHeight = 13object Label1: TLabelLeft = 16Top = 8Width = 41Height = 13AutoSize = FalseCaption = 'IP : 'endobject Label2: TLabelLeft = 176Top = 8Width = 49Height = 13AutoSize = FalseCaption = 'Port : 'endobject btnSetIpPort: TButtonLeft = 16Top = 32Width = 75Height = 25Caption = '设置信息'TabOrder = 0OnClick = btnSetIpPortClickendobject Memo1: TMemoLeft = 16Top = 128Width = 497Height = 299Anchors = [akLeft, akTop, akRight, akBottom]Lines.Strings = ('Memo1')ScrollBars = ssBothTabOrder = 1endobject btnSend: TButtonLeft = 96Top = 32Width = 75Height = 25Caption = '发送消息'TabOrder = 2OnClick = btnSendClickendobject btnStatus: TButtonLeft = 176Top = 32Width = 75Height = 25Caption = 'skt状态'TabOrder = 3OnClick = btnStatusClickendobject btnClearMemo: TButtonLeft = 256Top = 32Width = 89Height = 25Caption = '清空消息框'TabOrder = 4OnClick = btnClearMemoClickendobject btnAllClients: TButtonLeft = 208Top = 64Width = 137Height = 25Caption = '所有客户端信息'TabOrder = 5OnClick = btnAllClientsClickendobject btnSocket: TButtonLeft = 16Top = 96Width = 153Height = 25Caption = '客户端网络信息'TabOrder = 6OnClick = btnSocketClickendobject edtAddress: TEditLeft = 16Top = 64Width = 185Height = 21TabOrder = 7Text = 'edtAddress'endobject btnBlock: TButtonLeft = 192Top = 96Width = 153Height = 25Caption = '客户端内存块信息'TabOrder = 8OnClick = btnBlockClickendobject edtIP: TEditLeft = 40Top = 4Width = 121Height = 21TabOrder = 9Text = '192.168.1.233'endobject edtPort: TEditLeft = 216Top = 4Width = 89Height = 21TabOrder = 10Text = '9888'endobject btnFrmSQL: TButtonLeft = 432Top = 32Width = 75Height = 25Caption = 'btnFrmSQL'TabOrder = 11OnClick = btnFrmSQLClickend
end

  1.2、formSQL.pas

    1.2.1、

object frmSQL: TfrmSQLLeft = 362Top = 105Width = 457Height = 480Caption = 'frmSQL'Color = clBtnFaceFont.Charset = DEFAULT_CHARSETFont.Color = clWindowTextFont.Height = -11Font.Name = 'MS Sans Serif'Font.Style = []OldCreateOrder = FalsePosition = poDesktopCenterDesignSize = (449453)PixelsPerInch = 96TextHeight = 13object Label1: TLabelLeft = 16Top = 14Width = 145Height = 13AutoSize = FalseCaption = 'SQL语句 : 'endobject lvSQL: TListViewLeft = 16Top = 96Width = 416Height = 345Anchors = [akLeft, akTop, akRight, akBottom]Columns = <>GridLines = TrueOwnerData = TrueReadOnly = TrueRowSelect = TrueTabOrder = 0ViewStyle = vsReportOnData = lvSQLDataendobject Button1: TButtonLeft = 359Top = 8Width = 75Height = 25Anchors = [akTop, akRight]Caption = 'Button1'TabOrder = 1OnClick = Button1Clickendobject edtSQL: TEditLeft = 80Top = 10Width = 264Height = 21Anchors = [akLeft, akTop, akRight]TabOrder = 2Text = 'select * from file_tbl where rownum<5'endobject btnBLOB: TButtonLeft = 16Top = 48Width = 75Height = 25Caption = 'btnBLOB'TabOrder = 3OnClick = btnBLOBClickend
end

 

2、代码:

  2.1、formMain.pas

unit formMain;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls,classDrTcp, Winsock2;typeTfrmMain = class(TForm)Memo1: TMemo;btnSetIpPort: TButton;btnSend: TButton;btnStatus: TButton;btnClearMemo: TButton;btnAllClients: TButton;btnSocket: TButton;edtAddress: TEdit;btnBlock: TButton;Label1: TLabel;edtIP: TEdit;Label2: TLabel;edtPort: TEdit;btnFrmSQL: TButton;procedure btnSetIpPortClick(Sender: TObject);procedure btnSendClick(Sender: TObject);procedure btnClearMemoClick(Sender: TObject);procedure btnStatusClick(Sender: TObject);procedure btnAllClientsClick(Sender: TObject);procedure FormCreate(Sender: TObject);procedure btnSocketClick(Sender: TObject);procedure btnBlockClick(Sender: TObject);procedure btnFrmSQLClick(Sender: TObject);publicpublicprocedure UnpackClients(_pc :PChar; _iLen :integer);procedure UnpackSocket(_pc :PChar; _iLen :integer);procedure UnpackBlock(_pc :PChar; _iLen :integer);end;varfrmMain: TfrmMain;implementationusesformSQL;{$R *.dfm}procedure TfrmMain.FormCreate(Sender: TObject);
begin
//  edtIP.Text := '192.168.1.15';
end;procedure TfrmMain.btnSetIpPortClick(Sender: TObject);
var iPort :Integer;
begin//TdrTcpClient.SetIpPort('127.0.0.1', 9888);//TdrTcpClient.SetIpPort('192.168.1.15', 9888);//TdrTcpClient.SetIpPort('192.168.1.233', 9888);iPort := StrToIntDef(trim(edtPort.Text), 9888);TdrTcpClient.SetIpPort(Trim(edtIP.Text), iPort);
end;procedure TfrmMain.btnSendClick(Sender: TObject);
beginTdrTcpClient.SendSQL('select * from ccc');
end;procedure TfrmMain.btnStatusClick(Sender: TObject);
beginMemo1.Lines.Add(IntToStr(TdrTcpClient.Status));
end;procedure TfrmMain.btnClearMemoClick(Sender: TObject);
beginMemo1.Lines.Clear;
end;procedure TfrmMain.UnpackClients(_pc: PChar; _iLen: integer);
var iLen, iIdx :integer;str :string;ll :LONGLONG;
beginMemo1.Lines.Add('所有客户端的 IP/Port 信息 :');CopyMemory(@ll, @_pc[0], SizeOf(LONGLONG));Memo1.Lines.Add('   当前时间(ms) : '+inttostr(ll));iIdx := SizeOf(LONGLONG);Dec(_iLen, 8);while _iLen>0 dobeginCopyMemory(@ll, @_pc[iIdx], 8);Memo1.Lines.Add('           时间(ms) : '+inttostr(ll));CopyMemory(@iLen, @_pc[iIdx+8], 4);SetLength(str, iLen);CopyMemory(@str[1], @_pc[iIdx+4+8], iLen);Inc(iIdx, 4+8+iLen);Memo1.Lines.Add('         '+str);Memo1.Lines.Add('');Dec(_iLen, 4+8+iLen);end;SetLength(str, 0);
end;procedure TfrmMain.UnpackSocket(_pc: PChar; _iLen: integer);
var strIpRes, strMacRes, strReq :string;iLenIpRes, iLenMacRes, iLenReq :Integer;iLenMsg :Integer;strMsg :string;
beginCopyMemory(@iLenMsg, @_pc[0], 4);if (iLenMsg < 0) thenbeginiLenMsg := -iLenMsg;SetLength(strMsg, iLenMsg);CopyMemory(@strMsg[1], @_pc[4], iLenMsg);Memo1.Lines.Add('请求主机信息(未找到):');Memo1.Lines.Add('     '+strMsg);endelsebeginCopyMemory(@iLenIpRes, @_pc[4], 4);SetLength(strIpRes, iLenIpRes - 4);CopyMemory(@strIpRes[1], @_pc[8], iLenIpRes - 4);CopyMemory(@iLenMacRes, @_pc[4+iLenIpRes], 4);SetLength(strMacRes, iLenMacRes - 4);CopyMemory(@strMacRes[1], @_pc[4+iLenIpRes+4], iLenMacRes - 4);CopyMemory(@iLenReq, @_pc[4+iLenIpRes+iLenMacRes], 4);SetLength(strReq, iLenReq - 4);CopyMemory(@strReq[1], @_pc[4+iLenIpRes+iLenMacRes+4], iLenReq - 4);Memo1.Lines.Add('请求主机"'+strReq+'"的信息:');Memo1.Lines.Add('     IP : '+strIpRes);Memo1.Lines.Add('     Mac : '+strMacRes);end;
end;procedure TfrmMain.UnpackBlock(_pc: PChar; _iLen: integer);
var iTotalLen :Integer;iValidBeginOffset :Integer;iValidLen :Integer;dwType :DWORD;dwLastTick :DWORD;// ***
    iLenBlockMsg, iOffset, iIdx :Integer;iLenReq :Integer;strReq :string;dwTick :DWORD;
beginCopyMemory(@iLenBlockMsg, @_pc[0], 4);CopyMemory(@dwTick, @_pc[4], 4);CopyMemory(@iLenReq, @_pc[iLenBlockMsg], 4);SetLength(strReq, iLenReq-4);CopyMemory(@strReq[1], @_pc[iLenBlockMsg+4], iLenReq-4);Memo1.Lines.Add('请求主机"'+strReq+'"的信息:'+inttostr(dwTick));Memo1.Lines.Add('     '+inttostr(dwTick)+' : '+inttostr(Length(strReq)));iIdx := 0;iOffset := 8;Dec(iLenBlockMsg, iOffset);while iLenBlockMsg > 0 dobeginInc(iIdx);CopyMemory(@iTotalLen,        @_pc[iOffset+0], 4);CopyMemory(@iValidBeginOffset,@_pc[iOffset+4], 4);CopyMemory(@iValidLen,        @_pc[iOffset+8], 4);CopyMemory(@dwType,           @_pc[iOffset+12], 4);CopyMemory(@dwLastTick,       @_pc[iOffset+16], 4);Memo1.Lines.Add('   内存块('+inttostr(iIdx)+') :');Memo1.Lines.Add('       总长 : '              +inttostr(iTotalLen));Memo1.Lines.Add('       (有效数据)开始偏移 : '+inttostr(iValidBeginOffset));Memo1.Lines.Add('       (有效数据)长度 : '    +inttostr(iValidLen));Memo1.Lines.Add('       用途 : 0x'            +inttohex(dwType, 8));Memo1.Lines.Add('       最后申请时间 : '      +inttostr(dwLastTick));Inc(iOffset, 20);Dec(iLenBlockMsg, 20);end;
end;procedure TfrmMain.btnAllClientsClick(Sender: TObject);
var pc :array[0..255] of Char;iPktLen, iPktIdx, iPktType :Integer;
beging_callbackWnd.FfuncClients := UnpackClients;iPktLen := TCP_PACKET_HEADER_LEN;iPktIdx := 0;iPktType:= OP_TYPE_MANAGE_CLIENTS;CopyMemory(@pc[0], @iPktLen, 4);CopyMemory(@pc[4], @iPktIdx, 4);CopyMemory(@pc[8], @iPktType, 4);TdrTcpClient.SendBytes(@pc[0], iPktLen);
end;procedure TfrmMain.btnSocketClick(Sender: TObject);
var pc :array[0..255] of Char;iPktLen, iPktIdx, iPktType :Integer;strRemoteAddress :string;iLen :Integer;
beginstrRemoteAddress := Trim(edtAddress.Text);g_callbackWnd.FfuncSocket := UnpackSocket;iPktLen := TCP_PACKET_HEADER_LEN + (4 + Length(strRemoteAddress));iPktIdx := 0;iPktType:= OP_TYPE_MANAGE_SOCKET_REQ;CopyMemory(@pc[0], @iPktLen, 4);CopyMemory(@pc[4], @iPktIdx, 4);CopyMemory(@pc[8], @iPktType, 4);// ***iLen := 4 + Length(strRemoteAddress);CopyMemory(@pc[12], @iLen, 4);CopyMemory(@pc[16], @strRemoteAddress[1], Length(strRemoteAddress));TdrTcpClient.SendBytes(@pc[0], iPktLen);
end;procedure TfrmMain.btnBlockClick(Sender: TObject);
var pc :array[0..255] of Char;iPktLen, iPktIdx, iPktType :Integer;strRemoteAddress :string;iLen :Integer;
beginstrRemoteAddress := Trim(edtAddress.Text);g_callbackWnd.FfuncBlock := UnpackBlock;iPktLen := TCP_PACKET_HEADER_LEN + (4+Length(strRemoteAddress));iPktIdx := 0;iPktType:= OP_TYPE_MANAGE_BLOCK_REQ;CopyMemory(@pc[0], @iPktLen, 4);CopyMemory(@pc[4], @iPktIdx, 4);CopyMemory(@pc[8], @iPktType, 4);// ***iLen := 4 + Length(strRemoteAddress);CopyMemory(@pc[12], @iLen, 4);CopyMemory(@pc[16], @strRemoteAddress[1], Length(strRemoteAddress));TdrTcpClient.SendBytes(@pc[0], iPktLen);
end;procedure TfrmMain.btnFrmSQLClick(Sender: TObject);
beginfrmSQL.Show;
end;end.

  2.2、formSQL.pas

unit formSQL;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, ComCtrls, StdCtrls,classDrTcp;typeTfrmSQL = class(TForm)lvSQL: TListView;Button1: TButton;edtSQL: TEdit;Label1: TLabel;btnBLOB: TButton;procedure Button1Click(Sender: TObject);procedure lvSQLData(Sender: TObject; Item: TListItem);procedure btnBLOBClick(Sender: TObject);privateFbuffer :TdrBuffer;procedure UnpackSQL(_buffer :TdrBuffer);publicFdataSet :TdrDataSet;FiColumnCnt :Integer;end;varfrmSQL: TfrmSQL;implementationusesformMain;{$R *.dfm}procedure TfrmSQL.Button1Click(Sender: TObject);
var pc :array[0..255] of Char;iPktLen, iPktIdx, iPktType :Integer;strSql :string;iLenSQL :Integer;
beginif (Fbuffer <> nil) thenbeging_bufferPool.ReleaseBlock(Fbuffer);Fbuffer := nil;end;strSql := Trim(edtSQL.Text);iLenSQL := Length(strSql);if iLenSQL = 0 thenbeginfrmMain.Memo1.Lines.Add('no sql');Exit;end;g_callbackWnd.FfuncSQL := UnpackSQL;Inc(iLenSQL, 4);iPktLen := TCP_PACKET_HEADER_LEN + iLenSQL;iPktIdx := 0;iPktType:= OP_TYPE_MANAGE_SQL;CopyMemory(@pc[0], @iPktLen, 4);CopyMemory(@pc[4], @iPktIdx, 4);CopyMemory(@pc[8], @iPktType, 4);// ***CopyMemory(@pc[TCP_PACKET_HEADER_LEN], @iLenSQL, 4);CopyMemory(@pc[TCP_PACKET_HEADER_LEN + 4], PChar(strSql), iLenSQL - 4);TdrTcpClient.SendBytes(@pc[0], iPktLen);
end;procedure TfrmSQL.UnpackSQL(_buffer :TdrBuffer);
var columnNew :TListColumn;i :Integer;
beginif (Fbuffer <> nil) thenbeging_bufferPool.ReleaseBlock(Fbuffer);Fbuffer := nil;end;Fbuffer := _buffer;if not Assigned(FdataSet) thenFdataSet := TdrDataSet.Create;FdataSet.Unpack(@_buffer.Fpc[TCP_PACKET_HEADER_LEN], _buffer.FiValidLen - TCP_PACKET_HEADER_LEN);if (FdataSet.ColumnCount <= 0) thenExit;lvSQL.Columns.Clear;FiColumnCnt := FdataSet.ColumnCount;for i:=0 to FiColumnCnt-1 dobegincolumnNew := lvSQL.Columns.Add;columnNew.AutoSize := True;columnNew.Caption := FdataSet.GetFieldName(i);end;lvSQL.Items.Count := FdataSet.RowCount;//lvSQL.Refresh;
  lvSQL.Repaint;
end;procedure TfrmSQL.lvSQLData(Sender: TObject; Item: TListItem);
var iColIdx :Integer;rec :TdrRecord;wstr :WideString;
beginif (FdataSet = nil) then Exit;if (FdataSet.RowCount <= 0) then Exit;for iColIdx:=0 to FiColumnCnt-1 dobeginrec := FdataSet.Rec[Item.Index, iColIdx];//wstr := rec.asString;//frmMain.Memo1.Lines.Add(IntToStr(Item.Index)+','+IntToStr(iColIdx)+' : '+IntToStr(Integer(rec.FpcRecord)));if (iColIdx = 0) thenItem.Caption := rec.asStringelseItem.SubItems.Add(rec.asString);end;
end;procedure TfrmSQL.btnBLOBClick(Sender: TObject);
var item :TListItem;rec :TdrRecord;pc :PChar;iLen :Integer;
beginitem := lvSQL.Selected;frmMain.Memo1.Lines.Add('ListView select item index : '+IntToStr(item.Index));rec := FdataSet.Rec[item.Index, 3];rec.asByteArray(nil, iLen);frmMain.Memo1.Lines.Add(IntToStr(iLen));
end;end.

  2.3、classDrTcp.pas

unit classDrTcp;interfaceusesWindows, Classes, Winsock, SysUtils, Messages, Math;// Math和StrUtils里面都有 IfThen(...)函数constBUFFER_BLOCK = 1024 * 1024;TCP_PACKET_HEADER_LEN = 4 * 3;// 调试输出信息WM_TCP_RECV = WM_USER + $1000;WM_LOG_CONSOLE = WM_USER + $1001;WM_TCP_PUSH = WM_USER + 1000;WM_TCP_CLIENTS = WM_USER + 1001;WM_CLIENT_SOCKET_MSG_REQ = WM_USER + 1002;WM_CLIENT_SOCKET_MSG_RES = WM_USER + 1003;         WM_CLIENT_BLOCK_MSG_REQ  = WM_USER + 1004;WM_CLIENT_BLOCK_MSG_RES  = WM_USER + 1005;WM_MANAGE_SQL  = WM_USER + 1006;// TCP数据 操作类型:高16位:高一级类型; 低16位:低一级类型// (正值)正常的 C/S之间的业务逻辑数据OP_TYPE_SQL =       $00010000;OP_TYPE_PUSH =      $00020000;OP_TYPE_HEARTBEAT = $00030000;// (负值)C/S之间的 管理数据OP_TYPE_MANAGE =    $80000000;OP_TYPE_MANAGE_CLIENTS = $80000001; // c请求s,所有客户端的socket信息(简单)OP_TYPE_MANAGE_SOCKET_REQ =  $80000010; // c-->s,s-->c, 某个客户端的详细socket信息  (request) (搬运工)OP_TYPE_MANAGE_SOCKET_RES =  $80000020; //                                          (response)(搬运工)OP_TYPE_MANAGE_BLOCK_REQ =   $80000030; // c-->s,s-->c, 某个客户端的内存block信息   (request) (搬运工)OP_TYPE_MANAGE_BLOCK_RES =   $80000040; //                                          (response)(搬运工)OP_TYPE_MANAGE_SQL =     $80000002;    // 我的SQL语句操作OP_TYPE_RECV =   $90000000;constDR_LONGNVARCHAR = -16;DR_NCHAR        = -15;DR_NVARCHAR     = -9;DR_ROWID        = -8;DR_BIT     = -7;DR_TINYINT = -6;DR_BIGINT  = -5;DR_LONGVARBINARY= -4;DR_VARBINARY    = -3;DR_BINARY       = -2;DR_LONGVARCHAR  = -1;DR_NULL = 0;DR_CHAR = 1;DR_NUMERIC  = 2;DR_DECIMAL  = 3;DR_INTEGER  = 4;DR_SMALLINT = 5;DR_FLOAT = 6;DR_REAL  = 7;DR_DOUBLE= 8;DR_VARCHAR = 12;DR_BOOLEAN = 16;DR_DATALINK= 70;DR_DATE = 91;DR_TIME = 92;DR_TIMESTAMP = 93;DR_OTHER = 1111;DR_JAVA_OBJECT = 2000;DR_DISTINCT = 2001;DR_STRUCT = 2002;DR_ARRAY = 2003;DR_BLOB = 2004;DR_CLOB = 2005;DR_REF = 2006;DR_SQLXML = 2009;DR_NCLOB = 2011;//常量定义
ConstMAX_HOSTNAME_LEN               = 128;MAX_DOMAIN_NAME_LEN            = 128;MAX_SCOPE_ID_LEN               = 256;MAX_ADAPTER_NAME_LENGTH        = 256;MAX_ADAPTER_DESCRIPTION_LENGTH = 128;MAX_ADAPTER_ADDRESS_LENGTH     = 8;
//定义相关结构
TypeTIPAddressString = Array[0..4*4-1] of Char;PIPAddrString = ^TIPAddrString;TIPAddrString = RecordNext      : PIPAddrString;IPAddress : TIPAddressString;IPMask    : TIPAddressString;Context   : Integer;end;PFixedInfo = ^TFixedInfo;TFixedInfo = Record { FIXED_INFO }HostName         : Array[0..MAX_HOSTNAME_LEN+3] of Char;DomainName       : Array[0..MAX_DOMAIN_NAME_LEN+3] of Char;CurrentDNSServer : PIPAddrString;DNSServerList    : TIPAddrString;NodeType         : Integer;ScopeId          : Array[0..MAX_SCOPE_ID_LEN+3] of Char;EnableRouting    : Integer;EnableProxy      : Integer;EnableDNS        : Integer;end;PIPAdapterInfo = ^TIPAdapterInfo;TIPAdapterInfo = Record { IP_ADAPTER_INFO }Next                : PIPAdapterInfo;ComboIndex          : Integer;AdapterName         : Array[0..MAX_ADAPTER_NAME_LENGTH+3] of Char;Description         : Array[0..MAX_ADAPTER_DESCRIPTION_LENGTH+3] of Char;AddressLength       : Integer;Address             : Array[1..MAX_ADAPTER_ADDRESS_LENGTH] of Byte;Index               : Integer;_Type               : Integer;DHCPEnabled         : Integer;CurrentIPAddress    : PIPAddrString;IPAddressList       : TIPAddrString;GatewayList         : TIPAddrString;DHCPServer          : TIPAddrString;HaveWINS            : Bool;PrimaryWINSServer   : TIPAddrString;SecondaryWINSServer : TIPAddrString;LeaseObtained       : Integer;LeaseExpires        : Integer;end;function GetAdaptersInfo(_ai : PIPAdapterInfo; var _dwBufLen : DWORD) : Integer;StdCall;external 'iphlpapi.dll';typeTdrBuffer = classpublicFpc :PChar;FiTotalLen :Integer;FiValidBeginOffset :Integer;FiValidLen :Integer;FdwType :DWORD; // 用于什么的? TCP接收/SQL/PUSH/...?FdwLastTick :DWORD; // 最后一次被Aquire时候的GetTickCountend;TdrBufferPool = class//(TObject)publicconstructor create;destructor destroy;override;privateFlist :TList;FlistAll :TList;//... 这个没弄,还有加锁没弄...FhEvent :THandle;//...privatefunction NewBlock(_iLen :Integer = 0) :TdrBuffer;function DelBlock(_buffer :TdrBuffer) :Integer;publicfunction AquireBlock(_dwType :DWORD; _iLen :Integer) :TdrBuffer;function ReleaseBlock(_buffer :TdrBuffer) :Integer;publicproperty ListAll :TList read FlistAll;end;// ***TdrRecvBuffer = class//(TObject)publicconstructor Create;destructor Destroy;override;privateFlist :TList;FiTotalLen :Integer;FiPktIdx :Integer;   // TCP包 序号
    FhEvent :THandle;FiFirstPktLen :Integer;publicfunction BufferAuqire(out _pc :PChar; out _iLen :integer) :integer;function BufferReleaseAll :integer;function BufferRecv(_iRecv :Integer; _iBlockIdx: integer) :Integer;function BufferHandleAll :Integer;// 处理所有已经接收到的 TCP包privatefunction BufferHandle :Integer;// 处理单个 TCP包// ***private// 从接收到的缓冲区里面 得到TCP包头的信息function TcpPktHeader(out _iPktLen, _iPktIdx, _iPktType :Integer) :Integer; // 始终默认是 [0]的缓冲区块// 从TCP包头的信息中,判断 我们是否需要这个TCP包(0:不需要; >0:需要; <0:出错信息)function TcpPktIsNeed(_iPktIdx, _iPktType :integer):Integer;procedure TcpPktDispatch(_buffer :TdrBuffer);end;// ***TdrTcpClient = class(TThread)publicFiErrorNo :Integer;FiStatus :integer; // 线程的状态(0:初始状态; 1:运行中; -1:结束)publicFskt :TSocket;privatefunction RecvTimeoutSet :Integer;function RecvTimeoutCancel :Integer;function Recv01() :Integer;protectedprocedure Execute; override;publicfunction Send01(_pbyte :PByte; _iLen :integer) :Integer;publicclass procedure SetIpPort(_strDestIp :string; _iDestPort :integer);class function Conn :Integer;class procedure SendSQL(_str :string);class procedure SendBytes(_pc :PChar; _iLen :Integer);class function ConnectDest :TSocket;class function Status :Integer;class procedure SendHeartBeat;end;// ***TdrDataSet = class;TdrRecord = classpublicconstructor Create(_dataset :TdrDataSet; _iRowIdx, _iColumnIdx :Integer);procedure FenXi;privateFdataset :TdrDataSet;FiRowIdx, FiColumnIdx :Integer;FpcRecord :PChar; // 指向某个Record的指针publicfunction asByteArray(_pByte :PByte; out _iLen :Integer) :Integer;function asInteger :Integer;function asSingle :Single;function asDouble :Double;function asString :string;privatefunction GetFieldType :Integer;function GetFieldTypeName :string;function GetFieldName :string;publicproperty FieldType :Integer read GetFieldType;property FieldTypeName :string read GetFieldTypeName;property FieldName :string read GetFieldName;end;TdrDataSet = classpublicfunction Unpack(_pc :PChar; _iLen :Integer) :integer;privateFpcBuf :PChar;FiBufLen :Integer; // 缓冲区中 有效数据的长度FaryColumnType :array of Integer;FaryColumnName :array of string;FaryaryRecord :array of array of Integer; // 指向各个Record的指针publicfunction GetFieldType(_iColumnIdx :integer) :Integer;function GetFieldTypeName(_iColumnIdx :integer) :string;function GetFieldName(_iColumnIdx :integer) :string;privateFfield :TdrRecord; // 这个属性有且只有一个publicfunction GetRecord(_iRowIdx, _iColumnIdx :integer):TdrRecord;property Rec[_iRow, _iCol :Integer] :TdrRecord read GetRecord;publicfunction GetRowCount :Integer;function GetColumnCount :Integer;property RowCount: integer read GetRowCount;property ColumnCount: integer read GetColumnCount;end;// ***TfuncPush = procedure(_pc :PChar; _iLen :integer) of Object;TfuncCallback = procedure(_pc :PChar; _iLen :integer) of Object;TfuncCallback_Buf = procedure(_buffer :TdrBuffer) of Object;TcallbackWnd = classpublicconstructor Create;publicFhWnd :HWND;FdwErrNo :DWORD;privateprocedure CreateWindow;public     // 打包 信息function PackSocket(_pc :PChar; _iLen :integer) :integer;procedure PackBlock(_pc :PChar; _iLen :integer);publicFfuncPush :TfuncPush;FfuncClients :TfuncCallback;   // 拆包 信息
    FfuncSocket :TfuncCallback;FfuncBlock :TfuncCallback;FfuncSQL :TfuncCallback_Buf;end;function ProcWindow(_hWnd :HWND; _uMsg :UINT; _wParam :WPARAM; _lParam :LPARAM):longint;stdcall;function ErrorNo2Str(_dwErrNo :DWORD):string;procedure BufferBlockUsage(_iOpType :Integer; var _str :string);varg_callbackWnd :TcallbackWnd = nil;  // 需要 自己新建g_bufferPool :TdrBufferPool = nil;  // 需要 自己新建implementationusesformMain;varg_drRecvBuffer :TdrRecvBuffer = nil;// 需要 自己新建g_tcpClient :TdrTcpClient = nil;    // 需要 自己新建(动态创建,不是在initialization下面创建)g_bufferSql :TdrBuffer = nil;//g_bufferPush :TdrBuffer = nil;
// ***g_strDestIp :string;g_iDestPort :integer;//g_tcpClient :TdrTcpClient = nil;    // 需要 自己新建(动态创建,不是在initialization下面创建)// ***procedure LogConsole(_str :string);
var pc :PChar;iLen :Integer;
beginiLen := Length(_str);GetMem(pc, iLen);PostMessage(g_callbackWnd.FhWnd, WM_LOG_CONSOLE, WParam(iLen), LParam(pc));
end;function LogFile(_str :string) :integer;
var hFile :THandle;strFileName :string;dwWritten :DWORD;lb :LongBool;
beginResult := 0;strFileName := ParamStr(0)+'.'+FormatDateTime('yyyymmdd', now)+'.log';hFile := CreateFile(PChar(strFileName), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_NEW, 0, 0);if (hFile = INVALID_HANDLE_VALUE) thenbeginResult := GetLastError;Exit;end;lb := Windows.SetEndOfFile(hFile);if (not lb) thenbeginResult := GetLastError;CloseHandle(hFile);Exit;end;dwWritten := 0;lb := Windows.WriteFile(hFile, _str[1], Length(_str), dwWritten, nil);if (not lb) thenbeginResult := GetLastError;CloseHandle(hFile);Exit;end;CloseHandle(hFile);
end;function FieldTypeName_f(_iFieldType :Integer; var _strFieldTypeName :string) :Integer;
begincase _iFieldType ofDR_LONGNVARCHAR : _strFieldTypeName := 'DR_LONGNVARCHAR';DR_NCHAR : _strFieldTypeName := 'DR_NCHAR';DR_NVARCHAR : _strFieldTypeName := 'DR_NVARCHAR';DR_ROWID : _strFieldTypeName := 'DR_ROWID';DR_BIT : _strFieldTypeName := 'DR_BIT';DR_TINYINT : _strFieldTypeName := 'DR_TINYINT';DR_BIGINT : _strFieldTypeName := 'DR_BIGINT';DR_LONGVARBINARY : _strFieldTypeName := 'DR_LONGVARBINARY';DR_VARBINARY : _strFieldTypeName := 'DR_VARBINARY';DR_BINARY : _strFieldTypeName := 'DR_BINARY';DR_LONGVARCHAR : _strFieldTypeName := 'DR_LONGVARCHAR';DR_NULL : _strFieldTypeName := 'DR_NULL';DR_CHAR : _strFieldTypeName := 'DR_CHAR';DR_NUMERIC : _strFieldTypeName := 'DR_NUMERIC';DR_DECIMAL : _strFieldTypeName := 'DR_DECIMAL';DR_INTEGER : _strFieldTypeName := 'DR_INTEGER';DR_SMALLINT : _strFieldTypeName := 'DR_SMALLINT';DR_FLOAT : _strFieldTypeName := 'DR_FLOAT';DR_REAL : _strFieldTypeName := 'DR_REAL';DR_DOUBLE : _strFieldTypeName := 'DR_DOUBLE';DR_VARCHAR : _strFieldTypeName := 'DR_VARCHAR';DR_BOOLEAN : _strFieldTypeName := 'DR_BOOLEAN';DR_DATALINK : _strFieldTypeName := 'DR_DATALINK';DR_DATE : _strFieldTypeName := 'DR_DATE';DR_TIME : _strFieldTypeName := 'DR_TIME';DR_TIMESTAMP : _strFieldTypeName := 'DR_TIMESTAMP';DR_OTHER : _strFieldTypeName := 'DR_OTHER';DR_JAVA_OBJECT : _strFieldTypeName := 'DR_JAVA_OBJECT';DR_DISTINCT : _strFieldTypeName := 'DR_DISTINCT';DR_STRUCT : _strFieldTypeName := 'DR_STRUCT';DR_ARRAY : _strFieldTypeName := 'DR_ARRAY';DR_BLOB : _strFieldTypeName := 'DR_BLOB';DR_CLOB : _strFieldTypeName := 'DR_CLOB';DR_REF : _strFieldTypeName := 'DR_REF';DR_SQLXML : _strFieldTypeName := 'DR_SQLXML';DR_NCLOB : _strFieldTypeName := 'DR_NCLOB';else_strFieldTypeName := 'Unknown('+inttostr(_iFieldType)+')';end;
end;procedure GetMacByIP(_iIp :integer; var _strMac :string);
var adapterInfo, pInfo : PIPAdapterInfo;dwSize    : DWORD;iRes     : Integer;ipAddrStr :TIPAddrString;pIpAddrStr :PIPAddrString;i :Integer;iIp :Integer;bFind :Boolean;
beginbFind := false;dwSize := 0;GetAdaptersInfo(nil, dwSize);GetMem(adapterInfo, dwSize);iRes := GetAdaptersInfo(adapterInfo, dwSize);If (iRes <> ERROR_SUCCESS) ThenbeginMessageBoxA(0,'获取IP信息失败', '错误', MB_OK or MB_ICONERROR);exit;end;pInfo := adapterInfo;repeat// IP地址ipAddrStr := pInfo.IPAddressList;iIp := inet_addr(ipAddrStr.IPAddress);if (_iIp = iIp) thenbeginbFind := True;_strMac := '';for i:=1 to pInfo.AddressLength dobegin_strMac := _strMac + IntToHex(pInfo.Address[i], 2);if (i <> pInfo.AddressLength) then_strMac := _strMac + ':';end;Break;end;pIpAddrStr := ipAddrStr.Next;while pIpAddrStr<>nil dobeginiIp := inet_addr(ipAddrStr.IPAddress);if (_iIp = iIp) thenbeginbFind := True;_strMac := '';for i:=1 to pInfo.AddressLength dobegin_strMac := _strMac + IntToHex(pInfo.Address[i], 2);if (i <> pInfo.AddressLength) then_strMac := _strMac + ':';end;Break;end;pIpAddrStr := pIpAddrStr.Next;end;if (bFind) then Break;pInfo := pInfo^.Next;until (pInfo = nil);FreeMem(adapterInfo);
end;procedure BufferBlockUsage(_iOpType :Integer; var _str :string);
beginif (_iOpType = OP_TYPE_SQL) then_str := 'SQL语句'else if (_iOpType = OP_TYPE_PUSH) then_str := 'TCP推送'else if (_iOpType = OP_TYPE_MANAGE) then_str := '管理数据'else if (_iOpType = OP_TYPE_MANAGE_CLIENTS) then_str := '管理(所有客户端IP/Port)'else if (_iOpType = OP_TYPE_MANAGE_SOCKET_RES) then_str := '管理(某客户端socket信息)'else if (_iOpType = OP_TYPE_MANAGE_BLOCK_RES) then_str := '管理(某客户端内存块信息)'else if (_iOpType = OP_TYPE_RECV) then_str := 'TCP接收缓冲';
end;function MAKELANGID(_p, _s :word) :DWORD;
beginResult := (_s shl 10) or (_p);
end;function ErrorNo2Str(_dwErrNo :DWORD):string;
constLANG_NEUTRAL = $0;SUBLANG_DEFAULT = $01;
var buf :array[0..255] of Char;
beginZeroMemory(@buf[0], Length(buf));Windows.FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_IGNORE_INSERTS,nil,_dwErrNo,     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),buf,Length(buf),nil);Result := buf;
end;{ TdrBufferPool }constructor TdrBufferPool.create;
begin//inherited Create;Flist := TList.Create;FlistAll := TList.Create;FhEvent := CreateEvent(nil, False, true, nil);
end;destructor TdrBufferPool.destroy;//override;
beginif Assigned(Flist) thenFlist.Free;inherited;
end;function TdrBufferPool.NewBlock(_iLen: Integer): TdrBuffer;
var iYuShu :Integer;
beginiYuShu := _iLen mod BUFFER_BLOCK;Result := TdrBuffer.Create;if (_iLen<>0)and(iYuShu = 0) thenResult.FiTotalLen := _iLenelseResult.FiTotalLen := (_iLen div BUFFER_BLOCK + 1) * BUFFER_BLOCK;GetMem(Result.Fpc, Result.FiTotalLen);Result.FiValidBeginOffset := 0;Result.FiValidLen := 0;FlistAll.Add(Result);
end;function TdrBufferPool.DelBlock(_buffer :TdrBuffer) :Integer;
var iIdx :Integer;
beginResult := 0;iIdx := FlistAll.IndexOf(_buffer);FlistAll.Delete(iIdx);if (iIdx = -1) thenResult := -1;
end;function TdrBufferPool.AquireBlock(_dwType :DWORD; _iLen: Integer): TdrBuffer;
var iAquireLen, i, iIdx, iYuShu :Integer;buffer :TdrBuffer;
beginResult := nil;WaitForSingleObject(FhEvent, INFINITE);tryif (Flist.Count = 0) thenResult := NewBlock(_iLen)elsebeginiIdx := -1;iYuShu := _iLen mod BUFFER_BLOCK;if (_iLen<>0)and(iYuShu = 0) theniAquireLen := _iLenelseiAquireLen := (_iLen div BUFFER_BLOCK + 1) * BUFFER_BLOCK;for i:=0 to Flist.Count-1 dobeginbuffer := TdrBuffer(Flist.Items[i]);if iAquireLen <= buffer.FiTotalLen thenbeginiIdx := i;break;end;end;if (iIdx = -1) thenResult := NewBlock(_iLen)elsebeginResult := TdrBuffer(Flist.Items[iIdx]);Flist.Delete(iIdx);end;Result.FiValidBeginOffset := 0;Result.FiValidLen := 0;end;Result.FdwType := _dwType;PostMessage(g_callbackWnd.FhWnd, WM_TCP_RECV, 1, _dwType);Result.FdwLastTick := GetTickCount;finallySetEvent(FhEvent);end;
end;function TdrBufferPool.ReleaseBlock(_buffer: TdrBuffer): Integer;
constBUFFER_BLOCK_MAX_LEN = 1024 * 1024 * 500; // >=这个数的内存,采取直接释放内存缓冲区的操作方式
var i :Integer;buffer0, buffer1 :TdrBuffer;
beginPostMessage(g_callbackWnd.FhWnd, WM_TCP_RECV, 2, _buffer.FdwType);_buffer.FdwType := 0;Result := 0;WaitForSingleObject(FhEvent, INFINITE);tryif (_buffer.FiTotalLen >= BUFFER_BLOCK_MAX_LEN) then  // >=这个数的内存,采取直接释放内存缓冲区的操作方式beginDelBlock(_buffer);FreeMem(_buffer.Fpc, _buffer.FiTotalLen);_buffer.Free;Exit;end;if (Flist.Count = 0) thenbeginFlist.Add(_buffer);Exit;end;buffer0 := TdrBuffer(Flist.Items[0]);if (_buffer.FiTotalLen <= buffer0.FiTotalLen) thenbeginFlist.Insert(0, _buffer);Exit;endelsebeginfor i:=1 to Flist.Count-1 dobeginbuffer0 := TdrBuffer(Flist.Items[i-1]);buffer1 := TdrBuffer(Flist.Items[i]);if (_buffer.FiTotalLen > buffer0.FiTotalLen)and(_buffer.FiTotalLen <= buffer1.FiTotalLen) thenbeginFlist.Insert(i, _buffer);Exit;end;end;Flist.Add(_buffer);end;finallySetEvent(FhEvent);end;
end;{ TdrRecvBuffer }constructor TdrRecvBuffer.Create;
beginFlist := TList.Create;FhEvent := CreateEvent(nil, False, false, nil);
end;destructor TdrRecvBuffer.destroy;//override;
beginif Assigned(Flist) thenFlist.Free;if (FhEvent<>0) thenCloseHandle(FhEvent);inherited;
end;function TdrRecvBuffer.BufferAuqire(out _pc: PChar; out _iLen: integer): integer;
var buffer, bufferNew :TdrBuffer;iCnt1, iCntUsed :Integer;
beginResult := -1;if (Flist.Count = 0) thenbeginbufferNew := g_bufferPool.AquireBlock(OP_TYPE_RECV, 0);Flist.Add(bufferNew);Result := Flist.Count - 1;_pc := bufferNew.Fpc;_iLen := bufferNew.FiTotalLen;endelsebeginbuffer := TdrBuffer(Flist.Items[Flist.Count - 1]);if (buffer.FiValidBeginOffset + buffer.FiValidLen) > buffer.FiTotalLen thenraise Exception.CreateFmt('TdrRecvBuffer.BufferAuqire 缓冲区错误(1) : %d, %d, %d',[buffer.FiValidBeginOffset, buffer.FiValidLen, buffer.FiTotalLen])else if (buffer.FiValidBeginOffset + buffer.FiValidLen) = buffer.FiTotalLen thenbeginbufferNew := g_bufferPool.AquireBlock(OP_TYPE_RECV, 0);Flist.Add(bufferNew);Result := Flist.Count - 1;_pc := bufferNew.Fpc;_iLen := bufferNew.FiTotalLen;endelse// if (buffer.FiValidBeginOffset + buffer.FiValidLen) < buffer.FiTotalLen thenbeginiCntUsed := buffer.FiValidBeginOffset + buffer.FiValidLen;_pc := @buffer.Fpc[iCntUsed];_iLen := buffer.FiTotalLen - iCntUsed;Result := Flist.Count - 1;end;end;
end;function TdrRecvBuffer.BufferReleaseAll :integer;
beginwhile Flist.Count > 0 dobeging_bufferPool.ReleaseBlock(TdrBuffer(Flist.Items[0]));Flist.Delete(0);end;
end;function TdrRecvBuffer.BufferRecv(_iRecv: Integer; _iBlockIdx: integer): Integer;
var iCntUsed :Integer;buffer :TdrBuffer;
beginResult := 0;Inc(FiTotalLen, _iRecv);buffer := TdrBuffer(Flist.Items[_iBlockIdx]);Inc(buffer.FiValidLen, _iRecv);if (buffer.FiValidBeginOffset + buffer.FiValidLen) > buffer.FiTotalLen thenraise Exception.CreateFmt('TdrRecvBuffer.BufferRecv 缓冲区错误(1) : %d, %d, %d',[buffer.FiValidBeginOffset, buffer.FiValidLen, buffer.FiTotalLen]);
end;function TdrRecvBuffer.BufferHandle: Integer;   // 处理单个 TCP包
var bufferCopy, buffer :TdrBuffer;iRtn, iPktIsNeed :Integer;iPktLen, iPktIdx, iPktType :Integer;iPktLen01 :Integer;iBlockIdx, iBlockDropEndIdx :Integer;iCopyOffset, i, iCopyLen :Integer;bNeedBreak :Boolean;
beginResult := 0;if (FiTotalLen < TCP_PACKET_HEADER_LEN) then // 一个TCP包都没有接收完毕beginResult := 1;Exit;end;if (FiFirstPktLen <> 0) and (FiTotalLen < FiFirstPktLen) thenbeginResult := 2;Exit;end;iRtn := TcpPktHeader(iPktLen, iPktIdx, iPktType);FiFirstPktLen := iPktLen;if (FiTotalLen < iPktLen) then // 一个TCP包都没有接收完毕beginResult := 3;Exit;end;FiFirstPktLen := 0;iPktIsNeed := TcpPktIsNeed(iPktIdx, iPktType);// *** (1) *** 缓冲区的分配/获取bufferCopy := nil;if (iPktIsNeed > 0) thenbufferCopy := g_bufferPool.AquireBlock(iPktType, iPktLen);// *** (2) *** 缓冲区内容填充iCopyOffset := 0;iBlockIdx := 0;iPktLen01 := iPktLen;iBlockDropEndIdx := -1;while (iPktLen01 > 0) dobeginbNeedBreak := false;if (iBlockIdx >= Flist.Count) thenraise Exception.CreateFmt('TdrRecvBuffer.BufferHandle 缓冲区错误(1) : %d, %d', [iBlockIdx, Flist.Count]);buffer := TdrBuffer(Flist.Items[iBlockIdx]);if (buffer.FiValidBeginOffset + buffer.FiValidLen) > buffer.FiTotalLen thenraise Exception.CreateFmt('TdrRecvBuffer.BufferHandle 缓冲区错误(2) : %d, %d, %d, %d',[iBlockIdx, buffer.FiValidBeginOffset, buffer.FiValidLen, buffer.FiTotalLen])else if (buffer.FiValidBeginOffset + buffer.FiValidLen) = buffer.FiTotalLen thenbeginif iBlockDropEndIdx <> (iBlockIdx-1) thenraise Exception.CreateFmt('TdrRecvBuffer.BufferHandle 缓冲区错误(3) : %d, %d, %d', [iBlockIdx, iBlockDropEndIdx, iBlockIdx]);iBlockDropEndIdx := iBlockIdx;endelse// if (buffer.FiValidBeginOffset + buffer.FiValidLen) < buffer.FiTotalLen thenbNeedBreak := True;if (not bNeedBreak) thenbegin // 不是 某TCP包中的最后一块内存块的话,内存块的尾端肯定是占满的if (buffer.FiValidBeginOffset + buffer.FiValidLen) <> buffer.FiTotalLen thenraise Exception.CreateFmt('TdrRecvBuffer.BufferHandle 缓冲区错误(4) : %d, %d, %d, %d',[iBlockIdx, buffer.FiValidBeginOffset, buffer.FiValidLen, buffer.FiTotalLen]);end;// 缓冲区数据 复制// 三部曲:(1)计算iCopyLen (2)CopyMemory (3)计算3个数值iCopyLen := 0;if (iBlockIdx = 0) thenbeginiCopyLen := Math.IfThen(iPktLen01 > buffer.FiValidLen, buffer.FiValidLen, iPktLen01);if (bufferCopy <> nil) thenCopyMemory(@bufferCopy.Fpc[iCopyOffset], @buffer.Fpc[buffer.FiValidBeginOffset], iCopyLen);Dec(iPktLen01, iCopyLen);Inc(buffer.FiValidBeginOffset, iCopyLen); // 缓冲区指针移动
      Dec(buffer.FiValidLen, iCopyLen);endelsebeginif buffer.FiValidBeginOffset <> 0 thenraise Exception.CreateFmt('TdrRecvBuffer.BufferHandle 缓冲区错误(5) : %d, %d', [iBlockIdx, buffer.FiValidBeginOffset]);iCopyLen := Math.IfThen(iPktLen01 > buffer.FiValidLen, buffer.FiValidLen, iPktLen01);if (bufferCopy <> nil) thenCopyMemory(@bufferCopy.Fpc[iCopyOffset], @buffer.Fpc[0], iCopyLen);Dec(iPktLen01, iCopyLen);Inc(buffer.FiValidBeginOffset, iCopyLen); // 缓冲区指针移动
      Dec(buffer.FiValidLen, iCopyLen);end;Inc(bufferCopy.FiValidLen, iCopyLen);Inc(iCopyOffset, iCopyLen);// ***if (iCopyOffset > bufferCopy.FiTotalLen) thenraise Exception.CreateFmt('TdrRecvBuffer.BufferHandle 缓冲区错误(6) : %d, %d, %d', [iBlockIdx, iCopyOffset, bufferCopy.FiTotalLen]);if (bNeedBreak) thenbeginif (iPktLen01 <> 0) thenraise Exception.CreateFmt('TdrRecvBuffer.BufferHandle 缓冲区错误(7) : %d, %d', [iBlockIdx, buffer.FiValidBeginOffset]);break;end;Inc(iBlockIdx);end; // while// *** (3) *** 缓冲区 分发
  TcpPktDispatch(bufferCopy);// 扫尾处理
  Dec(FiTotalLen, iPktLen);if iBlockDropEndIdx > -1 thenfor i:=0 to iBlockDropEndIdx dobeging_bufferPool.ReleaseBlock(TdrBuffer(Flist.Items[0]));Flist.Delete(0);end;
end;function TdrRecvBuffer.BufferHandleAll: Integer;  // 处理所有已经接收到的 TCP包
var iRtn : integer;
beginResult := 0;while FiTotalLen > (TCP_PACKET_HEADER_LEN) dobeginiRtn := BufferHandle;if (iRtn > 0) thenbreak;end;
end;function TdrRecvBuffer.TcpPktHeader(out _iPktLen, _iPktIdx, _iPktType: Integer): Integer;  // 始终默认是 [0]的缓冲区块
var aryByte12 :array[0..11] of Char;buffer :TdrBuffer;iCntLeft :Integer;pi :PInteger;
beginResult := 0;buffer := TdrBuffer(Flist.Items[0]);if (buffer.FiValidLen >= TCP_PACKET_HEADER_LEN) thenbeginpi := @buffer.Fpc[buffer.FiValidBeginOffset + 0];  _iPktLen := pi^;pi := @buffer.Fpc[buffer.FiValidBeginOffset + 4];  _iPktIdx := pi^;pi := @buffer.Fpc[buffer.FiValidBeginOffset + 8];  _iPktType:= pi^;endelsebeginif (Flist.Count = 1) thenraise Exception.CreateFmt('TdrRecvBuffer.TcpPktHeader 缓冲区错误(1) : %d', [Flist.Count]);iCntLeft := TCP_PACKET_HEADER_LEN - buffer.FiValidLen;CopyMemory(@aryByte12[0], @buffer.Fpc[buffer.FiValidBeginOffset], buffer.FiValidLen);buffer := TdrBuffer(Flist.Items[1]);if (buffer.FiValidBeginOffset <> 0)or(buffer.FiValidLen < iCntLeft) thenraise Exception.CreateFmt('TdrRecvBuffer.TcpPktHeader 缓冲区错误(2) : %d, %d, %d',[buffer.FiValidBeginOffset, buffer.FiValidLen, iCntLeft]);CopyMemory(@aryByte12[0], @buffer.Fpc[0], iCntLeft);pi := @aryByte12[0];  _iPktLen := pi^;pi := @aryByte12[4];  _iPktIdx := pi^;pi := @aryByte12[8];  _iPktType:= pi^;end;
end;function TdrRecvBuffer.TcpPktIsNeed(_iPktIdx, _iPktType :integer):Integer;
beginResult := 0;if (_iPktType = OP_TYPE_SQL) then // 主动的SQL语句请求beginif (_iPktIdx = FiPktIdx) thenResult := 1;endelse if (_iPktType = OP_TYPE_PUSH) then // TCP服务端推送消息beginResult := 1;endelse if (_iPktType and OP_TYPE_MANAGE) <> 0 then // 管理beginResult := 1;end;
end;procedure TdrRecvBuffer.TcpPktDispatch(_buffer :TdrBuffer);
var pi :PInteger;iPktLen, iPktIdx, iPktType :Integer;
beginpi := @_buffer.Fpc[4];  iPktIdx := pi^;pi := @_buffer.Fpc[8];  iPktType:= pi^;if (iPktType = OP_TYPE_SQL) then // 主动的SQL语句请求beginif (iPktIdx = FiPktIdx) thenSetEvent(FhEvent);endelse if (iPktType = OP_TYPE_PUSH) then // TCP服务端推送消息beginPostMessage(g_callbackWnd.FhWnd, WM_TCP_PUSH, 0, LParam(_buffer));endelse if (iPktType and OP_TYPE_MANAGE) <> 0 then // 管理beginif DWORD(iPktType) = OP_TYPE_MANAGE_CLIENTS then // 所有客户端的信息PostMessage(g_callbackWnd.FhWnd, WM_TCP_CLIENTS, 0, LParam(_buffer))else if DWORD(iPktType) = OP_TYPE_MANAGE_SOCKET_REQ thenPostMessage(g_callbackWnd.FhWnd, WM_CLIENT_SOCKET_MSG_REQ, 0, LParam(_buffer))else if DWORD(iPktType) = OP_TYPE_MANAGE_SOCKET_RES thenPostMessage(g_callbackWnd.FhWnd, WM_CLIENT_SOCKET_MSG_RES, 0, LParam(_buffer))else if DWORD(iPktType) = OP_TYPE_MANAGE_BLOCK_REQ thenPostMessage(g_callbackWnd.FhWnd, WM_CLIENT_BLOCK_MSG_REQ, 0, LParam(_buffer))else if DWORD(iPktType) = OP_TYPE_MANAGE_BLOCK_RES thenPostMessage(g_callbackWnd.FhWnd, WM_CLIENT_BLOCK_MSG_RES, 0, LParam(_buffer))else if DWORD(iPktType) = OP_TYPE_MANAGE_SQL thenPostMessage(g_callbackWnd.FhWnd, WM_MANAGE_SQL, 0, LParam(_buffer))elsebeginend;end;
end;{ TdrTcpClient }function TdrTcpClient.RecvTimeoutSet: Integer;
var iRecvTimeout, iRtn :Integer;
beginResult := 0;iRecvTimeout := 1; // 毫秒iRtn := setsockopt(Fskt, SOL_SOCKET, SO_RCVTIMEO, PChar(@iRecvTimeout), sizeof(integer));if SOCKET_ERROR = iRtn thenbeginResult := GetLastError;FiErrorNo := Result;end;
end;function TdrTcpClient.RecvTimeoutCancel: Integer;
var iRecvTimeout, iRtn :Integer;
beginResult := 0;iRecvTimeout := 0; // 毫秒iRtn := setsockopt(Fskt, SOL_SOCKET, SO_RCVTIMEO, PChar(@iRecvTimeout), sizeof(integer));if SOCKET_ERROR = iRtn thenbeginResult := GetLastError;FiErrorNo := Result;end;
end;procedure TdrTcpClient.Execute;
var pcRecv :PChar;iLenRecv :Integer;iRecvBlockIdx :integer;iRecv, iRtn :Integer;
begin//inherited;
  g_drRecvBuffer.BufferReleaseAll;FiStatus := 1;while True dobeginiRecvBlockIdx := g_drRecvBuffer.BufferAuqire(pcRecv, iLenRecv);iRecv := recv(Fskt, pcRecv^, iLenRecv, 0);if (iRecv = 0) then // 连接优雅(gracefully)关闭beginFiErrorNo := 0;break;endelse if (iRecv < 0) thenbeginFiErrorNo := GetLastError;break;endelse// if (iRecv > 0) thenbeging_drRecvBuffer.BufferRecv(iRecv, iRecvBlockIdx);g_drRecvBuffer.BufferHandleAll;PostMessage(g_callbackWnd.FhWnd, WM_TCP_RECV, 0, iRecv);end;
// ZC: 用timeout操作的时候,在数据读完之后 有明显感觉的卡顿现象(大概有1s左右)...于是,放弃使用timeout读数据
//    iRtn := Recv01;
//    if (iRtn <= 0) then
//      break;
//    g_drRecvBuffer.BufferHandleAll;end;closesocket(Fskt);FiStatus := -1;// 线程执行完毕(退出)//raise Exception.CreateFmt('socket线程退出 : %d', [FiErrorNo]);
end;function TdrTcpClient.Recv01: Integer;
var pcRecv :PChar;iLenRecv :Integer;iRecvBlockIdx :integer;iRecv :Integer;
beginResult := 0;if RecvTimeoutSet<>0 thenbeginResult := GetLastError;Exit;end;while true dobeginiRecvBlockIdx := g_drRecvBuffer.BufferAuqire(pcRecv, iLenRecv);iRecv := recv(Fskt, pcRecv^, iLenRecv, 0);if (iRecv = 0) then // 连接优雅(gracefully)关闭beginResult := -1;FiErrorNo := 0;endelse if (iRecv < 0) thenbeginFiErrorNo := GetLastError;if WSAETIMEDOUT <> FiErrorNo thenbeginResult := -2;endelsebeginResult := 1;end;break;endelse// if (iRecv > 0) thenbeging_drRecvBuffer.BufferRecv(iRecv, iRecvBlockIdx);if (iRecv <> iLenRecv) thenbeginResult := 2;Break;end;end;end;if RecvTimeoutCancel <> 0 thenResult := GetLastError;
end;function TdrTcpClient.Send01(_pbyte: PByte; _iLen: integer): Integer;
var iRtn :Integer;
beginResult := 0;iRtn := send(Fskt, _pbyte^, _iLen, 0);if iRtn = SOCKET_ERROR thenResult := GetLastError;
end;class function TdrTcpClient.Conn :integer;
var skt :TSocket;bNeedCreate :boolean;
beginResult := 0;if (length(g_strDestIp)=0)or(g_iDestPort=0) thenbeginraise Exception.Create('服务器IP/Poer 未设置');Exit;end;bNeedCreate := false;if (g_tcpClient = nil) thenbNeedCreate := trueelsebeginif (g_tcpClient.FiStatus = 0) thenbeginResult := -1;Exit;endelse if (g_tcpClient.FiStatus = -1) thenbeginbNeedCreate := True;g_tcpClient.Free;end;end;if (bNeedCreate) thenbeginskt := TdrTcpClient.ConnectDest;g_tcpClient := TdrTcpClient.Create(false);g_tcpClient.Fskt := skt;end;
end;class procedure TdrTcpClient.SendSQL(_str: string);
var iPktLen, iPktIdx, iPktType :Integer;bytesSend :array[0..255] of byte;iRtn :Integer;
beginif Conn < 0 thenraise Exception.Create('TCP接收线程正在初始化,请稍后再试...');Inc(g_drRecvBuffer.FiPktIdx);iPktLen := TCP_PACKET_HEADER_LEN + Length(_str);iPktIdx := g_drRecvBuffer.FiPktIdx;iPktType := OP_TYPE_SQL;CopyMemory(@bytesSend[0], @iPktLen, 4);  // TCP包头 --(1) 总长CopyMemory(@bytesSend[4], @iPktIdx, 4);  // TCP包头 --(2) 序号CopyMemory(@bytesSend[8], @iPktType, 4);                 // TCP包头 --(3) 类型CopyMemory(@bytesSend[12], PChar(_str), Length(_str));   // TCP包 内容
iRtn := g_tcpClient.Send01(@bytesSend[0], iPktLen);if (iRtn <> 0) thenraise Exception.CreateFmt('发送消息异常 : (%d)%s', [iRtn, ErrorNo2Str(iRtn)]);WaitForSingleObject(g_drRecvBuffer.FhEvent, INFINITE);
end;class procedure TdrTcpClient.SendBytes(_pc :PChar; _iLen :Integer);
var iRtn :Integer;
beginif Conn < 0 thenraise Exception.Create('TCP接收线程正在初始化,请稍后再试...');iRtn := g_tcpClient.Send01(@_pc[0], _iLen);if (iRtn <> 0) thenraise Exception.CreateFmt('发送消息异常 : (%d)%s', [iRtn, ErrorNo2Str(iRtn)]);
end;class function  TdrTcpClient.ConnectDest :TSocket;
var wsadata1 :WSADATA;addrSrv :SOCKADDR_IN;iRtn :Integer;skt :TSocket;dwErrorNo :DWORD;
beginResult := 0;WSAStartup(MAKEWORD(1,1), wsadata1);skt := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (skt <= 0) thenbegindwErrorNo := GetLastError;raise Exception.CreateFmt('%s %d', ['套接字创建异常:', dwErrorNo]);end;addrSrv.sin_family := AF_INET;addrSrv.sin_port := htons(g_iDestPort);addrSrv.sin_addr.S_addr := inet_addr(PChar(g_strDestIp));iRtn := connect(skt, addrSrv, sizeof(addrSrv));if(iRtn <> 0) thenbegindwErrorNo := GetLastError;raise Exception.CreateFmt('%s %d %s', ['服务器连接异常:', dwErrorNo, ErrorNo2Str(dwErrorNo)]);end;Result := skt;
end;class procedure TdrTcpClient.SetIpPort(_strDestIp: string; _iDestPort: integer);
beging_strDestIp := _strDestIp;g_iDestPort := _iDestPort;
end;class function TdrTcpClient.Status: Integer;
beginif (g_tcpClient = nil) thenResult := -100elseResult := g_tcpClient.FiStatus;
end;class procedure TdrTcpClient.SendHeartBeat;
var pc :array[0..12] of Char;iPktLen, iPktIdx, iPktType :Integer;
beginiPktLen := 12;iPktIdx := 0;iPktType := OP_TYPE_HEARTBEAT;CopyMemory(@pc[0], @iPktLen, 4);CopyMemory(@pc[4], @iPktIdx, 4);CopyMemory(@pc[8], @iPktType, 4);SendBytes(pc, iPktLen);
end;{ TcallbackWnd }function ProcWindow(_hWnd :HWND;_uMsg :UINT;_wParam :WPARAM;_lParam :LPARAM):longint;stdcall;
var buffer :TdrBuffer;pc :PChar;
beginResult := 0; // 用户已经处理if (_uMsg = WM_TCP_PUSH) thenbeginif Assigned(g_callbackWnd.FfuncPush) thenbegin// 得到 缓冲区buffer := TdrBuffer(_lParam);// 业务逻辑处理g_callbackWnd.FfuncPush(@buffer.Fpc[TCP_PACKET_HEADER_LEN], buffer.FiValidLen - TCP_PACKET_HEADER_LEN);// 释放缓冲区
      g_bufferPool.ReleaseBlock(buffer);end;endelse if (_uMsg = WM_TCP_CLIENTS) thenbeginif Assigned(g_callbackWnd.FfuncClients) thenbeginbuffer := TdrBuffer(_lParam);g_callbackWnd.FfuncClients(@buffer.Fpc[TCP_PACKET_HEADER_LEN], buffer.FiValidLen - TCP_PACKET_HEADER_LEN);g_bufferPool.ReleaseBlock(buffer);end;endelse if (_uMsg = WM_CLIENT_SOCKET_MSG_REQ) thenbeginbuffer := TdrBuffer(_lParam);g_callbackWnd.PackSocket(@buffer.Fpc[TCP_PACKET_HEADER_LEN], buffer.FiValidLen - TCP_PACKET_HEADER_LEN);g_bufferPool.ReleaseBlock(buffer);endelse if (_uMsg = WM_CLIENT_BLOCK_MSG_REQ) thenbeginbuffer := TdrBuffer(_lParam);g_callbackWnd.PackBlock(@buffer.Fpc[TCP_PACKET_HEADER_LEN], buffer.FiValidLen - TCP_PACKET_HEADER_LEN);g_bufferPool.ReleaseBlock(buffer);endelse if (_uMsg = WM_CLIENT_SOCKET_MSG_RES) thenbeginif Assigned(g_callbackWnd.FfuncSocket) thenbeginbuffer := TdrBuffer(_lParam);g_callbackWnd.FfuncSocket(@buffer.Fpc[TCP_PACKET_HEADER_LEN], buffer.FiValidLen - TCP_PACKET_HEADER_LEN);g_bufferPool.ReleaseBlock(buffer);end;endelse if (_uMsg = WM_CLIENT_BLOCK_MSG_RES) thenbeginif Assigned(g_callbackWnd.FfuncBlock) thenbeginbuffer := TdrBuffer(_lParam);g_callbackWnd.FfuncBlock(@buffer.Fpc[TCP_PACKET_HEADER_LEN], buffer.FiValidLen - TCP_PACKET_HEADER_LEN);g_bufferPool.ReleaseBlock(buffer);end;endelse if (_uMsg = WM_MANAGE_SQL) thenbeginbuffer := TdrBuffer(_lParam);if Assigned(g_callbackWnd.FfuncSQL) theng_callbackWnd.FfuncSQL(buffer);g_bufferPool.ReleaseBlock(buffer);endelse if (WM_TCP_RECV = _uMsg) thenbeginif (_wParam = 0) thenfrmMain.Memo1.Lines.Add('Recv : '+inttostr(_lParam))else if (_wParam = 1) thenfrmMain.Memo1.Lines.Add('Allocate buffer block for : 0x'+inttohex(_lParam, 8))else if (_wParam = 2) thenfrmMain.Memo1.Lines.Add('Release buffer block from : 0x'+inttohex(_lParam, 8))else if (_wParam = 3) thenfrmMain.Memo1.Lines.Add('Space for unicode string : '+inttostr(_lParam))else if (_wParam = 4) thenfrmMain.Memo1.Lines.Add('Space for ansi string : '+inttostr(_lParam))else if (_wParam = 5) thenfrmMain.Memo1.Lines.Add('UTF-8 string space is : '+inttostr(_lParam));endelse if (WM_LOG_CONSOLE = _uMsg) thenbeginpc := PChar(_lParam);frmMain.Memo1.Lines.Add(PChar(_lParam));FreeMem(pc, _wParam);endelse if (_uMsg = WM_TIMER) thenbeginif (1 = _wParam) thenbeginif (g_tcpClient<>nil)and(g_tcpClient.FiStatus = 1) thenTdrTcpClient.SendHeartBeat;end;endelse if (_uMsg = WM_DESTROY) thenbeginDestroyWindow(_hwnd);PostQuitMessage(0);endelse  Result := DefWindowProc(_hWnd, _uMsg, _wParam, _lParam);
end;constructor TcallbackWnd.Create;
beginCreateWindow;//SetTimer(FhWnd, 1, 1000 * 10, nil);
end;procedure TcallbackWnd.CreateWindow;
var wndcls :WNDCLASS;hInstance :THandle;
beginhInstance := Windows.GetModuleHandle(nil);ZeroMemory(@wndcls, sizeof(wndcls));wndcls.cbClsExtra    := 0;wndcls.cbWndExtra    := 0;wndcls.hbrBackground := HBRUSH(GetStockObject(WHITE_BRUSH));    // 背景画刷wndcls.hCursor        := LoadCursor(0, IDC_CROSS);wndcls.hIcon        := LoadIcon(0, IDI_ERROR);    // 窗口图标wndcls.hInstance    := hInstance;wndcls.lpfnWndProc    := @ProcWindow;wndcls.lpszClassName:= 'DrTcpCallbackWnd';wndcls.lpszMenuName := nil;wndcls.style        := CS_HREDRAW or CS_VREDRAW;Windows.RegisterClass(wndcls);FhWnd := CreateWindowEx(WS_EX_CLIENTEDGE,wndcls.lpszClassName,wndcls.lpszClassName,WS_OVERLAPPEDWINDOW,100, 100,400, 300,0,0, //g_hMenu,
        hInstance,0);if (FhWnd = 0) thenFdwErrNo := GetLastError;//    ShowWindow(hWnd1, SW_SHOWNORMAL);
    UpdateWindow(FhWnd);
end;function TcallbackWnd.PackSocket(_pc :PChar; _iLen :integer) :integer;
var sockAddr :TSockAddr;iNameLen :Integer;dwErrNo :DWORD;strMac, strIP :string;iLenIp, iLenMac, iLenMsg :Integer;pc :array[0..255] of Char;iPktLen, iPktIdx, iPktType :Integer;
beginResult := 0;iNameLen := SizeOf(sockAddr);if SOCKET_ERROR = getsockname(g_tcpClient.Fskt, sockAddr, iNameLen) thenbegindwErrNo := GetLastError;Result := dwErrNo;Exit;end;strIP := inet_ntoa(sockAddr.sin_addr);strMac := '';GetMacByIP(sockAddr.sin_addr.S_addr, strMac);iLenIp := 4 + length(strIP);iLenMac:= 4 + length(strMac);iLenMsg := 4 + iLenIp + iLenMac;iPktLen := TCP_PACKET_HEADER_LEN + iLenMsg + _iLen;iPktIdx := 0;iPktType:= OP_TYPE_MANAGE_SOCKET_RES;CopyMemory(@pc[0], @iPktLen, 4);CopyMemory(@pc[4], @iPktIdx, 4);CopyMemory(@pc[8], @iPktType, 4);// ***CopyMemory(@pc[TCP_PACKET_HEADER_LEN], @iLenMsg, 4);CopyMemory(@pc[TCP_PACKET_HEADER_LEN + 4], @iLenIp, 4);CopyMemory(@pc[TCP_PACKET_HEADER_LEN + 8], PChar(strIP), iLenIp - 4);CopyMemory(@pc[TCP_PACKET_HEADER_LEN + 4 + iLenIp], @iLenMac, 4);CopyMemory(@pc[TCP_PACKET_HEADER_LEN + 4 + iLenIp + 4], PChar(strMac), iLenMac - 4);// ***CopyMemory(@pc[TCP_PACKET_HEADER_LEN+iLenMsg], _pc, _iLen);TdrTcpClient.SendBytes(@pc[0], iPktLen);
end;procedure TcallbackWnd.PackBlock(_pc :PChar; _iLen :integer);
var iPktLen, iPktIdx, iPktType :Integer;iIdx :Integer;buffer :TdrBuffer;mem :TMemoryStream;iLenMsg :Integer;pc :PChar;dwTick :DWORD;
beginmem := TMemoryStream.Create;tryiPktLen := TCP_PACKET_HEADER_LEN;iPktIdx := 0;iPktType:= OP_TYPE_MANAGE_BLOCK_RES;mem.Write(iPktLen, 4);mem.Write(iPktIdx, 4);mem.Write(iPktType, 4);iLenMsg := 8;mem.Write(iLenMsg, 4);dwTick := GetTickCount;mem.Write(dwTick, 4);iIdx := 0;while iIdx < g_bufferPool.ListAll.Count dobeginbuffer := TdrBuffer(g_bufferPool.ListAll.Items[iIdx]);mem.Write(buffer.FiTotalLen, 4);mem.Write(buffer.FiValidBeginOffset, 4);mem.Write(buffer.FiValidLen, 4);mem.Write(buffer.FdwType, 4);mem.Write(buffer.FdwLastTick, 4);Inc(iLenMsg, 20);Inc(iIdx);end;iPktLen := TCP_PACKET_HEADER_LEN + iLenMsg + _iLen;iPktIdx := 0;iPktType:= OP_TYPE_MANAGE_BLOCK_RES;pc := PChar(mem.Memory);CopyMemory(@pc[0], @iPktLen, 4);CopyMemory(@pc[4], @iPktIdx, 4);CopyMemory(@pc[8], @iPktType, 4);CopyMemory(@pc[TCP_PACKET_HEADER_LEN], @iLenMsg, 4);    mem.Write(_pc^, _iLen);TdrTcpClient.SendBytes(mem.Memory, iPktLen);finallymem.Free;end;
end;{ TdrDataSet }function TdrDataSet.Unpack(_pc :PChar; _iLen :Integer) :integer;
var iTotalLen, iColumnCnt, iRowCnt :Integer;i, iOffset, iLenColumnName, iRowIdx, iColIdx :Integer;iLenRecord :Integer;
beginResult := 0;FpcBuf := _pc;FiBufLen := _iLen;CopyMemory(@iTotalLen,  @_pc[0], 4);if (iTotalLen <> _iLen) thenbeginResult := -1;Exit;end;CopyMemory(@iColumnCnt, @_pc[4], 4);CopyMemory(@iRowCnt,    @_pc[8], 4);SetLength(FaryColumnType, iColumnCnt);SetLength(FaryColumnName, iColumnCnt);SetLength(FaryaryRecord, iRowCnt, iColumnCnt);// 列类型for i:=0 to (iColumnCnt-1) doCopyMemory(@FaryColumnType[i], @_pc[12 + i * 4], 4);iOffset := 12 + iColumnCnt * 4;// 列名称for i:=0 to (iColumnCnt-1) dobeginCopyMemory(@iLenColumnName, @_pc[iOffset], 4);SetLength(FaryColumnName[i], iLenColumnName);CopyMemory(@((FaryColumnName[i])[1]), @_pc[iOffset + 4], iLenColumnName);Inc(iOffset, 4 + iLenColumnName);end;// [2]、字段值(长度 + 内容)for iRowIdx:=0 to iRowCnt-1 dofor iColIdx:=0 to iColumnCnt-1 dobeginCopyMemory(@iLenRecord, @_pc[iOffset], 4);FaryaryRecord[iRowIdx, iColIdx] := iOffset + 4;Inc(iOffset, 4 + iLenRecord);end;
end;function TdrDataSet.GetRecord(_iRowIdx, _iColumnIdx: integer): TdrRecord;
beginif not Assigned(Ffield) thenFfield := TdrRecord.Create(Self, _iRowIdx, _iColumnIdx)elsebeginFfield.FiRowIdx := _iRowIdx;Ffield.FiColumnIdx := _iColumnIdx;end;Ffield.FenXi;Result := Ffield;
end;function TdrDataSet.GetFieldType(_iColumnIdx: integer): Integer;
beginResult := FaryColumnType[_iColumnIdx];
end;function TdrDataSet.GetFieldTypeName(_iColumnIdx: integer): string;
beginFieldTypeName_f(GetFieldType(_iColumnIdx), Result);
end;function TdrDataSet.GetFieldName(_iColumnIdx: integer): string;
beginResult := FaryColumnName[_iColumnIdx];
end;function TdrDataSet.GetRowCount: Integer;
beginResult := Length(FaryaryRecord);
end;function TdrDataSet.GetColumnCount: Integer;
beginResult := Length(FaryColumnType);
end;{ TdrRecord }constructor TdrRecord.Create(_dataset: TdrDataSet; _iRowIdx, _iColumnIdx: Integer);
beginFdataset := _dataset;FiRowIdx := _iRowIdx;FiColumnIdx := _iColumnIdx;
end;procedure TdrRecord.FenXi;
var iOffset :Integer;
beginiOffset := Fdataset.FaryaryRecord[FiRowIdx, FiColumnIdx];FpcRecord := @Fdataset.FpcBuf[iOffset];
end;function TdrRecord.asByteArray(_pByte: PByte; out _iLen: Integer): Integer;
beginCopyMemory(@_iLen, FpcRecord-4, 4);if (_pByte <> nil) thenCopyMemory(_pByte, FpcRecord, _iLen);
end;function TdrRecord.asInteger: Integer;
beginCopyMemory(@Result, FpcRecord, 4);
end;function TdrRecord.asSingle: Single;
beginCopyMemory(@Result, FpcRecord, SizeOf(Single));
end;function TdrRecord.asDouble: Double;
beginCopyMemory(@Result, FpcRecord, SizeOf(Double));
end;function TdrRecord.asString: string;
var iLen :Integer;iFieldType :Integer;d :Double;iUnicodeLen, iAnsiLen :Integer;pwc :PWideChar;pc :PChar;
beginiFieldType := GetFieldType;case iFieldType ofDR_NUMERIC :beginCopyMemory(@iLen, FpcRecord - 4, 4);CopyMemory(@d, FpcRecord, iLen);Result := FloatToStr(d);end;DR_LONGNVARCHAR, DR_NCHAR, DR_NVARCHAR, DR_LONGVARCHAR, DR_CHAR, DR_VARCHAR :beginpwc := nil;pc := nil;tryCopyMemory(@iLen, FpcRecord - 4, 4);//PostMessage(g_callbackWnd.FhWnd, WM_TCP_RECV, 5, iLen);if (iLen = 0) thenbeginResult := 'Empty string .';Exit;end;SetLength(Result, iLen);CopyMemory(@Result[1], FpcRecord, iLen);{iUnicodeLen := MultiByteToWideChar(CP_UTF8, 0, FpcRecord, iLen, nil, 0);GetMem(pwc, iUnicodeLen * 2);MultiByteToWideChar(CP_UTF8, 0, FpcRecord, iLen, pwc, iUnicodeLen);iAnsiLen := WideCharToMultiByte(CP_ACP, 0, pwc, iUnicodeLen, nil, 0, nil, nil);GetMem(pc, iAnsiLen + 1);WideCharToMultiByte(CP_ACP, 0, pwc, iUnicodeLen, pc, iAnsiLen, nil, nil);pc[iAnsiLen] := Char(0);Result := pc;     }finallyif (pwc <> nil) then FreeMem(pwc, iUnicodeLen * 2);if (pc <> nil) then  FreeMem(pc, iAnsiLen + 1);end;end;else     FieldTypeName_f(iFieldType, Result);end;
end;function TdrRecord.GetFieldType: Integer;
beginResult := Fdataset.GetFieldType(FiColumnIdx);
end;function TdrRecord.GetFieldTypeName: string;
beginResult := Fdataset.GetFieldTypeName(FiColumnIdx);
end;function TdrRecord.GetFieldName: string;
beginResult := Fdataset.GetFieldName(FiColumnIdx);
end;initializationg_bufferPool := TdrBufferPool.create;g_drRecvBuffer := TdrRecvBuffer.Create;g_callbackWnd := TcallbackWnd.Create;g_strDestIp := '';g_iDestPort := 0;finalizationif Assigned(g_bufferPool) then g_bufferPool.Free;if Assigned(g_drRecvBuffer) then g_drRecvBuffer.Free;end.

 

3、

 

转载于:https://www.cnblogs.com/CodeHouseZ/p/6144149.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402559.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java、Mysql、MyBatis 中枚举 enum 的使用

From: https://yulaiz.com/java-mysql-enum/ Java 和 MySql 中都有枚举的概念&#xff0c;合理的使用枚举&#xff0c;可以让代码阅读和数据库数据查询更加直观、高效。那么我们怎么使用呢&#xff0c;什么时候使用&#xff0c;两者之间怎么进行数据关联呢&#xff1f;&#x…

ny12 喷水装置(二)

喷水装置&#xff08;二&#xff09; 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;4描述有一块草坪&#xff0c;横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<10000)个点状的喷水装置&#xff0c;每个喷水装置i喷水的效果是让…

wordpress插件制作视频教程【资料分享】

2019独角兽企业重金招聘Python工程师标准>>> 一共5集&#xff0c;每一集15分钟左右&#xff0c;适合入门用哦~ 资料地址&#xff1a; http://wordpresshy.com/create-plugin 分集介绍&#xff1a; 1 【教学大纲】 1.介绍什么是插件&#xff1b; 2.插件的文件结…

博主故事:博客提升了我在口腔行业的影响力

自从我上次谈了谈个人开设博客的目的一文后&#xff0c;今天就有一位博友发来了感谢留言&#xff0c;他说他的博客让他在国内做牙齿矫正行业的有了一定影响力&#xff0c;下月被请到上海讲课&#xff0c;也有不少民营机构前来挖他&#xff0c;还被邀请参加中国口腔医学界最盛大…

RabbitMQ入门教程——发布/订阅

什么是发布订阅 发布订阅是一种设计模式定义了一对多的依赖关系&#xff0c;让多个订阅者对象同时监听某一个主题对象。这个主题对象在自身状态变化时&#xff0c;会通知所有的订阅者对象&#xff0c;使他们能够自动更新自己的状态。 为了描述这种模式&#xff0c;我们将会构建…

linux C 学习---函数指针

我们经常会听到这样的说法&#xff0c;不懂得函数指针就不是真正的C语言高手。我们不管这句话对与否&#xff0c;但是它都从侧面反应出了函数指针的重要性&#xff0c;所以我们还是有必要掌握对函数指针的使用。先来看看函数指针的定义吧。 函数是由执行语句组成的指令序列或者…

CSS3与页面布局学习笔记(六)——CSS3新特性(阴影、动画、渐变、变形( transform)、透明、伪元素等)...

一、阴影 1.1、文字阴影 text-shadow<length>①&#xff1a; 第1个长度值用来设置对象的阴影水平偏移值。可以为负值 <length>②&#xff1a; 第2个长度值用来设置对象的阴影垂直偏移值。可以为负值 <length>③&#xff1a; 如果提供了第3个长度值则用来设置…

解决表字段使用关键字导致Mybatis Generator生成代码异常的解决方案

From: http://blog.itfsw.com/2017/05/23/jiejue-biao-ziduan-shiyong-guanjianzi-daozhi-mybatis-generator-shengcheng-daima-yichang-de-jiejue-fangan/ 在某个项目中遇到这么一个问题&#xff0c;因为原始表结构中某些字段定义使用了MySQL的关键字如match等&#xff0c;在…

Linux C编程---指针数组简析(二维数组、多级指针)

讲到指针和数组&#xff0c;先给大家看一道例题&#xff1a; 题目&#xff1a;填空练习&#xff08;指向指针的指针&#xff09; 1.程序分析&#xff1a;      2.程序源代码&#xff1a; main() { char *s[]{"man","woman","girl","bo…

20169210《Linux内核原理与分析》第十二周作业

Return-to-libc 攻击实验 缓冲区溢出的常用攻击方法是用 shellcode 的地址来覆盖漏洞程序的返回地址&#xff0c;使得漏洞程序去执行存放在栈中 shellcode。为了阻止这种类型的攻击&#xff0c;一些操作系统使得系统管理员具有使栈不可执行的能力。这样的话&#xff0c;一旦程序…

判断android图片是否硬解码(方法)

2019独角兽企业重金招聘Python工程师标准>>> 在oncreate方面的setContentView(R.layout.main); 前面&#xff0c;添加如下代码&#xff1a; getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HAR…

Linux C 编程技巧--利用有限状态机模型编程

我们知道&#xff0c;一般编写程序时都要画出流程图&#xff0c;按照流程图结构来编程&#xff0c;如果编写一个比较繁琐&#xff0c;容易思维混乱的程序时&#xff0c;我们可以利用有限状态机模型画出一个状态转移图&#xff0c;这样便可以利用画出的逻辑图来编写程序&#xf…

linux远程登录三种方式telnet,ssh,vnc

linux远程连接三种方式telnet&#xff0c;ssh&#xff0c;vnctelnet和ssh服务只能实现基于字符界面的远程控制&#xff0c;如果要基于图形界面进行远程控制&#xff0c;可以借助免费的VNC来完成。一、telnet连接1.首先进入终端&#xff0c;查看是否安装了telnet服务。linux默认…

大数据之Yarn——Capacity调度器概念以及配置

试想一下&#xff0c;你现在所在的公司有一个hadoop的集群。但是A项目组经常做一些定时的BI报表&#xff0c;B项目组则经常使用一些软件做一些临时需求。那么他们肯定会遇到同时提交任务的场景&#xff0c;这个时候到底如何分配资源满足这两个任务呢&#xff1f;是先执行A的任务…

C/C++经典面试题

面试题1&#xff1a;变量的声明和定义有什么区别 为变量分配地址和存储空间的称为定义&#xff0c;不分配地址的称为声明。一个变量可以在多个地方声明&#xff0c;但只能在一个地方定义。加入extern修饰的是变量的声明&#xff0c;说明此变量将在文件以外或在文件后面部分定义…

Java跳出多重循环

From: https://www.cnblogs.com/fastfn/p/9777067.html 场景&#xff1a;很多的时候需要做到跳出多重循环&#xff0c;而在Java中虽然后goto关键字&#xff0c;但是是保留字&#xff0c;并没有启用。而在处理分支结构的if...else,switch...case,好像都达不到想要的效果。 作为…

java基础集合简介Map(三)下

From: https://www.cnblogs.com/douyu2580860/p/8358768.html --Map接口简介 今天来看一看map集合&#xff0c;map映射接口&#xff0c;用于存放键值对&#xff0c;<key,value>&#xff0c;通过key来查找value,顾名思义key不能为空&#xff0c;唯一且不重复&#xff0c;不…

从getmemery()函数看内存管理、函数传参等一系列问题

在C 面试题目中&#xff0c;会经常出现getmemery()函数的改错题&#xff0c;比如下面这道题&#xff0c; 例一&#xff1a;代码如下&#xff1a; [cpp] view plaincopy #include <stdio.h> char *getmemery() { char p[] "hello world!"; …

Java中array、List、Set互相转换

From: https://www.cnblogs.com/yysbolg/p/9977365.html 数组转List String[] staffs new String[]{"A", "B", "C"}; List staffsList Arrays.asList(staffs);//注意: Arrays.asList() 返回一个受指定数组决定的固定大小的列表。所以不能做 a…

Apache Shiro 使用手册(三)Shiro 授权

授权即访问控制&#xff0c;它将判断用户在应用程序中对资源是否拥有相应的访问权限。 如&#xff0c;判断一个用户有查看页面的权限&#xff0c;编辑数据的权限&#xff0c;拥有某一按钮的权限&#xff0c;以及是否拥有打印的权限等等。 一、授权的三要素授权有着三个核心元素…