socketchannel,利用Delphi-cross-socket 庫提升kbmmw 跨平臺開發

 2023-10-21 阅读 31 评论 0

摘要:以前我寫過了,通過httpsys 提升windows 下,delphi 多層應用。隨著delphi 10.2 對linux 的支持,很多人也想在linux 下 發布kbmmw 服務器,但是官方僅通過indy 支持 linux。剛好國內有大牛開源了Delphi 跨平臺 Socket 通訊庫. socketchannel,通過這

以前我寫過了,通過httpsys 提升windows 下,delphi 多層應用。隨著delphi 10.2 對linux 的支持,很多人也想在linux 下

發布kbmmw 服務器,但是官方僅通過indy 支持 linux。剛好國內有大牛開源了Delphi 跨平臺 Socket 通訊庫.

socketchannel,通過這個可以直接讓kbmmw 服務器高速的運行在在windows、linux、Mac 上。

delphi-cross-socket 的開源地址為:https://github.com/winddriver/Delphi-Cross-Socket

下面是官網的部分介紹。

Delphi 跨平臺 Socket 通訊庫作者: WiNDDRiVER(soulawing@gmail.com)
重要更新(2017.08.22)代碼重構, 做了大量修改, 詳見源碼增加了幾個新的 interface, 用法詳見 demosICrossSocketICrossSslSocketICrossServerICrossSslServer特性針對不同平臺使用不同的IO模型:IOCPWindowsKQUEUEFreeBSD(MacOSX, iOS...)EPOLLLinux(Linux, Android...)支持極高的并發Windows能跑10萬以上的并發數, 需要修改注冊表調整默認的最大端口數Mac做了初步測試, 測試環境為虛擬機中的 OSX 10.9.5, 即便修改了系統的句柄數限制, 最多也只能打開32000多個并發連接, 或許 OSX Server 版能支持更高的并發吧同時支持IPv4、IPv6零內存拷貝已通過測試WindowsOSXiOSAndroidLinux建議開發環境要發揮跨平臺的完整功能請使用Delphi 10.2 Tokyo及以上的版本最低要求支持泛型和匿名函數的Delphi版本, 具體是從哪個版本開始支持泛型和匿名函數的我也不是太清楚

django socket。?

大家可以下載對應的源碼,并使用delphi 測試它附帶的例子程序。

今天簡單說一下如何利用delphi-cross-socket 實現kbmmw 的跨平臺開發。

?

?

首先我們做一個kbmmw transport.

聲明如下。

unit kbmMWCrossScoketServerTransport;{.$define httpsyslog}interfaceusesClasses, Sysutils,kbmMWCustomTransport,kbmMWServer,kbmMWGlobal, variants,kbmMWHTTPUtils,kbmMWExceptions,{$ifdef httpsyslog}kbmMWLog,{$endif}Net.CrossSocket,{$IFDEF __SSL__}Net.CrossSslSocket,{$IFDEF POSIX}Net.CrossSslDemoCert,{$ENDIF}{$ENDIF}Net.SocketAPI;typeTProtServer = class(TkbmMWServer);TxalionTransport=class(TkbmMWCustomServerTransport);Txalioninfo=class(TkbmMWServerTransportInfo);Txalionserver = classprivateFServer:Tkbmmwserver;FTransport: TkbmMWCustomServerTransport;    FSocket: {$IFDEF __SSL__}TCrossSslSocket{$ELSE}TCrossSocket{$ENDIF};procedure OnReceived(Sender: TObject; AConnection: ICrossConnection; ABuf: Pointer; ALen: Integer);
publicconstructor Create;destructor Destroy; override;end;TkbmMWCustomCrossScoketServerTransport = class(TkbmMWCustomServerTransport)private{ Private declarations }FCrossScoketServer: TxalionServer;Fhost:string;Fport:integer;// Fssl:boolean;Fversion:string;public// @excludeconstructor Create(AOwner:TComponent); override;// @excludedestructor Destroy; override;publicclass function IsSerializedTransport:boolean; override;class function IsConnectionlessTransport:boolean; override;procedure Listen; override;procedure Close; override;function IsListening:boolean; override;published{ 服務器 ip    例如   127.0.0.1}property Host:string read Fhost write Fhost;property Port:integer read Fport write Fport;Property Version:string read Fversion;end;{$IFDEF LEVEL16}[ComponentPlatformsAttribute({$IFDEF LEVEL26}pidLinux64 or{$ENDIF}{$IFDEF LEVEL23}pidiOSDevice64 or {$ENDIF}{$IFDEF LEVEL18}pidiOSSimulator or pidiOSDevice or {$ENDIF}{$IFDEF LEVEL19}pidAndroid or {$ENDIF}pidWin32 or pidWin64{$IFDEF LEVEL17} or pidOSX32{$ENDIF})]
{$ENDIF}TkbmMWCrossScoketServerTransport= class(TkbmMWCustomCrossScoketServerTransport)published{ Published declarations }property Crypt;property Compression;property StreamFormat;property VerifyTransfer;property TransportStateOptions;property FormatSettings;property Plugin;property Params;property StringConversion;property NodeID;property ClusterID;end;{$I CrossSocketversion.inc}{$ifdef httpsyslog}varfilelogmgr:TkbmMWLocalFileLogManager;{$endif}

?

實現部分如下:

implementationfunction kbmMWCrossScoketPutVerificationHeader(Size:integer):Tbytes;
vars:string;c:byte;i:integer;
constEOL=#10#13;
begins:=format('KBMMW X%0.8x ',[Size]); // 16 bytes.c:=0;for i:=KBMMW_STRINGCHAROFS to 16-KBMMW_STRINGCHARLENOFS doc:=c xor ord(s[i]);s:=s+format('X%0.2x'+EOL,[c]);    // 1+2+CR+LF = 5 bytes.
        setlength(result,length(s));for i := 1 to length(s) doresult[i-1]:=ord(s[i]);end;function kbmMWCrossScoketGetVerificationHeader(buff:pointer;len:integer):integer;
vars,s1:string;c,c1:byte;i:integer;pb:pbyte;
constSINVDATA = 'Invalid data';
beginResult:=0;                             // Satisfy compiler.c1:=0;s:='';trypb:=buff;for I := 0 to 20 dos:=s+chr((pb+i)^);// Extract checksum.trys1:=copy(s,17,3);c1:=strtoint(s1);exceptkbmMWRaiseException(KBMMW_ERR_TRANSPORT_INVALIDDATA,SINVDATA);end;// Calculate checksum.c:=0;for i:=KBMMW_STRINGCHAROFS to 16-KBMMW_STRINGCHARLENOFS doc:=c xor ord(s[i]);// Match?if c<>c1 thenexit;//kbmMWRaiseException(KBMMW_ERR_TRANSPORT_INVALIDDATA,SINVDATA);// Extract size.s1:=copy(s,7,9);tryResult:=strtoint(s1);exceptexit;// kbmMWRaiseException(KBMMW_ERR_TRANSPORT_INVALIDDATA,SINVDATA);end;exceptkbmMWDebugDumpMemory(mwdlAdvanced,mwdtTransport,kbmMWDebugWhere,'Exception during iocp verification',PByte(s),ByteLength(s));raise;end;
end;constructor Txalionserver.Create;
begininherited;FSocket :={$IFDEF __SSL__}TCrossSslSocket{$ELSE}TCrossSocket{$ENDIF}.Create(0);//FSocket.OnConnected := OnConnected;FSocket.OnReceived := OnReceived;
end;destructor Txalionserver.Destroy;
beginFSocket.Free;inherited;
end;procedure Txalionserver.OnReceived(Sender: TObject; AConnection: ICrossConnection; ABuf: Pointer; ALen: Integer);varheadlen:integer;// 校驗為 21 ,不校驗為4
retl,i, j,inlen:integer;cStreamClass:TkbmMWCustomTransportStreamClass;OutStream:IkbmMWCustomResponseTransportStream;InStream:IkbmMWCustomRequestTransportStream;stamp:int64;AInfo:ikbmMWServerTransportInfo;//IkbmMWCustomTransportInfo;
   indata:pbyte;retdata:Tbytes;sr,query,spath,s:String;vt:word;bsize:tbytes;rethead:Tbytes;inStreamFormat:string;
begininStreamFormat:=TxalionTransport(FTransport).StreamFormat;if   (inStreamFormat<>'STANDARD')  thenbeginraise Exception.Create('Only support STANDARD StreamFormat.');end;//           beginif TxalionTransport(FTransport).VerifyTransfer thenbeginheadlen:=21;if kbmMWCrossScoketGetVerificationHeader(abuf,alen)<>(alen-headlen) then  //21為校驗的頭beginAConnection.SendBytes(Tencoding.UTF8.GetBytes('Invalid data'));exit;end;endelsebeginheadlen:=4;end;stamp:=TkbmMWTiming.GetTimeUS;aInfo:=TkbmMWServerTransportInfo.Create;cStreamClass:=TxalionTransport(FTransport).FControllerClass.CheckGetStreamClass(mwmtResponse);OutStream:=TkbmMWCustomResponseTransportStream(cStreamClass.Create(FTransport,AInfo));cStreamClass:=TxalionTransport(FTransport).FControllerClass.CheckGetStreamClass(mwmtRequest);InStream:=TkbmMWCustomRequestTransportStream(cStreamClass.Create(FTransport,AInfo));InStream.RemoteLocation:=AConnection.PeerAddr;// Client.PeerIP;
inlen:=alen-headlen;tryif inlen>0 thenbeginInStream.DataStream.Clear;InStream.DataStream.SetSize( inlen);indata:=pbyte(abuf);inc(indata,headlen);move(indata^,InStream.DataStream.Memory^,inlen);end;TProtServer(FServer).InternalServeStream(FTransport,InStream,OutStream);TProtServer(FServer).UpdateGlobalStats(InStream,OutStream,stamp);// Send response back.
retl:=OutStream.DataStream.Size;if TxalionTransport(FTransport).VerifyTransfer thenbeginrethead:=kbmMWCrossScoketPutVerificationHeader(retl);AConnection.SendBytes(rethead);//  client.Send(rethead[0],headlen);endelsebeginSetLength(bSize,4);bSize[3]:=(retl shr (8+8+8)) and 255;bSize[2]:=(retl shr (8+8)) and 255;bSize[1]:=(retl shr (8)) and 255;bSize[0]:=retl and 255;AConnection.SendBytes(bsize);//client.Send(bsize[0],4);end;setlength(retdata,retl);move(OutStream.DataStream.Memory^,retdata[0],retl);AConnection.SendBytes(retdata);excepton E: Exception dobegin{$ifdef httpsyslog}Log.Warn('Find error.'+e.Message );log.Warn('info:'+TkbmMWPlatformMarshal.memory2String(indata,inlen));{$endif}AConnection.SendBytes(Tencoding.UTF8.GetBytes(e.Message));//    client.Send(e.Message);end;end;end;
{ TkbmMWCustomhttpsysServerTransport }procedure TkbmMWCustomCrossScoketServerTransport.Close;
beginif state=mwtrstDisconnected then   exit;FCrossScoketServer.FSocket.DisconnectAll;//      Fiocpserver.fiocpServer.Stop;
      SetState(mwtrstDisconnected);
end;constructor TkbmMWCustomCrossScoketServerTransport.Create(AOwner: TComponent);
begininherited;FCrossScoketServer:= TxalionServer.Create;Fhost:='0.0.0.0';Fport:=3000;self.VerifyTransfer:=True;fversion:=sysversion;end;destructor TkbmMWCustomCrossScoketServerTransport.Destroy;
beginif FCrossScoketServer<>nil thenfreeandnil(FCrossScoketServer);inherited;
end;class function TkbmMWCustomCrossScoketServerTransport.IsConnectionlessTransport: boolean;
beginResult:=False;
end;function TkbmMWCustomCrossScoketServerTransport.IsListening: boolean;
beginResult:=(state=mwtrstListening);
end;class function TkbmMWCustomCrossScoketServerTransport.IsSerializedTransport: boolean;
beginResult:=true;
end;procedure TkbmMWCustomCrossScoketServerTransport.Listen;begininherited;if state=mwtrstListening then   exit;FCrossScoketserver.FServer:=server;FCrossScoketserver.FTransport:=self;FCrossScoketserver.FSocket.Listen(Fhost,Fport);SetState(mwtrstListening);end;{$ifdef httpsyslog}
initializationfilelogmgr:=TkbmMWLocalFileLogManager.Create('./kbmmwlog.txt'); // ,一個是日志文件filelogmgr.FileOptions:=[mwlfoDeleteOldLog];//:=true; // 刪除老的日志文件filelogmgr.FlushInterval:=0; // 寫文件時間間隔,0 為立即寫文件Log.LogManager:=filelogmgr; //
     log.Info('Start logging!');{$endif}

?

把以上代碼注冊成控件并安裝。

打開kbmmw 自帶的例子 ,位置如圖:

然后把原來的indy Transport 換成 我們新作的Transport.

?

?服務端就ok了,我們可以編譯運行,如圖:

?

由于這是標準的tcp 傳輸協議,我們在客戶段就直接使用indy 的代碼(官方自帶的)。

打開后,直接運行。

?

?

連接服務器,正常工作。windows 上沒有任何問題。

在linux 下,我們可以參照這一篇 文章,把indy transport

換成 delphi-cross-socket transport 就可以了,其他的都不用動。就可以實現Linux 下運行的kbmmw server 了。

一下子直接跨三個平臺。太爽了。

?

在此再次感謝開源delphi-cross-socket 的大牛兄弟。

?

轉載于:https://www.cnblogs.com/xalion/p/8379518.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/155305.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息