1. 程式人生 > >使用http.sys,讓delphi 的多層服務飛起來

使用http.sys,讓delphi 的多層服務飛起來

一直以來,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 原始碼,新增相關目錄。

然後加入我們的單元,需要使用的相關物件宣告如下:

20×20
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;
20×20

然後我們就可以使用這個,實現我們的webbroker 應用了。

我們使用delphi 自帶的嚮導,開始建一個webserver.

1344×1024

 點ok,繼續

1042×1044

1042×1044

1042×1044

 點完成。

生成對應的工程檔案,然後我們替換主窗體的程式碼。

823×555

主程式對應的程式碼很簡單。

20×20
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;
20×20

webmodel 裡面就很簡單了

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

然後我們開始執行這個程式。

802×530

開啟瀏覽器,就會發現,我們的webbroker 程式執行正常。

855×279

 webbroker 伺服器成功了,那麼常用的webservice 也就不在話下了。

根據自帶的嚮導,替換對應的主主窗體的檔案,執行,棒棒噠。

885×821

有同學質疑,這個真的是http.sys提供的服務嗎?

那麼有圖有真相:

2049×1461

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

最後,對於不使用datasnap,使用kbmmw  的同學,不用擔心,在kbmmw   裡面照樣可以使用http.sys ,

只不過是要寫對應的transport.下面給出服務端和客戶端的物件宣告。

20×20
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}
20×20 20×20
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;
    
            
           

相關推薦

使用http.sysdelphi服務真的起來

dem app reads ... lean 核心 syn ive word 原delphi窯洞洞主xalion在自己的博客上發過一篇文章: 《使用http.sys,讓delphi 的多層服務飛起來》 http://www.cnblogs.com/xalion/p/6219

使用http.sysdelphi服務起來

一直以來,delphi 的網路通訊層都是以indy 為主,雖然indy 的功能非常多,涉及到網路服務的 各個方面,但是對於大多數多層服務來說,就是需要一個快速、穩定、高效的傳輸層。Delphi 的 datasnap 主要通過三種實現資料通訊的,一種是大家恨得牙癢癢的i

Delphi開發方案比較

以下轉載自: http://blog.sina.com.cn/s/blog_53decb4101009a5m.html~type=v5_one&label=rela_nextarticle http://blog.csdn.net/SmallHand/archive

直播協議人氣整Cip服務器對他有大的影響?

飛翔 服務器 都是 一道 水流 bgp 什麽 批評 對他 慶歷四年的春天,滕子京被降職到巴陵郡做太守。到了第二年,政事順利,百姓和樂,各種荒廢的事業都興辦起來了。於是重新修建嶽陽樓,擴大它原有的規模,把唐代名家和當代人的詩賦刻在它上面。囑托我寫一篇文章來記述這件事情。 整C

結合實際需求在webapi內利用WebSocket建立單向的訊息推送平臺A頁面和服務端建立WebSocket連線其他頁面可以及時給A頁面推送訊息

1.需求示意圖     2.需求描述 原本是為了給做unity3d客戶端開發的同事提供不定時的訊息推送,比如商城購買道具後服務端將道具資訊推送給客戶端。 本篇文章簡化理解,用“相關部門開展活動,向全市人民徵集社會服務改善意見”為例子。但核心想法一致:單向推送(指這個需求上只需要單向)。所

一款直擊痛點的優秀http框架我超高效率完成了和第三方介面的對接

## 1.背景 因為業務關係,要和許多不同第三方公司進行對接。這些服務商都提供基於http的api。但是每家公司提供api具體細節差別很大。有的基於`RESTFUL`規範,有的基於傳統的http規範;有的需要在`header`裡放置簽名,有的需要`SSL`的雙向認證,有的只需要`SSL`的單向認證;有的以`

一個Shell指令碼裝逼的小技巧指令碼屏顯酷炫起來

在我們腦海裡,Shell指令碼執行在Putty/Xshell裡也就是黑白的字元,但今天小編整理了一個可以快速讓你讓Sehll指令碼的列印屏顯酷炫起來,下面這條命令: echo -e “\033[44;37;5m So Cool! \033[0m” 執行後,打印出來的效果是這樣的,是不是覺得逼格滿滿?

環信小程式 Demo原始碼釋出你的小程式聊起來

1月9日,向喬布斯致敬的張小龍如約釋出了微信小程式,首批上線的小程式就有300多家,一時刷爆朋友圈,如果不轉發一兩條有關小程式的內容,你都不好意思自稱挨踢人。從效率看,小程式成功給APP瘦身,節省了系統資源。以往使用者

建立Linux 0.11完整的系統linux 0.11真正轉起來!方便大家學習。 中文版權所有: OldLinux論壇 

為了配合Linux 0.11核心工作原理的學習,本章介紹了利用PC機模擬軟體和在實際計算機上執行Linux 0.11系統的方法。其中包括核心的編譯過程、PC模擬環境下檔案的訪問和複製、引導盤和根檔案系統的製作方法以及Linux 0.11系統的使用方法。最後還說明了如何對核心程

Spring Boot(三): 在Spring Boot中使用log4j2你的console端豐富起來

maven依賴 <dependency> <groupId>org.springframework.boot</groupId>

讀“你的軟件起來”持續更新代碼運行效率之路

根據 查表 個人 通過 不知道 代碼 時間 方向 詞匯   通過看作者改進代碼運行效率的過程,頗受震撼。以前只是關註一個算法的空間復雜度以及時間復雜度,看到初寫的代碼,就感覺已經沒有可以進行優化的方向了。 但是作者卻采用多種方式,達到了令人驚訝的結果。首先記錄作者的改進的幾

ARKit從入門到精通(10)-ARKit飛機繞著你起來

img self. lin code 視圖 it教程 href earth plan 1.1-ARKit物體圍繞相機旋轉流程介紹 1.2-完整代碼 1.3-代碼下載地址 廢話不多說,先看效果 其實是會一直圍著你轉圈的,只不過筆者不好意思暴露家

用AppiumAndroid功能自動化測試起來

turn 代碼片段 cti pass 三種 align sel 方式 sock p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 24.0px "Helvetica Neue"; color: #2f2f2f } p.p2 { ma

用WordPress程式做博的一些基本設定你的部落格起來

大家做自媒體部落格一般網站上線後,像網站模板,欄目,LOGO等基本設定後,就製作運營相關的工作就行了,因為WordPress程式,簡單快捷,模板多,操作簡單,所以WP程式成為很多網友的首選建站程式,但是用WordPress建站的話需要注意設定一些細節,這樣你的部落格會有一個

頁面滑動流暢得起來的新特性:Passive Event Listeners

function handler(event) { console.log(event.type); // log event type } document.addEventListener("mousewheel", handler, {passive:true});

寫個shell指令碼搭載jenkins你的程式部署起來

【轉載請註明】: 原文出處:https://www.cnblogs.com/jstarseven/p/11399251.html    作者:jstarseven    碼字挺辛苦的.....  說明:java程式部署是簡單的,尤其是sp

appium+python自動化60-windows上同時啟動個appium服務個android機器並行運行

pre tps yam rom 啟動app 技術分享 AI 如果 aapt 前言 做android自動化的時候,啟動一個appium服務,只能匹配一個手機去自動化執行。有時候想同一套代碼,可以在不同的手機上執行,測下app在不同手機上兼容性。 這就需要啟動多個appium服

EF通用數據封裝類(支持讀寫分離一主從)

dto cte 功能 pes getc mes 工廠 好的 靈活 淺談orm 記得四年前在學校第一次接觸到 Ling to Sql,那時候瞬間發現不用手寫sql語句是多麽的方便,後面慢慢的接觸了許多orm框架,像 EF,Dapper,Hibernate,ServiceSta

請牢記以上幾點做到人願意與你為友

打開 san 無限 你會 並發 span 交朋友 col 若有 請牢記以上幾點,做到讓更多人願意與你為友。若有下一點,你會吸住更多人才的。 第一:你有用。你能帶給人家實用價值。 第二:你有料。跟你相處能打開眼界,放大格局。 第三:你有量。你能傾聽別人的想法並發表有價值的見

日留存、周留存、月留存究竟怎樣才能的用戶留下來?

響應 有效 案例 1年 二次 足夠 獲取 內存 一個 作者:羅曼羅 ,技術出身的pm,一線互聯網平臺高級產品經理。 摘自新浪微博:http://blog.sina.com.cn/s/blog_6fd175b50102vmcg.html 為什麽要寫這個話題?我觀察到現在很多A