核心提示:一直以来,delphi 的网络通讯层都是以indy 为主,虽然indy 的功能非常多,涉及到网络服务的各个方面,但是对于大多数多层服务来说,就是需要一个快速、稳定、高效的传输层。Delphi 的 datasnap主要通过三种实现数据通讯的,一种是大家恨得牙痒痒的indy,另外一种是通过iis 的is...

一直以来,delphi 的网络通讯层都是以indy 为主,虽然indy 的功能非常多,涉及到网络服务的

各个方面,但是对于大多数多层服务来说,就是需要一个快速、稳定、高效的传输层。Delphi 的 datasnap

主要通过三种实现数据通讯的,一种是大家恨得牙痒痒的indy,另外一种是通过iis 的isapi,最后一种是通过

apache  的动态模块(DSO) 来实现。

indy 的问题多多,大家基本上都是趋向使用后两种方式,后面两种方式的麻烦是必须安装IIS 或者是

Apache。用起来还要配置很多东西,也不是太方便。

还好,微软在Windows Vista (server 2008) 以后使用http.sys 作为web 服务的核心,IIS 也是通过这个核心

实现其web 服务的。使用http.sys 都有哪些优势呢?

1.不用做额外的编码,直接支持https(妈妈再也不用担心ios 10 要 https 了)

2.内核级的缓冲和内核级的请求队列(大大降低应用服务器自身的压力)

3.多个应用程序可以使用同一个端口(防火墙表示很欣慰)

4.内核级的SSL 支持

5.内核级的静态文件输出支持

6.理论上,这是windows 下最快的http 服务,没有之一。

这么多好处,那么我们是否可以在delphi 里面直接使用http.sys ,让delphi 的多层服务在windows 下飞起来?

答案是肯定的,delphi 完全可以非常顺利的使用http.sys  服务,不光是webbroke, datasanp, 包括我们常用的kbmmw.

目前delphi 的第三方控件里面支持http.sys 的主要有两个,一个是著名的控件商TMS, 其专门有一个控件叫TMS Sparkle

主要就是封装http.sys 服务,这个公司的其他的一些多层控件都是架构在这个控件上的,唯一不好的是,它是商业软件,需要

付费购买。另外一个就是著名的开源框架mormot。此作者的功力已经是恐龙级,可以进delphi  界牛人前十名。他在mormot

里面也封装了 http.sys. 由于是开源的,所以是需要自己把对应封装的代码拿出来,实现与delphi 现有的多层应用适配。

下面以mormot  封装的 THttpApiServer 为例,说明一下在多层应用中如何使用适配使用http.sys.

我们首先解决webbroker 中如何使用THttpApiServer?

其实如果大家对webbroker  比较了解的话,就知道webbroker 的工作原理就是把客户端来的请求分发到webbroker 的处理过程,

然后再把返回结果响应给客户端。那么我们需要做一个winapiWebBrokerBridge,功能就是完成以上要求。

首先下载mormot 源码,添加相关目录。

然后加入我们的单元,需要使用的相关对象声明如下:

unit winapiWebBrokerBridge;{ by xalion  2016.12.25} interface uses   Classes,
HTTPApp,
SysUtils,
system.NetEncoding,
SynCommons,
SynZip,
SynCrtSock , WebBroker, WebReq;type EWBBException = class(EWebBrokerException);
EWBBInvalidIdxGetDateVariable = class(EWBBException);
EWBBInvalidIdxSetDateVariable = class(EWBBException );
EWBBInvalidIdxGetIntVariable = class(EWBBException );
EWBBInvalidIdxSetIntVariable = class(EWBBException );
EWBBInvalidIdxGetStrVariable = class(EWBBException);
EWBBInvalidIdxSetStringVar = class(EWBBException);
EWBBInvalidStringVar = class(EWBBException); Twinapirequestinfo=class(Tobject)
protected FHttpServerRequest:THttpServerRequest;
Finrawheaders:Tstringlist;
FContentStream : TStream;
FFreeContentStream : Boolean;
Fhost:string;
Fport:string;
Fcontent:string;
FURL:string;
Fremoteip:string;
Fcontentlength:integer;
fInContentType:string; Fcommand:string;
public constructor Create(C: THttpServerRequest);
destructor Destroy; override;
end; Twinapiresponseinfo=class(Tobject)
protected FHttpServerRequest:THttpServerRequest;
Foutrawheaders:Tstringlist;
FContentStream : TStream;
FFreeContentStream : Boolean;
Fhost:string;
Fport:string;
Fcontent:string;
Fcontenttype:string;
Fcontentlength:integer;
Fstatuscode:integer;
FCookies: TCookieCollection;
public constructor Create(C: THttpServerRequest);
destructor Destroy; override;
procedure AddCookiestohead;
end; TwinapiAppRequest = class(TWebRequest)
protected FRequestInfo : TwinapiRequestInfo;
FResponseInfo : TwinapiResponseInfo;
FFreeContentStream : Boolean;
FStatusCode:integer;
// function GetDateVariable(Index: Integer): TDateTime; override;
function GetIntegerVariable(Index: Integer): Integer; override;
function GetStringVariable(Index: Integer): string; override;
function GetRemoteIP: string; override;
function GetRawPathInfo:string; override;
function GetRawContent: TBytes; override; public constructor Create(arequestinfo:Twinapirequestinfo; aresponseinfo:Twinapiresponseinfo);
destructor Destroy; override;
function GetFieldByName(const Name: string): string; override; function ReadClient(var Buffer; Count: Integer): Integer; override;
function ReadString(Count: Integer):string; override;
function TranslateURI(const URI: string): string; override; function WriteHeaders(StatusCode: Integer; const ReasonString, Headers: string): Boolean; override; end; TwinapiAppResponse = class(TWebResponse)
protected FRequestInfo : TwinapiRequestInfo;
FResponseInfo : TwinapiResponseInfo;
function GetContent: string; override;
function GetStatusCode: Integer; override;
procedure SetContent(const AValue: string); override;
procedure SetContentStream(AValue: TStream); override;
procedure SetStatusCode(AValue: Integer); override;
procedure SetStringVariable(Index: Integer; const Value:string); override;
procedure SetDateVariable(Index: Integer; const Value: TDateTime); override;
procedure SetIntegerVariable(Index: Integer; Value: Integer); override; public constructor Create(AHTTPRequest: TWebRequest;arequestinfo:Twinapirequestinfo; aresponseinfo:Twinapiresponseinfo);
destructor Destroy; override;
procedure SendRedirect(const URI: string); override;
procedure SendResponse; override;
procedure SendStream(AStream: TStream); override;
function Sent: Boolean; override;
end; TwinapiWebBrokerBridge = class(THttpApiServer)
private // procedure RunWebModuleClass(C : THttpServerRequest); protected FWebModuleClass: TComponentClass;
function Request(C : THttpServerRequest): cardinal;override; public procedure RegisterWebModuleClass(AClass: TComponentClass); end;

然后我们就可以使用这个,实现我们的webbroker 应用了。

我们使用delphi 自带的向导,开始建一个webserver.

点ok,继续

点完成。

生成对应的工程文件,然后我们替换主窗体的代码。

主程序对应的代码很简单。

unit mainp;

interface

uses
  Winapi.Messages, System.SysUtils, System.Variants,  SynCrtSock,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.AppEvnts, Vcl.StdCtrls, winapiWebBrokerBridge, Web.HTTPApp; type
  TForm1 = class(TForm)
    ButtonStart: TButton;
    ButtonStop: TButton;
    EditPort: TEdit;
    Label1: TLabel;
    ApplicationEvents1: TApplicationEvents;
    ButtonOpenBrowser: TButton;
    procedure ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
    procedure ButtonStartClick(Sender: TObject);
    procedure ButtonStopClick(Sender: TObject);
    procedure ButtonOpenBrowserClick(Sender: TObject);
  private
    FServer: TwinapiWebBrokerBridge;
    procedure StartServer;
    { Private declarations }
  public
    { Public declarations }
  end; var
  Form1: TForm1; implementation {$R *.dfm} uses
  WinApi.Windows, Winapi.ShellApi;
procedure TForm1.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);begin if fserver=nil then begin ButtonStart.Enabled :=True;
ButtonStop.Enabled :=false;
EditPort.Enabled := True;
end else begin ButtonStart.Enabled := not FServer.Started;
ButtonStop.Enabled := FServer.Started ;
EditPort.Enabled := not FServer.Started;
end;end;procedure TForm1.ButtonOpenBrowserClick(Sender: TObject);var LURL: string;begin LURL := Format('http://localhost:%s', [EditPort.Text]);
ShellExecute(0,
nil,
PChar(LURL), nil, nil, SW_SHOWNOACTIVATE);end;procedure TForm1.ButtonStartClick(Sender: TObject);begin StartServer;end;procedure TForm1.ButtonStopClick(Sender: TObject);begin freeandnil( FServer);end;procedure TForm1.StartServer;begin FServer := TwinapiWebBrokerBridge.Create(True); Fserver.Clone(10);// 开始10个进程 Fserver.AddUrl('/','8080',false,'+',true);
fserver.Start;end;

webmodel 里面就很简单了

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);begin response.Content:='你好!' end;

然后我们开始运行这个程序。

打开浏览器,就会发现,我们的webbroker 程序运行正常。

webbroker 服务器成功了,那么常用的webservice 也就不在话下了。

根据自带的向导,替换对应的主主窗体的文件,运行,棒棒哒。

有同学质疑,这个真的是http.sys提供的服务吗?

那么有图有真相:

datasnap  的·例子就不再演示了,方法与上面差不多。

最后,对于不使用datasnap,使用kbmmw  的同学,不用担心,在kbmmw   里面照样可以使用http.sys ,

只不过是要写对应的transport.下面给出服务端和客户端的对象声明。

unit kbmMWHTTPAPIServerTransport;{$define httpsyslog} interface uses   Classes, Sysutils,
kbmMWCustomTransport,kbmMWServer,kbmMWGlobal, variants, kbmMWHTTPUtils,
{$ifdef httpsyslog} kbmMWLog,
{$endif} SynCommons,
SynZip,
SynCrtSock;type TProtServer = class(TkbmMWServer);
TxalionTransport=class(TkbmMWCustomServerTransport); Txalioninfo=class(TkbmMWServerTransportInfo); Txalionserver = class private FServer:Tkbmmwserver;
FTransport: TkbmMWCustomServerTransport; fPath: TFileName;
fapiServer: THttpApiServer;
function Process(C : THttpServerRequest): cardinal;
public
destructor Destroy; override; end; TkbmMWCustomhttpapiServerTransport = class(TkbmMWCustomServerTransport)
private { Private declarations } FhttpsysServer: TxalionServer; Fhost:string;
Fport:string;
FServerUrl:string;
Fssl:boolean;
Fversion:string;
FHTTPQueueLength: integer; FServerThreadPoolCount :integer; 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 { 设置url 例如/kbmmw} property ServerURL:string read Fserverurl write Fserverurl; { 服务器 ip 例如 127.0.0.1} property Host:string read Fhost write Fhost; property Port:string read Fport write Fport; property SSL:boolean read fssl write fssl; Property Version:string read Fversion;
property HTTPQueueLength: integer read FHTTPQueueLength write FHTTPQueueLength;
property ServerThreadPoolCount: integer read FServerThreadPoolCount write FServerThreadPoolCount; end; TkbmMWhttpapiServerTransport= class(TkbmMWCustomhttpapiServerTransport)
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 httpsysversion.inc}
unit kbmMWNativeHTTPClientTransport;// by xalion interface {$I kbmMW.inc} {.$define indyhttp} {.$define httpsyslog} uses   Classes, Sysutils, kbmMWCustomTransport,kbmMWClient,

  {$ifdef indyhttp}     idhttp,
{$else} System.Net.HttpClientComponent,System.Net.HttpClient,
{$endif} {$ifdef httpsyslog} kbmMWLog,
{$endif} kbmMWGlobal;type {$IFDEF LEVEL16} [ComponentPlatformsAttribute({$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} TkbmMWNativeHTTPClientTransport = class(TkbmMWCustomClientTransport)
private {$ifdef indyhttp} FHttpClient:Tidhttp;
{$else} FHttpClient:TNetHTTPClient;
{$endif} FTimeout:integer;
MyRequestContent:TMemoryStream;
fhost:string;
fserverurl:string;
fssl:boolean;
Fversion:string;
FClientType:string; public constructor Create(AOwner:TComponent); override;
destructor Destroy; override; class function IsSerializedTransport:boolean; override;
class function IsConnectionlessTransport:boolean; override; procedure Connect; override;
procedure Disconnect; override;
procedure Assign(ATransport:TPersistent); override; function ReceiveStream(AInfo:IkbmMWCustomTransportInfo; const AStream:IkbmMWCustomTransportStream; ALimit:integer):boolean; override;
procedure TransmitStream(AInfo:IkbmMWCUstomTransportInfo; const AStream:IkbmMWCustomTransportStream); override;
published property Host:string read fhost write fhost;
property ServerURL:string read fserverurl write fserverurl;
property SSL:boolean read fssl write fssl;
Property ClientType:string read FClientType;
Property Version:string read Fversion; property Crypt ;
property Compression ;
property StreamFormat;
property StringConversion;
property Timeout:integer read FTimeout write FTimeout default 3000;
property OnException; property OnConnectionLost;
property OnReconnect;
property MaxRetries;
property MaxRetriesAlternative;
property ConnectionString;
property FallbackServers;
property AutoFallback;
property VerifyTransfer; end;
{$I httpsysversion.inc}

使用http.sys 的应用服务器比使用indy 的速度及稳定性都大大提高。

经过多个实际项目的使用,效果非常好。

总而言之,在windows 上,使用http.sys,就这么自信!

作者:xalion 录入:142857 来源:转载

使用http.sys,让delphi 的多层服务飞起来的更多相关文章

  1. 使用delphi 开发多层应用(二十一)使用XE5 RESTClient 直接访问kbmmw 数据库

    delphi XE5 出来了,增加了android 的开发支持,另外增加了一个RESTClient 来支持访问REST 服务器. 这个功能非常强大,可以直接使用非常多的REST 服务器.同时也可以支持 ...

  2. 在Delphi开发的服务中调用指定应用程序

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://fxh7622.blog.51cto.com/63841/529033 在很多时候 ...

  3. 使用delphi 开发多层应用(十六)使用XMLRPC 实现basic4android 远程调用RTC服务(讲述了RTC的特点,其底层通讯协议是自己封装SOCK 库,与kbmmw 的适合场合不完全一样)

        RealThinClient (以下简称RTC) 也是一款delphi 多层开发的框架,由于其底层通讯协议是自己封装SOCK 库,抛弃了 大家诟病的indy,因此表现的非常稳定,效率也非常高, ...

  4. Delphi的TService 服务路径获取 Dll中获取文件路径

    研究delphi服务的路径,试了好几个方法 ,都没取出来,最后发现,要采用取DLL路径的方法 //一.获取Dll自身路径 //1)方法一: Function GetDllPath(sDllName:s ...

  5. 使用delphi 开发多层应用(二十二)使用kbmMW 的认证管理器

    从kbmmw 4.4 开始,增加了认证管理器,这个比原来的简单认证提供了更多的功能.细化了很多权限操作. 今天对这一块做个介绍. 要做一个认证管理,大概分为以下5步: 1.  定义你要保护的资源,一般 ...

  6. 使用delphi 开发多层应用(十九) ios通过soap 访问kbmmw服务器

    随着delphi XE4 的推出,开始真正意义上支持ios 的开发,由于目前kbmmw 还不完全支持ios 的开发,因此 无法直接使用kbmmw 的客户端访问kbmmw 的服务器(虽然kbmmw 也提 ...

  7. Win7/Vista/Server2008下VS 环境 调试调用 HTTP.SYS 无法启动监听服务及启动后其他机器无法访问端口

    一. VS调试在Win7(vista系列)操作系统下 HttpListener无法绑定多个 指定IP.端口问题 来自:http://www.cnblogs.com/ryhan/p/4195693.ht ...

  8. 转(Delphi 新窑洞):使用delphi 开发多层应用(十七)使用RTC web 服务器返回JSON

    RTC作为delphi 的最专业的web 应用服务器,如果客户端要使用JSON 的话,那么使用RTC 应该也是一种 非常好的选择.下面我们做一个使用RTC web 服务器返回数据库JSON 的例子. ...

  9. delphi xe5 android 服务端和手机端的源码下载

    xe5 android的服务端和手机客户端的源代码下载地址 http://files.cnblogs.com/nywh2008/AndroidTest.rar

随机推荐

  1. 高性能JavaScript 编程实践

    前言 最近在翻<高性能JavaScript>这本书(2010年版 丁琛译),感觉可能是因为浏览器引擎的改进或是其他原因,书中有些原本能提高性能的代码在最新的浏览器中已经失效.但是有些章节的 ...

  2. cosbench read异常解决办法。 Unable to verify integrity of data download. Client calculated content hash didn't match hash calculated by Amazon S3. The data may be corrupt.

    问题:cosbench read测试failed 报错如下 Cosbench v0.4.2.c4 against Ceph (Hammer) / radosgw / HAproxy's HTTP en ...

  3. XRecyclerView Scrapped or attached views may not be recycled

    将XRecyclerView布局设置为 android:layout_width="match_parent"android:layout_height="match_p ...

  4. redis-介绍与比较

    <一>. NoSQL简介:    NoSQL是Not-Only-SQL的缩写,是被设计用来替换传统的关系型数据库在某些领域的用,特别针对web2.0站点以及大型的SNS网站,用来满足高并发 ...

  5. angularjs中ckeditor的destroy问题

    项目中,在切换了页面的tab页后会发现上传图片的操作报错,检查后发现问题根源是切换了tab页重新加载页面时ckeditor又会创建一次,这个时候的ckeditor已经不是第一次创建的那个了,所以上传图 ...

  6. VsFtpd服务配置简明笔记

    Ftp服务是最常用的文件传输方式,把配置步骤记录下来,以备将来使用. 1.用YUM安装VsFtpd服务:[root@Redis usr]# yum install vsftpd 2.安装完成后启动Vs ...

  7. Java中 NIO与IO的区别

    当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们如何影响您的代 ...

  8. win7下装ubuntu14.04双系统

    一.给ubuntu准备安装空间 计算机--右键--管理-磁盘管理--选择一个空余空间较多的磁盘--右键--压缩卷--压缩大概60G空间(接下来ubuntu就会装到这60G里面)   二.制作启动u盘 ...

  9. 【转】javascript面向对象编程

    摘要:本文本来是想自己写的,奈何花了好长时间写好之后忘记保存,还按了刷新键,一键回到解放前,索性不写了,所以本文是转载的. 面向对象编程是用抽象方式创建基于现实世界模型的一种编程模式,主要包括模块化. ...

  10. python学习笔记-(十六)python操作mysql

    一. mysql安装 1. windows下安装mysql 1.1. 下载源: http://dev.mysql.com/downloads/installer/,请认准对应版本 Windows (x ...