利用Delphi-cross-socket 库提升kbmmw 跨平台开发
以前我写过了,通过httpsys 提升windows 下,delphi 多层应用。随着delphi 10.2 对linux 的支持,很多人也想在linux 下
发布kbmmw 服务器,但是官方仅通过indy 支持 linux。刚好国内有大牛开源了Delphi 跨平台 Socket 通讯库.
通过这个可以直接让kbmmw 服务器高速的运行在在windows、linux、Mac 上。
delphi-cross-socket 的开源地址为:https://github.com/winddriver/Delphi-Cross-Socket
下面是官网的部分介绍。
Delphi 跨平台 Socket 通讯库 作者: WiNDDRiVER(soulawing@gmail.com)
重要更新(2017.08.22) 代码重构, 做了大量修改, 详见源码
增加了几个新的 interface, 用法详见 demos
ICrossSocket
ICrossSslSocket
ICrossServer
ICrossSslServer 特性 针对不同平台使用不同的IO模型:
IOCP Windows KQUEUE FreeBSD(MacOSX, iOS...) EPOLL Linux(Linux, Android...) 支持极高的并发
Windows 能跑10万以上的并发数, 需要修改注册表调整默认的最大端口数 Mac 做了初步测试, 测试环境为虚拟机中的 OSX 10.9.5, 即便修改了系统的句柄数限制, 最多也只能打开32000多个并发连接, 或许 OSX Server 版能支持更高的并发吧 同时支持IPv4、IPv6 零内存拷贝 已通过测试 Windows
OSX
iOS
Android
Linux 建议开发环境 要发挥跨平台的完整功能请使用Delphi 10.2 Tokyo及以上的版本
最低要求支持泛型和匿名函数的Delphi版本, 具体是从哪个版本开始支持泛型和匿名函数的我也不是太清楚
大家可以下载对应的源码,并使用delphi 测试它附带的例子程序。
今天简单说一下如何利用delphi-cross-socket 实现kbmmw 的跨平台开发。
首先我们做一个kbmmw transport.
声明如下。
unit kbmMWCrossScoketServerTransport;
{.$define httpsyslog}
interface
uses
Classes, 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;
type
TProtServer = class(TkbmMWServer);
TxalionTransport=class(TkbmMWCustomServerTransport);
Txalioninfo=class(TkbmMWServerTransportInfo);
Txalionserver = class
private
FServer:Tkbmmwserver;
FTransport: TkbmMWCustomServerTransport;
FSocket: {$IFDEF __SSL__}TCrossSslSocket{$ELSE}TCrossSocket{$ENDIF};
procedure OnReceived(Sender: TObject; AConnection: ICrossConnection; ABuf: Pointer; ALen: Integer);
public
constructor Create;
destructor Destroy; override;
end;
TkbmMWCustomCrossScoketServerTransport = class(TkbmMWCustomServerTransport)
private
{ Private declarations }
FCrossScoketServer: TxalionServer;
Fhost:string;
Fport:integer;
// Fssl:boolean;
Fversion:string;
public
// @exclude
constructor Create(AOwner:TComponent); override;
// @exclude
destructor Destroy; override;
public
class 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}
var
filelogmgr:TkbmMWLocalFileLogManager;
{$endif}
实现部分如下:
implementation function kbmMWCrossScoketPutVerificationHeader(Size:integer):Tbytes;
var
s:string;
c:byte;
i:integer;
const
EOL=##;
begin
s:=format('KBMMW X%0.8x ',[Size]); // 16 bytes.
c:=;
for i:=KBMMW_STRINGCHAROFS to -KBMMW_STRINGCHARLENOFS do
c:=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 := to length(s) do
result[i-]:=ord(s[i]); end; function kbmMWCrossScoketGetVerificationHeader(buff:pointer;len:integer):integer;
var
s,s1:string;
c,c1:byte;
i:integer;
pb:pbyte;
const
SINVDATA = 'Invalid data';
begin
Result:=; // Satisfy compiler.
c1:=;
s:='';
try pb:=buff;
for I := to do
s:=s+chr((pb+i)^); // Extract checksum.
try
s1:=copy(s,,);
c1:=strtoint(s1);
except
kbmMWRaiseException(KBMMW_ERR_TRANSPORT_INVALIDDATA,SINVDATA);
end; // Calculate checksum.
c:=;
for i:=KBMMW_STRINGCHAROFS to -KBMMW_STRINGCHARLENOFS do
c:=c xor ord(s[i]); // Match?
if c<>c1 then
exit;
//kbmMWRaiseException(KBMMW_ERR_TRANSPORT_INVALIDDATA,SINVDATA); // Extract size.
s1:=copy(s,,);
try
Result:=strtoint(s1);
except
exit; // kbmMWRaiseException(KBMMW_ERR_TRANSPORT_INVALIDDATA,SINVDATA);
end; except
kbmMWDebugDumpMemory(mwdlAdvanced,mwdtTransport,kbmMWDebugWhere,'Exception during iocp verification',
PByte(s),ByteLength(s));
raise;
end;
end; constructor Txalionserver.Create;
begin
inherited;
FSocket :=
{$IFDEF __SSL__}
TCrossSslSocket
{$ELSE}
TCrossSocket
{$ENDIF}
.Create();
//FSocket.OnConnected := OnConnected;
FSocket.OnReceived := OnReceived;
end; destructor Txalionserver.Destroy;
begin
FSocket.Free;
inherited;
end; procedure Txalionserver.OnReceived(Sender: TObject; AConnection: ICrossConnection; ABuf: Pointer; ALen: Integer); var headlen: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;
begin inStreamFormat:=TxalionTransport(FTransport).StreamFormat;
if (inStreamFormat<>'STANDARD') then
begin
raise Exception.Create('Only support STANDARD StreamFormat.');
end;
// begin if TxalionTransport(FTransport).VerifyTransfer then
begin
headlen:=; if kbmMWCrossScoketGetVerificationHeader(abuf,alen)<>(alen-headlen) then //21为校验的头 begin
AConnection.SendBytes(Tencoding.UTF8.GetBytes('Invalid data'));
exit;
end; end
else
begin
headlen:=;
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; try
if inlen> then
begin
InStream.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 then
begin
rethead:=kbmMWCrossScoketPutVerificationHeader(retl);
AConnection.SendBytes(rethead); // client.Send(rethead[0],headlen);
end
else
begin SetLength(bSize,);
bSize[]:=(retl shr (++)) and ;
bSize[]:=(retl shr (+)) and ;
bSize[]:=(retl shr ()) and ;
bSize[]:=retl and ; AConnection.SendBytes(bsize);
//client.Send(bsize[0],4);
end; setlength(retdata,retl);
move(OutStream.DataStream.Memory^,retdata[],retl);
AConnection.SendBytes(retdata); except
on E: Exception do
begin
{$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;
begin if state=mwtrstDisconnected then exit; FCrossScoketServer.FSocket.DisconnectAll; // Fiocpserver.fiocpServer.Stop;
SetState(mwtrstDisconnected);
end; constructor TkbmMWCustomCrossScoketServerTransport.Create(AOwner: TComponent);
begin
inherited; FCrossScoketServer:= TxalionServer.Create; Fhost:='0.0.0.0';
Fport:=; self.VerifyTransfer:=True; fversion:=sysversion; end; destructor TkbmMWCustomCrossScoketServerTransport.Destroy;
begin
if FCrossScoketServer<>nil then
freeandnil(FCrossScoketServer);
inherited;
end; class function TkbmMWCustomCrossScoketServerTransport.IsConnectionlessTransport: boolean;
begin
Result:=False;
end; function TkbmMWCustomCrossScoketServerTransport.IsListening: boolean;
begin
Result:=(state=mwtrstListening);
end; class function TkbmMWCustomCrossScoketServerTransport.IsSerializedTransport: boolean;
begin
Result:=true;
end; procedure TkbmMWCustomCrossScoketServerTransport.Listen; begin
inherited; if state=mwtrstListening then exit; FCrossScoketserver.FServer:=server;
FCrossScoketserver.FTransport:=self;
FCrossScoketserver.FSocket.Listen(Fhost,Fport);
SetState(mwtrstListening); end; {$ifdef httpsyslog}
initialization
filelogmgr:=TkbmMWLocalFileLogManager.Create('./kbmmwlog.txt'); // ,一个是日志文件
filelogmgr.FileOptions:=[mwlfoDeleteOldLog];//:=true; // 删除老的日志文件
filelogmgr.FlushInterval:=; // 写文件时间间隔,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 的大牛兄弟。
利用Delphi-cross-socket 库提升kbmmw 跨平台开发的更多相关文章
- 利用Delphi编写Socket通信程序
一.Delphi与Socket 计算机网络是由一系列网络通信协议组成的,其中的核心协议是传输层的TCP/IP和UDP协议.TCP是面向连接的,通信双方保持一条通路,好比目前的电话线,使用telnet登 ...
- Delphi的Socket编程步骤(repulish)
转贴自:http://topic.csdn.net/t/20010727/16/212155.html ClientSocket 和ServerSocket几个重要的属性: 1.client和se ...
- Delphi与Socket
一.Delphi与Socket计算机网络是由一系列网络通信协议组成的,其中的核心协议是传输层的TCPIP和UDP协议.TCP是面向连接的,通信双方保持一条通路,好比目前的电话线,使用telnet登陆B ...
- 利用Delphi监视注册表的变化
转帖:利用Delphi监视注册表的变化 2009-12-23 11:53:51 分类: 利用Delphi监视注册表的变化 我们在编写软件的时候,常常需要把一些信息保存到系统的注册表中.如果 ...
- 用clumsy模拟丢包测试socket库的失败重传
用python的socket库写了通信小程序,现在我需要通过软件模拟出在网络极差的情况下,socket底层解决丢包问题的能力怎么样,我一开始想的是分别在linux和windowns下分别测试,后来一想 ...
- Python底层socket库
Python底层socket库将Unix关于网络通信的系统调用对象化处理,是底层函数的高级封装,socket()函数返回一个套接字,它的方法实现了各种套接字系统调用.read与write与Python ...
- oracle 利用flashback将备库激活为read wirte(10g 及上)
oracle 利用flashback将备库激活为read wirte(10g 及上) 环境: OS: CENTOS 6.5 X64 DB: ORACLE 10.2.0.5 主库操作: SQL> ...
- 利用Delphi的File Of Type创建并管理属于你自己的数据库
http://www.360doc.com/content/16/1128/19/28222077_610249962.shtml 利用Delphi的File Of Type创建并管理属于你自己的数据 ...
- zw版【转发·台湾nvp系列Delphi例程】Delphi 使用 HALCON库件COM控件数据格式转换
zw版[转发·台湾nvp系列Delphi例程]Delphi 使用 HALCON库件COM控件数据格式转换 Delphi 使用 HALCON库件COM控件数据格式转换,与IHObjectX接口有关 va ...
随机推荐
- Vue之常用语法
变量的定义: var定义的变量:只有全局作用域和函数作用域.有变量提升,先打印后定义变量不会报错,打印结果为undefined let定义的变量:没有变量提升 ——>有局 ...
- Intent Activity跳转 传递数据 Bundle
1.普通跳转: Intent intent=new Intent(); intent.setClass(MainActivity.this,NewActivity.class); //新建一个Inte ...
- 微信小程序开发——开发者工具无法输入中文的处理
问题模块 框架类型 问题类型 操作系统 工具版本 开发者工具 小程序 Bug Windows v.02.1810290 异常描述: 无法输入中文,偶现,但是概率有点高,重启,重装,更新版本等等都未解决 ...
- jquery is()和has()方法
1. is() :判断当前节点是否是否匹配选择器.返回布尔值: 2. has():判断当前节点是否包含选择器中的子元素,返回包含固定子元素的父元素(jquery对象) 用法:可用于判断父元素中是否包含 ...
- 第五章 Inheritance继承
[继承] Java不支持多重继承 - 每个子类只有一个超类. 不是将成员变量声明为静态,更好的做法是将University实例化为对象,然后使用该对象访问其成员,如下所示: [抽象类] 可以包含或者不 ...
- java 线程Thread 技术--线程状态与同步问题
线程技术第三篇: 线程的状态: 1. 创建状态: 当用new 操作符创建一个新的线程对象时,该线程就处于创建状态,系统不为它分配资源 2.可运行状态:当线程调用start 方法将为线程分配必须的系统资 ...
- 无法连接到localhost。其他信息:用户“sa”登录失败。原因:该用户被禁用。(Microsoft Sql Server,错误:18470).
18470错误: 解决方案: 使用windows身份验证登录之后,选择安全性--->登录名--->sa--->右击--->属性: 右击选择属性进入属性页面: 选择状态,然后再登 ...
- mysql数据库存储经度纬度
使用float或者double会自动四舍五入,用decimal(20,17)当然你用varchar也是可以的
- Python中setup.py一些不为人知的技巧
http://python.jobbole.com/80912/ 在我开始之前,我想先说清楚我将要解释的是些“窍门”.他们不是“最好的做法”,至少在一种情况下是不可取的. 说到不可取的做法,我会适时写 ...
- Nginx 的 docker 部署
1.输入命令 docker pull nginx:1.15 拉取 nginx 的镜像: 2.使用 docker images 查看拉取到的镜像信息: 3.在主机上创建用于映射的目录 mkdir -p ...