DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: cuiqingbo
今日帖子: 25
在线用户: 10
导航: 论坛 -> Web应用开发 斑竹:bodies  
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/20 18:30:46
标题:
使用http.sys,让delphi的多层服务真的飞起来 浏览:30882
加入我的收藏
楼主: 原delphi窑洞洞主xalion在自己的博客上发过一篇文章:
《使用http.sys,让delphi 的多层服务飞起来》
http://www.cnblogs.com/xalion/p/6219515.html
这里边提到如何把mormot的httpserver抠出来,嫁接到webbroker上,非常好的思路。
可惜xalion没贴出全部源代码。

最近对WebBroker做了点深入研究,给出了c5soft的实现,贴出全部源代码。
目前是0.0.0.1版本,仅搭了个框架,但是明眼人一看就明白实现思路,一步一步可以把整个框架填满。
源代码在Delphi7 与Delphi 10.2下编译通过。
此帖子包含附件:c5soft_2018520183046.zip 大小:4.9K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/20 18:31:23
1楼: 执行截图
此帖子包含附件:
JPEG 图像
大小:81.1K
----------------------------------------------
-
作者:
男 snakegao (snakegao) ★☆☆☆☆ -
盒子活跃会员
2018/5/20 19:14:28
2楼: 学习学习,谢谢星5
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/20 19:16:33
3楼: 可行吗?
----------------------------------------------
-
作者:
男 star5 (星五) ★☆☆☆☆ -
盒子活跃会员
2018/5/20 19:23:08
4楼: 2楼,是C5,不是星5


下载看看
----------------------------------------------
博客 - http://offeu.com
脚本模型 - http://webpascal.com
需要短信接口的请联系我,可发行业与营销内容。
作者:
男 kinneng (kinneng) ★☆☆☆☆ -
盒子活跃会员
2018/5/20 19:29:42
5楼: 支持D7就是好!
----------------------------------------------
声明:本人不在论坛询问任何编程问题,请不要将我的帖子当成问题来回答。炒股一天,编程三年,不浪费时间了。 经常在外面,没空,不要找我..
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/20 19:39:01
6楼: 框架使用方法:
第一步,新建WebServer Application
此帖子包含附件:
JPEG 图像
大小:79.6K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/20 19:40:28
7楼: 第二步,选择 CGI Standalone Executable
此帖子包含附件:
JPEG 图像
大小:47.0K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/20 19:43:34
8楼: 第三步,将c5soft写的SynWebApp.pas放到项目文件夹下,修改dpr文件, 将CGIApp替换为SynWebApp in 'SynWebApp.pas'
此帖子包含附件:
JPEG 图像
大小:80.2K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/20 19:44:51
9楼: 后续要点:要让程序编译通过,需要下载mORMot的源文件,并将mORMot添加到Delphi的库搜寻路径中。剩下的要是还不会,就去看web broker开发文档了。
此帖子包含附件:
JPEG 图像
大小:108.5K
----------------------------------------------
-
作者:
男 ljh3146 (ljh) ★☆☆☆☆ -
盒子活跃会员
2018/5/20 20:56:35
10楼: c5soft大侠一直是个热心人。感谢!
----------------------------------------------
-
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2018/5/20 21:08:08
11楼: 这么多人喜欢这个http.sys么。
不如去折腾libuv.
跨平台的库,好像有一个delphi的翻译版
----------------------------------------------
--
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/20 21:37:24
12楼: libuv的是nodejs的底层,异步,事件驱动,用Nodejs就是在用libuv。在Nodejs上目前最棒的框架是KOA。寸有所长,尺有所短。Nodejs强大,仍有不少场合不适合用javascript来写。Web开发可以将nodejs与Delphi结合起来用,各取所长。
----------------------------------------------
-
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2018/5/20 21:58:22
13楼: 没让去用node.js,我是说直接引用libuv库,可以编译成obj直接在delphi里使用。
----------------------------------------------
--
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/20 22:59:45
14楼: 通过编译到exe中使用与通过http协议相互调用,能达到同样的效果。在Nodejs里可以通过Node-fetch调用mORMot,在mORMot里可以通过THttpClientSocket调用Nodejs。要讲效率当然是前者,后者的优势是成熟。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/20 23:04:05
15楼: 希望彻底搞懂WebBroker的朋友可以看看flier (小海 //爱喝可乐^_^)写的刨析文稿。我收录在这里:http://www.cnblogs.com/c5soft/p/webbroker.html
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/20 23:33:28
16楼: datasnap rest的技术也是基于webbroker的。
----------------------------------------------
-
作者:
男 jjwwang (jjwwang) ★☆☆☆☆ -
普通会员
2018/5/20 23:52:44
16楼: 好贴!
----------------------------------------------
学无止境
作者:
男 mprjcf (mprjcf) ★☆☆☆☆ -
普通会员
2018/5/21 9:02:50
17楼: 顶,好东西
----------------------------------------------
他们总是取笑失败者,以酷似智者;他们也总是为成功者喝采,以取得赏金。
作者:
男 tp26021340 (锦) ★☆☆☆☆ -
普通会员
2018/5/21 9:14:42
18楼: 顶一下,好东西
----------------------------------------------
XE7 安卓手机框架、IOS手机框架开发,联系QQ:2403182533
作者:
男 jianlei (剑雷) ★☆☆☆☆ -
盒子活跃会员
2018/5/22 8:27:51
19楼: 感谢大神的分享精神
----------------------------------------------
-
作者:
男 olddelphier (oldDelphier) ▲▲▲▲△ -
普通会员
2018/5/22 8:52:47
20楼: 最近一直在搞webbroker,正好参考下
多谢
----------------------------------------------
-
作者:
男 olddelphier (oldDelphier) ▲▲▲▲△ -
普通会员
2018/5/22 10:23:30
21楼: 这个是cgi的,独立exe 需要替换IdHTTPWebBrokerBridge,还要自己实现

xalion上有定义, 没代码
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 11:26:53
22楼: @olddelphier:不要搞错,不是cgi了,是Bridge,但是我这个实现比xalion那个要简单易懂。无需开启iis,对delphi编译的exe一启动,通过浏览器就能接入。
----------------------------------------------
-
作者:
男 vclclx (vclclx) ★☆☆☆☆ -
普通会员
2018/5/22 12:04:25
23楼: 启动时出现错误:
First chance exception at $73CED722. Exception class EHttpApiServer with message 'HttpSetServiceConfiguration failed: 拒绝访问。 (5)'. Process SynBrokerTest.exe (198108)
是哪里需要设置?
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 12:12:17
24楼: mORMot 请下载1.18版,nightly
----------------------------------------------
-
作者:
男 olddelphier (oldDelphier) ▲▲▲▲△ -
普通会员
2018/5/22 12:43:34
25楼: xe4下了最新的mormot 把几个string改成ansistring 直接就可以跑了
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 13:03:21
26楼: 改string为ansiStrin后D10.2.3就编译不了,最好改成条件编译。
----------------------------------------------
-
作者:
男 olddelphier (oldDelphier) ▲▲▲▲△ -
普通会员
2018/5/22 14:15:46
27楼: 试了下,可以在原来的项目中直接引用 SynWebApp替换IdHTTPWebBrokerBridge就可以过渡

多谢
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 14:30:06
28楼: TWebRequest部分仅实现了GET的部分转换,queryFields还未做,POST的转换还未做ContentFields未做;
TWebResponse部分仅写了Content与ContentType,ConentStream尚未做。

再深度一点,WebModule里面需要实现静态文件服务与Session管理(这两个功能也可以直接放在Process里面),才能把网站架起来。

各位大侠,抽空把这些空缺补上。

随便吐槽:c5soft这么好的方案,怎么就没有掌声呢?难道就真没有几个人懂WebBroker吗?
----------------------------------------------
-
作者:
男 olddelphier (oldDelphier) ▲▲▲▲△ -
普通会员
2018/5/22 14:41:37
29楼: 那些可以参考以前的indy webrequest和webresponse 来完善
----------------------------------------------
-
作者:
男 vclclx (vclclx) ★☆☆☆☆ -
普通会员
2018/5/22 15:24:59
30楼: 我是从synopse.info网站上的下载链接下载的:https://github.com/synopse/mORMot/archive/master.zip

在Win10 X64环境下,必须以管理员身份启动Delphi,才能不出现“拒绝访问”错误。
此帖子包含附件:
JPEG 图像
大小:89.8K
----------------------------------------------
-
作者:
男 vclclx (vclclx) ★☆☆☆☆ -
普通会员
2018/5/22 15:29:10
31楼: 奇怪,现在不用管理员身份也可以了。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 15:41:55
32楼: @vclclx 程序中AddUrl与RemoveURL调用是需要管理员权限,编译后的exe需要以管理员身份运行,或者直接以管理员身份运行delphi编译调式。

或者将dpr改一下,包含mORMot包中的vistaAdm.RES,强制程序以管理员身份运行:

program SynBrokerTest;

{$APPTYPE CONSOLE}

uses

{$R vistaAdm.RES}

{$IFNDEF UNICODE}
  FastMM4,
{$ENDIF}
  WebBroker,
  SynWebApp in 'SynWebApp.pas',
  uWebModule in 'uWebModule.pas' {WebModule1: TWebModule};

{$R *.res}

begin
{$IFDEF UNICDOE}
  ReportMemoryLeaksOnShutDown := True;
{$ENDIF}
  Application.Initialize;
  Application.CreateForm(TWebModule1, WebModule1);
  Application.Run;
end.
----------------------------------------------
-
作者:
男 edwinyeah (Edwin) ★☆☆☆☆ -
盒子活跃会员
2018/5/22 16:07:28
33楼: 虽然我直接就用mORMot,但是仍然支持楼主!
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 16:47:00
34楼: @edwinyeah
我也直接用mORMot写了个WebServer,正7x24小时在业务中跑。Session管理,静态文件下载服务,文件上传服务都跑得很好。数据库我直接用ADOInt中的_Recordset,不用TDataset,直接用微软的东西,Bug更少。Delphi7编译后exe文件大小是855KM,AsPack压缩后326KB。

现在问题来了,客户希望在WebServer中提供SOAP WebService服务,本想自己写一个SOAP接口挂在mORMot上,想了想工作量太大。Delphi里SOAP是现成的,但是走的是WebBroker这条路,这才反过来用mORMot做WebBroker的底层。
此帖子包含附件:
JPEG 图像
大小:185.8K
----------------------------------------------
-
作者:
男 chonghai (DBlue) ★☆☆☆☆ -
盒子活跃会员
2018/5/22 17:06:20
35楼: 好东西。顶c5soft大虾!
----------------------------------------------
喜欢Delphi,关注Delphi,愿和广大爱好者交朋友。
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 17:19:31
36楼: WebBroker设计得稍微复杂,让初学者丈二和尚摸不到头脑,其实就是解决一个路由问题,将URL定位到一段处理程序。用一个数组,两个函数就搞定了。
这是c5soft的非webBroker实现:

type
 TDispatchAction = function(const Env: TWebEnv): Boolean; 
 TRouteMap = record
    MethodAndPathInfo: RawUTF8;
    Action: TDispatchAction;
  end;

var
  RouteMapList: array of TRouteMap;

procedure RouteMap(const Method, PathInfo: RawUTF8;
  const Action: TDispatchAction);
var
  nLen: Integer;
begin
  nLen := Length(RouteMapList);
  Inc(nLen);
  SetLength(RouteMapList, nLen);
  Dec(nLen);
  RouteMapList[nLen].MethodAndPathInfo := UpperCase(Method + ':' + PathInfo);
  RouteMapList[nLen].Action := Action;
end;

function RouteDispatch(const AEnv: TWebEnv; AMethodAndPathInfo: RawUTF8 = ''): Boolean;
var
  i: Integer;
  rm: TRouteMap;
  cScheme: RawUTF8;
  bFound: Boolean;
begin
  Result := False;
  if AMethodAndPathInfo = '' then
    AMethodAndPathInfo := PUTF8Char(AEnv.MethodAndPathInfo);
  for i := Length(RouteMapList) - 1 downto 0 do begin
    rm := RouteMapList[i];
    if AEnv.SSL then
      cScheme := 'HTTPS '
    else
      cScheme := 'HTTP ';
    bFound := IdemPChar(PUTF8Char(cScheme + AMethodAndPathInfo), PAnsiChar(rm.MethodAndPathInfo));
    if not bFound then begin
      bFound := IdemPChar(PUTF8Char(AMethodAndPathInfo), PAnsiChar(rm.MethodAndPathInfo));
    end;
    if bFound then begin
      Result := rm.Action(AEnv);
      break;
    end;
  end;
end;
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 17:38:57
37楼: RouteDispatch函数在Server的Process中调用,实现路由委派,
RouteMap在各个功能模块的initialization里调用,往RouteMapList里注册本模块。

这是Sever的Process:

function TWebServer.Process(AContext: THttpServerRequest): cardinal;
var ...
begin
  try
    ...
    Session := Session.Create(Self, AContext);
    try
        ...
        if RouteDispatch(Session) then begin
          ... 
          Result := 200
        end else begin 
          ... Static File
          end;
        end;
      end;
    finally
      FreeAndNil(Session);
      ...
    end;
  except
    on E: Exception do begin
      ... 
      Result := 500;
    end;
  end
end;

下面是功能模块的写法:

unit uMapPHLogin;

interface

implementation

uses SysUtils, SynCommons, TypInfo, Classes,
  uWebDatabase, uWebServer, uWebSessionPH, uWebUtils;

function RouteMapLogin(const Env: TWebEnv): Boolean;
var
  Session: TWebSessionPayHelper absolute Env;
 ...
  jo: PDocVariantData;
  jv: Variant
begin
  jo := DocVarInit(jv);
  ... 
  Session.OutJSon(jo);
  Result := True;
end;

function RouteMapChangePwd(const Env: TWebEnv): Boolean;
var
  ...
begin
  ...
  Session.OutJSon(jo);
  Result := True;
end;

function RouteMapChangePwdPost(const Env: TWebEnv): Boolean;
var
  ...
  jo: PDocVariantData;
  jv: Variant;

begin
  jo := DocVarInit(jv);
  ...
  Session.OutJSon(jo);
  Result := True;
end;
...
initialization
  RouteMap('HTTPS GET', '/rest/login', RouteMapLogin);
  RouteMap('HTTPS GET', '/rest/refreshOnLine', RouteMapRefreshOnLine);
  RouteMap('HTTPS GET', '/rest/TChangePwd', RouteMapChangePwd);
  RouteMap('HTTPS POST', '/rest/TChangePwd', RouteMapChangePwdPost);
  RouteMap('HTTPS GET', '/rest/TAbout', RouteMapAbout);
  RouteMap('HTTPS GET', '/rest/TBye.html', RouteMapBye);

end.
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 19:37:26
38楼: SynBroker 0.0.0.2 版

增加WBString类型及与RawUTF8的转换
让程序在Delphi 7/XE/10.2.3下能够同时编译,项目文件:
Delphi 7: synBrokerTest
Delphi XE: synBrokerTestD15
Delphi 10.2.3: synBrokerTestD25,支持Win64 


//CompilerVersion<Delphi2009 or CompilerVersion>Delphi 10 Seattle
type
{$IF (CompilerVersion<20.0) OR (CompilerVersion>=30.0) }
  WBString = string;
{$ELSE}
  WBString = AnsiString;
{$IFEND}

function UTF8ToWBString(const AVal: RawUTF8): WBString;
function WBStringToUTF8(const AVal: WBString): RawUTF8;
此帖子包含附件:c5soft_2018522193726.rar 大小:28.6K
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/22 20:01:04
39楼: 恕我愚钝,大神可否让delphi 10.2.3中的datasnap用上http.sys呢?我真正不会干这个活,把morMot中的httpserver抠出来,嫁接到datasnap上。我想这样,让datasnap 弃用indy,让http.sys做底层,一定会让datasnap性能提高很多。
----------------------------------------------
-
作者:
男 snakegao (snakegao) ★☆☆☆☆ -
盒子活跃会员
2018/5/22 20:08:01
39楼: 为c5soft点赞!学习中....
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 21:25:09
40楼: @sxqwhxq

将DataSnap的底层换成mORMot的http.sys关键步骤,以D10.2.3为例:

第一步:选WebBroker服务器类型
此帖子包含附件:
JPEG 图像
大小:73.9K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 21:26:59
41楼: 第二步:选Console App类型
此帖子包含附件:
JPEG 图像
大小:56.5K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 21:29:01
42楼: 第三步:选择Http通讯协议
此帖子包含附件:
JPEG 图像
大小:94.4K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 21:35:12
43楼: 第四步:修改dpr文件,uses里面用SynWebApp替换IdHTTPWebBrokerBridge,后续执行代码全部清除,写成下面这个样子,应该就能编译了。


program Project2;
{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.Types,
  IPPeerServer,
  IPPeerAPI,

  //IdHTTPWebBrokerBridge,
  SynWebApp,

  Web.WebReq,
  Web.WebBroker,
  Datasnap.DSSession,
  ServerMethodsUnit1 in 'ServerMethodsUnit1.pas',
  WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule},
  ServerConst1 in 'ServerConst1.pas';

{$R *.res}


begin
{$IFDEF UNICDOE}
  ReportMemoryLeaksOnShutDown := True;
{$ENDIF}
  Application.Initialize;
  Application.WebModuleClass:=WebModuleClass;
  Application.Run;
end.

其中的关键是:  Application.WebModuleClass:=WebModuleClass;
当然,要让程序跑起来,需要全功能的SynWebApp.pas,目前这个模块还没写完。
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/22 21:51:49
43楼: 把工程中的所有有IdHTTPWebBrokerBridge单元都换为SynWebApp?
这个怎么办呢?
unit FormUnit1;

interface

uses
  Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.AppEvnts, Vcl.StdCtrls, IdHTTPWebBrokerBridge, Web.HTTPApp;
还有,这个全局变量:
procedure TForm1.FormCreate(Sender: TObject);
begin
  FServer := TIdHTTPWebBrokerBridge.Create(Self);//这个全局变量怎么办?
end;
----------------------------------------------
-
作者:
男 inbreak (入侵) ★☆☆☆☆ -
盒子活跃会员
2018/5/22 22:18:41
44楼: 这个技术贴,支持呀,
----------------------------------------------
我是菜鸟,己经搞了十多年了,但是我仍然很菜。
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 22:27:50
45楼: @sxqwhxq
出现这种情况是建立工程的时候选择了GUI,没选Console,把程序文件备份出来,重建一下工程,引用以前的源代码就可以了。

作为服务器程序,选择GUI是浪费资源。
此帖子包含附件:
JPEG 图像
大小:73.9K
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/22 22:36:41
46楼: 是。我再碰碰运气。看能否把datasnap这头老牛重新吃上嫩草。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 22:42:13
47楼: 前面第四步,修改dpr的忘了处理TDSSessionManager了,修改后代码应该是这个样子:
program Project2;
{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.Types,
  IPPeerServer,
  IPPeerAPI,

  //IdHTTPWebBrokerBridge,
  SynWebApp,

  Web.WebReq,
  Web.WebBroker,
  Datasnap.DSSession,
  ServerMethodsUnit1 in 'ServerMethodsUnit1.pas',
  WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule},
  ServerConst1 in 'ServerConst1.pas';

{$R *.res}


begin
{$IFDEF UNICDOE}
  ReportMemoryLeaksOnShutDown := True;
{$ENDIF}
  Application.Initialize;
  Application.WebModuleClass:=WebModuleClass;
  Application.Run;
  if TDSSessionManager.Instance <> nil then
    TDSSessionManager.Instance.TerminateAllSessions;
 
end.
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 23:14:05
48楼: 还有一个简单办法,就是仿照TIdHTTPWebBrokerBridge写一个TSynHTTPWebBrokerBridge,单元名称就叫SynHTTPWebBrokerBridge.pas,这样一个结构:

TSynWebReqest = class(TWebRequest)
...
TSynWebResponse = class(TWebResponse)
...
TSynWebServer=Class(TComponent)
protected
  fHttpServer:THttpApiServer;
  function Process(AContext: THttpServerRequest): cardinal;
public
  ...
end;

implementation

var 
  SynWebRequestHandler: TRequestHandler = nil;

...
TSynWebServer.Process(AContext: THttpServerRequest): cardinal;
var
  HTTPRequest: TSynWebReqest;
  HTTPResponse: TSynWebResponse;
begin
  Result := 200;
  try
    HTTPRequest := TSynWebReqest.Create(AContext);
    try
      HTTPResponse := TSynWebResponse.Create(HTTPRequest);
      HTTPResponse.StatusCode := 200;
      try
        SynWebRequestHandler.HandleRequest(HTTPRequest, HTTPResponse);
        Result := HTTPResponse.StatusCode;
      finally
        HTTPResponse.Free;
      end;
    finally
      HTTPRequest.Free;
    end;
  except
    //HandleServerException(ExceptObject, Output);
  end;
end;   
end;

function createSynWebRequestHandler:TRequestHandler;
begin
   if SynWebRequestHandler=nil then
      SynWebRequestHandler:=TRequestHandler.create;  
   return SynWebRequestHandler; 
end;

initialization
WebReq.WebRequestHandlerProc := createSynWebRequestHandler;

finalization
  FreeAndNil(SynWebRequestHandler);

如此而已。可以将TSynWebReqest /TSynWebResponse实现与前面SynWebApp.pas中的实现合并成一个单元。叫SynReqRes.pas吧。
----------------------------------------------
-
作者:
男 starrysea (星海) ▲▲▲▲▲ -
普通会员
2018/5/22 23:20:19
48楼: 支持一把, 有点意思
----------------------------------------------
挂机赚钱 https://www.yiluzhuanqian.com/P3VpZD0zNjY0MA%3D%3D
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/22 23:34:48
49楼: WebBroker换底层,实现路由的关键在于从mORMot的Process中调用:
  HandleRequest(HTTPRequest, HTTPResponse);


在synWebApp.pas单元中TSynWebApplication->TWebApplication->TWebRequestHandler,
Application是TWebRequestHandler的实例,调用自身的HandleRequest就可以了。

在SynHTTPWebBrokerBridge.pas单元,需要事先初始一个TWebRequestHandler,在Process中调用:SynWebRequestHandler.HandleRequest(HTTPRequest, HTTPResponse);
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/23 7:41:02
50楼: SynWebApp里面还有很多函数没有完成。另外,您这种技术可用于datasnap rest吗?
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/23 8:14:42
51楼: 应该是可以的,路由解析都是WebBroker这个套路。不过Rest Server直接用mORMot作者a.b.的那一套也是可行的。

我这里给大家捋捋思路,希望起到一个抛砖引玉的作用,欢迎各位贡献源代码,也欢迎大咖们拍砖。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/23 14:35:21
52楼: 放一个压力测试结果,10000次并发,SQL Server数据库,64位编译。微软的排队机制就是牛,用ab做压力测试的时候还不影响正常业务。
此帖子包含附件:
JPEG 图像
大小:332.1K
----------------------------------------------
-
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2018/5/23 14:48:22
53楼: 如果能找 500 个实体 计算机。
每一个计算机 开 2 个线程。
每个线程 死循环 执行 查询 操作 。
应该算是  1000 个并发了吧。
或者 找 1000 个计算机。
每一个计算机开一个线程。
或者 10 个计算机。
每个计算机 10 个CPU 核心。
每一个核心开 一个 线程。

那么 这样做 和 一个 4核心 CPU 的计算机,开 1000 个线程,有什么区别。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 ilikejava (灿尔哈察苏) ▲▲▲△△ -
普通会员
2018/5/23 14:52:13
54楼: @c5soft
您好,我按照您的方法已经编译通过了,但是我修改了您的SynWebApp.pas内的端口“8080”为“80”之后访问提示
Internal Application Error
Abstract Error
特向您请教一下是什么原因?
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/23 15:50:57
55楼: @ilikejava: 可能是80端口已经被占用了,试一下别的端口。
@wang_80919:并发,concurrecy,强调的是服务器端同一ip地址同一端口收到的同时访问个数,与客户端无关。压力测试时通过专门的软件多线程同时发出http请求模拟网络环境。比较好的工具是随Apache httpd同时发行的工具ab.exe。
这是apache httpd 2.4.33附带的最新版本 的ab.exe和一个以前收集的使用说明:
此帖子包含附件:c5soft_2018523155213.rar 大小:41.6K
----------------------------------------------
-
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2018/5/23 16:09:30
56楼: 你用 1 台 计算机 模拟 1000 台出来的效果和 100 台模拟出来 1000 台的效果,我个人认为是有差别的。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/23 16:32:40
56楼: 看过本站sxqwhxq (步惊云)发的DataSnap压力测试的一个帖子:
http://bbs.2ccc.com/topic.asp?topicid=547409
给人的印象是Delphi做Web服务,并发效果很不理想。
其实效果的好坏取决与两个因素:其一:http底层用哪个,其二:32位编译还是64位编译。
我估计sxqwhxq测试中http底层一定是用的indy控件,并且是32位编译。
http底层用哪家决定了处理并发的机制,是普通多线程还是iocp,另外一个就是稳定性即Bug多少。indy成功的案例还是比较少,不如用WinInet。
因为Delphi开发的并发处理本质上还是离不开多线程机制,每个线程占用一定内存资源,32位编译要实现万次并发绝对没戏,用mORMot技术在Delphi7/XE下编译照样没戏,一会儿就out of memory了,最后发布的时候一定要64位编译。

总结:用上mORMot的http.sys引擎,通过64位编译,终于让Delphi摆脱不能做企业网站的坏名声。咱们用Delphi做的东西终于可以与php/timcat/nodejs一争高下,做出7x24永远不宕机的产品。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/23 18:07:06
57楼: 上面那个压力测试是本机对本机访问,相当于对127.0.0.1测试的结果,仅能说明软件的稳定性。下面这个测试结果是本机对他机测试,其速度才有参考价值。

发出50万条请求,每次并发1万条,从服务器上打开数据库,返回查询结果。花了2.8小时完成了测试。

测试充当服务器机器的机器是一台联想的台式机,64G内存,i7-6700四核处理器,三星960 PRO固态硬盘,Win10企业版。用D10.2.3编译,底层mORMot,上层用的是我自己的Web框架,未用WebBroker。

测试结果看来相当完美,仅有1个Length错误,就是收到内容实际长度与http头中Content-Length的值不一样,这应该是网络坏境的原因。

为了观察压力测试对实际业务的影响,我特意通过防火墙将生产坏境的服务器访问重定向到这台测试机了,结果没有接到任何客户的不良反馈,通过Chrome中的调试工具监控,仅仅响应时间比为开压力测试前变慢了一些,从100ms以下到200-300ms,在客户的可容忍范围。说明http.sys的排队机制相当完美。
此帖子包含附件:
JPEG 图像
大小:373.4K
----------------------------------------------
-
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2018/5/23 18:16:02
58楼: 在任天堂的游戏机上到处都是 INDY 的成功案例。否则游戏就别玩了。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/23 18:53:11
59楼: c5soft大神:您用ab的测试似乎是固定结果的静态网页,能否用带数据库查询的动态网页呢?动态网页用ab测试有很高的错误率,建议用jmter测试。
上次高同学给我一个测试用中间件,好像是结合了kbmMw和morMot的(底层是基于indy还是http.sys也搞不清)的,用jmter测试,性能大约是datasnap rest的50倍,稳定性更是datasnap不能匹敌的,令人佩服的是,在5000个并发,没有一个错误,而datasnap 基本有30%的错误。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/23 19:37:26
60楼: 我贴出来的测试是访问数据库,根据id返回一个加密的xml,可以看成是一个静态页面,用于测试系统的承接能力与数据库性能。
上面的测试数据库连接池未打开,还是那50万个连接,正在测试打开连接池的结果。
还用AB, 回头我在服务器端写一个专门用于测试用的模块,让访问的表随机,字段数随机,记录数随机,测试一下差错情况。
JM太复杂,懒得摸去。
----------------------------------------------
-
作者:
男 dunken (dunken) ★☆☆☆☆ -
盒子活跃会员
2018/5/23 21:17:15
61楼:
----------------------------------------------
-
作者:
男 ritapl (ritapl) ★☆☆☆☆ -
盒子活跃会员
2018/5/24 10:56:46
62楼: @c5soft 还有一个简单办法,就是仿照TIdHTTPWebBrokerBridge写一个TSynHTTPWebBrokerBridge,单元名称就叫SynHTTPWebBrokerBridge.pas
   这个才是正路吧?
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/24 13:14:37
63楼: 这样做是让原来用Indy通讯控件,并选择GUI服务器界面的改动最小。
无所谓何为正路,何为弯路。
个人认为Server端做成GUI完全没有必要,应该选择Console,或Service用户界面。
----------------------------------------------
-
作者:
男 feiyanm (feiyanm) ▲▲▲▲▲ -
普通会员
2018/5/24 15:58:24
64楼: 支持c5,console好用。
----------------------------------------------
Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!我去WC吐一会儿去!
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/24 16:04:18
64楼: c5soft大帅,我觉得可以做成gui,在现在的服务器,console与gui的性能差异,真有那么大吗?
您的SynWebApp.pas啥时候可以完工呢?我等着它给datasnap rest提质提速呢,您折腾完整后,我愿意付费给您,当然,可能比较微薄。
希望每个使用SynWebApp.pas技术为delphi的三层能够用上http.sys技术的同志都能付费给您。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/24 16:26:45
65楼: @sxqwhxq (步惊云)
有您这句话我就很满意了,说明大家对知识产权还是很尊重。
我撸点代码纯粹是图个乐趣,不为钱。之所以没有把自己的代码开源,是没工夫做后续服务。
大家别催,随时关注这个帖子,我会把SynReqRes.pas,SynWebApp,SynHTTPWebBrokerBridge.pas写完。
我真希望哪位大侠对此有兴趣,替我动手,把代码写完了,分享给大家。
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/24 19:01:54
66楼: 无论morMor还kbmMw,使用难度、学习难度都远高于datasnap,但性能稳定性均高于datasnap。如果能让datasnap 乘上http.sys这趟时尚的快车,那么datasnap可用性将大大增强。您的工作意义非凡。
----------------------------------------------
-
作者:
男 zxh3344 (zxh3344) ★☆☆☆☆ -
普通会员
2018/5/24 19:32:35
67楼: 试过datasnap Rest压测内存会涨不掉了,天天来关注下此贴,哈哈
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/24 19:40:29
67楼: SynBroker 0.0.0.3 版

1.将request/response定义独立出来,放到SynReqRes.pas
2.新增SynHTTPWebBrokerBridge.pas单元,模拟TIdHTTPWebBrokerBridge的功能
3.重构SynWebApp.pas单元

代码在Delphi7,XE,10.2.3(64bit)下编译通过。
此帖子包含附件:c5soft_2018524194028.rar 大小:2.93M
----------------------------------------------
-
作者:
男 hwkjzyh (汉卿) ★☆☆☆☆ -
盒子活跃会员
2018/5/24 19:49:47
68楼: 感谢c5soft (大道至简)大侠无私的奉献,有这样热心的人,是delphi爱好者的福音。
----------------------------------------------
作者:
男 bayman (bayman) ★☆☆☆☆ -
普通会员
2018/5/24 21:03:11
69楼: 请问有办法直接返回stream吗?
如Response.ContentStream := TStringStream.Create('adsfasdfasdfasdfdasf');
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/24 23:45:22
70楼: 等我把SynReqRes.pas写完了,就可以直接返回stream了。

SynBroker 0.0.0.4 版
1.增强SynReqRes.pas实现了Content解析,可以Post了
2.实例代码中增加{$IFDEF MORMOT},方便在mORMot与Indy间切换
3.尚未完全测试,大家帮我找Bug吧
此帖子包含附件:c5soft_2018524234522.rar 大小:216.1K
----------------------------------------------
-
作者:
男 shystep (shys) ★☆☆☆☆ -
普通会员
2018/5/25 15:01:03
71楼: 感谢c5soft (大道至简)大侠无私的奉献!
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/25 15:56:55
72楼: datasnap 推荐服务器与客户端数据交换用json。用流,会有一些错误。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/25 17:53:00
73楼: 发布SynBroker 0.0.0.5 版,基本可用版

1.增强SynReqRes.pas,实现了输出ContentStream。基本功能全有了。
2.增加SoapClient客户端用例。实现了我个人的目的--让mORMot支持SOAP。
3.在Delphi7/XE/10.2.3三个版本下编译测试通过。Delphi7编译32位的客户端程序SoapClient.exe连接D10.2.3编译的64位的服务程序SynBrokerTestXXX.exe正常运行。

SynBroker呱呱落地,该说声谢谢了。SynBroker是大家的成果,我能把代码写出来离不开以下诸位的支持:
1.mORMot作者AB, Arnaud Bouchez,我敬仰的少数几位大师之一。mORMot这个项目充分体现了作者的工匠精神,是作者将现代软件工程最新理论付诸实践的产物。他简单、高效的风格非常契合我大道至简、美是简单的追求。
2.flier (小海 //爱喝可乐^_^),用中文将WebBroker系统架构刨析得最透彻的那位大咖,他还写了Soap分析,这位学者沉睡近20年的文字为我搞懂Web Broker节省大量时间。
3.Delphi窑洞洞主xalion,他那篇博文是这个项目的导火索。老司机们应该记得,当年51delphi为大家带来了多少福利。
4.本站站长及看帖并回复的朋友,是大家的关注点燃了我写代码的热情。
此帖子包含附件:c5soft_201852517530.rar 大小:2.75M
----------------------------------------------
-
作者:
男 zhahongyi (如风) ★☆☆☆☆ -
普通会员
2018/5/25 18:08:14
74楼: 顶楼上,佩服!真正的程序员,不但有高超的技术,认真钻研的韧劲,还有无私奉献的精神!

          谢谢!
----------------------------------------------
-
作者:
男 liminx (liminx) ★☆☆☆☆ -
普通会员
2018/5/25 18:20:04
75楼: 虽然不懂,还是要顶一下。
----------------------------------------------
-
作者:
男 hwkjzyh (汉卿) ★☆☆☆☆ -
盒子活跃会员
2018/5/25 18:59:00
76楼: c5soft (大道至简)给现在正热起来的商业三层架构透明化了,使复杂高深的三层架构让更多人都能用起来。

“咱们用Delphi做的东西终于可以与php/timcat/nodejs一争高下,做出7x24永远不宕机的产品。”
----------------------------------------------
作者:
男 smartdata (Jack) ★☆☆☆☆ -
普通会员
2018/5/25 19:01:56
76楼: 佩服楼主,继续顶!
----------------------------------------------
==========
作者:
男 snakegao (snakegao) ★☆☆☆☆ -
盒子活跃会员
2018/5/25 20:49:07
77楼: 感谢c5soft分享!!!!
----------------------------------------------
-
作者:
男 dunken (dunken) ★☆☆☆☆ -
盒子活跃会员
2018/5/25 21:45:37
78楼:  佩服楼主,继续顶!
----------------------------------------------
-
作者:
男 omvm ( ) ★☆☆☆☆ -
盒子活跃会员
2018/5/25 22:54:11
79楼: 鼓个掌,加下油。
----------------------------------------------
-
作者:
男 delphi_911 (YZY) ★☆☆☆☆ -
普通会员
2018/5/25 23:06:37
80楼: 好像.net调用webservice服务的时候中文乱码,delphi的客户端调用没问题。
估计字符还需要特殊处理
此帖子包含附件:
PNG 图像
大小:21.3K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/26 7:09:32
81楼: Delphi写Soap服务实在是太方便了,傻子都会写。底层换mORMot后性能与稳定性能够提升,完全可以用Delphi来写WebService了。

用http抓包工具比如HTTPAnalyzer分析一下发出与收到的数据情况,看看.net有什么特殊的要求。用.net服务器对.net客户端的数据流做个对比。就不难找到问题所在了。

delphi返回的soap结果中http报文头部Content-Type: text/xml没有charset标注,完整的应该是:Content-Type:text/xml; charset=UTF-8,是不是这里影响到.net客户端的解读?
----------------------------------------------
-
作者:
男 delphi_911 (YZY) ★☆☆☆☆ -
普通会员
2018/5/26 7:37:28
82楼: 很有可能,没仔细分析,测试用datasnap是正常的
----------------------------------------------
-
作者:
男 szlbz (秋风) ★☆☆☆☆ -
盒子活跃会员
2018/5/26 8:50:43
83楼: 感谢c5soft分享!!!!
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/26 11:32:25
84楼: 可用于datasnap rest环境么?
此帖子包含附件:
PNG 图像
大小:59.8K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/26 11:51:07
85楼: 用Delphi10.2.3新建一个DataSnap Rest Server,将TIdHTTPWebBrokerBridge替换为TSynHTTPWebBrokerBridge,注释掉  //FServer.Bindings.Clear;    //FServer.DefaultPort 编译通过。对DataSnap研究不深,等待有经验的老司机来测试。
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/26 13:43:19
86楼: 第一时间测试了下datasnap rest。
将SynHTTPWebBrokerBridge.pas、SynReqRes.pas、SynWebApp.pas拷入工程目录。
用SynHTTPWebBrokerBridge替代工程中所有IdHTTPWebBrokerBridge;
用 FServer := TSynHTTPWebBrokerBridge.Create(Self);替代
   FServer := TIdHTTPWebBrokerBridge.Create(Self);

1、编译时会出现错误:httpsetserviceconfiguration failed:拒绝访问;
2、忽略错误继续,生成的exe比用indy略大,说明http.sys有关代码编译进了工程,但启动exe明显要等待;
3、客户端访问正常,但速度比用indy慢。用jmter 2.11测试,要慢2-3倍。
----------------------------------------------
-
作者:
男 gaoyong_gy (gaoyong_gy) ★☆☆☆☆ -
盒子活跃会员
2018/5/26 13:54:50
87楼:   无论morMor还kbmMw,使用难度、学习难度都远高于datasnap,但性能稳定性均高于datasnap。如果能让datasnap 乘上http.sys这趟时尚的快车,那么datasnap可用性将大大增强。您的工作意义非凡。


你没有好例子,学起来当然觉得难。

亲自体验,kbmmw比datasnap简单易懂。
----------------------------------------------
Delphi 的移动程序开发,是您不可再错失的机遇:http://blog.163.com/you888@188/blog/static/6723961920169319529515/
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/26 15:01:19
88楼: @sxqwhxq (步惊云)
底层用mORMot替换Indy,编译出来的exe应该变小才对,下面截图是我对用例的测试结果。SynBrokerTestGUID25.dproj里面有编译条件定义,进入项目属性,到最顶层All Configuration设置,将Condition Defines由MORMOT改成MORMOTx编译出来的就是Indy版本,再改回MORMOT,编译出来的是mORMot版本。下图是delphi 10.2.3 64位Release编译的大小对比。文件没减小,可查看是否在别处还引用了Indy。编译报错也不应该是mORMot带来,好好查查。正常编译的mORMot程序启动速度应该飞快才对。http.sys注册时需要系统权限,建议将vistaAdm.RES资源文件包含在dpr中。至于说连接速度,indy与http.sys我没有让他们pk过,没有发言权。这与服务器运行环境有关,服务器上是什么操作系统?建议上支持http.sys V2的系统,比如win10。
改一下SynHTTPWebBrokerBridge.pas把httpApiServer的队列设置成10000,用64位编译,测一下高并发,看看会不会出现系统崩溃的情况。

 FHttpServer.OnRequest := Process;
  FHttpServer.HTTPQueueLength := 10000;
  FHttpServer.Clone(256 - 1);

你可劲地X,她再也不喊痛!抗X--这是换底层的根本理由。
此帖子包含附件:
JPEG 图像
大小:154.4K
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/26 18:34:37
89楼: 我吵,性能提升了20倍,但错误达到69%?
在jmter中开1000个线程,select xb,xb,csny,mz,commune from tbworker
1000条记录,5个字段,没有图形字段。
此帖子包含附件:
PNG 图像
大小:105.7K
----------------------------------------------
-
作者:
男 godear (pegae) ★☆☆☆☆ -
盒子活跃会员
2018/5/26 20:39:31
90楼: 感谢c5soft分享!!!
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/26 21:19:02
91楼: 找到绕开WebBroker直接使用编写Soap WebService的方法了。
把Soap核心组件扣出来,对接到我的框架中,路由代码如下:

unit uMapSoap;

interface

implementation

uses HTTPApp, SOAPHTTPPasInv, WebBrokerSOAP, WSDLPub, SynReqRes, uWebServer;

function DoDispatch(const Env: TWebEnv; const ADispatcher: IWebDispatch): Boolean;
var
  Request: TSynWebRequest;
  Response: TSynWebResponse;
begin
  Request := TSynWebRequest.Create(Env.Context);
  try
    Response := TSynWebResponse.Create(Request);
    try
      Result := ADispatcher.DispatchRequest(nil, Request, Response);
    finally
      Response.Free;
    end;
  finally
    Request.Free;
  end;
end;

function RouteMapSoapWSDL(const Env: TWebEnv): Boolean;
var
  WSDLPublisher: TWSDLHTMLPublish;
begin
  WSDLPublisher := TWSDLHTMLPublish.Create(nil);
  try
    Result:=DoDispatch(Env, WSDLPublisher);
  finally
    WSDLPublisher.Free;
  end;
end;

function RouteMapSoapPost(const Env: TWebEnv): Boolean;
var
  SoapDispatcher: THTTPSoapDispatcher;
  PascalInvoker: THTTPSoapPascalInvoker;
begin
  PascalInvoker := THTTPSoapPascalInvoker.Create(nil);
  SoapDispatcher := THTTPSoapDispatcher.Create(nil);
  SoapDispatcher.Dispatcher := PascalInvoker;
  try
    Result:=DoDispatch(Env, SoapDispatcher);
  finally
    SoapDispatcher.Free;
    PascalInvoker.Free;
  end;
end;

initialization
  RouteMap('GET', '/wsdl', RouteMapSoapWSDL);
  RouteMap('POST', '/soap', RouteMapSoapPost);

end.
----------------------------------------------
-
作者:
男 delphi_911 (YZY) ★☆☆☆☆ -
普通会员
2018/5/27 0:35:30
92楼: 这个怎么玩?
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/27 14:41:48
93楼: 1、用ab 测试静态网页(非数据库查询产生的网页),开5000个线程,不挂机;
2、用jmter测试动态网页(从数据库查询产生的网页),开1000个线程,产生大量错误,但不挂机。用indy版本不产生错误;开5000个线程,indy版本挂机,无法测试了,http.sys版本仍然产生大量访问错误,但仍然不挂机。
上面测试,中间件由于使用了较老版本的数据库,因此编译为32位。
看来,用http.sys替代indy,仍须完善。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/27 17:07:12
94楼: 32位编译高并发必挂机,mORMot也没辙。查查出错原因在哪里,才知道在哪里改进。
我抽空做一个动态页面测试用例,看看万次并发的差错情况。
----------------------------------------------
-
作者:
男 bayman (bayman) ★☆☆☆☆ -
普通会员
2018/5/27 17:39:31
95楼: 不是很明白
procedure TSynWebResponse.SendStream(AStream: TStream);
var
  Buffer: SockString;
begin
  SetLength(Buffer, AStream.Size);
  AStream.Read(Buffer[1], AStream.Size);
  Context.OutContent := Buffer;
end;  
这样输出的已经不是stream了吧,看了一下mORMot源码,好像根本没实现ContentStream,也看了一下文档,好像是说用rawutf8效率更高,但总觉得这样来来回回转换效率更低
另外执着于datasnap的理由又是什么呢?用json之类的话直接用mORMot不就好了吗?
俺水平太低没深入研究,请指教
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/27 19:01:56
96楼: @bayman
问题提得很好。
mORMot的确没提供SendStream。也许http.sys API就没有,没深入研究。但是http.sys提供了直接将文件发送给客户端的功能。如果非要做一个地道的SendStream,mORMot提供的方法是将Stream保存为一个临时文件,将文件名直接发给http.sys:
procedure TWebEnv.OutFile(const AFileName: string);
var
  ContentType: RawUTF8;
begin
  Context.OutContent := StringToUTF8(AFileName);
  Context.OutContentType := HTTP_RESP_STATICFILE;
  ContentType := InferContentType(AFileName);
  if Length(ContentType) > 0 then OutHeader(HEADER_CONTENT_TYPE + ContentType);
end;

不过SynBroker里的这个办法也是可行的,SockString=RawByteString= Array of Byte,就是字节流,应该是可以将任何东西发给客户端的,配合OutContentType,客户端就可以解析了。

mORMot自带的Rest框架非常好,完全可以取代DataSnap,这样做只是为了给已有DataSnap的项目输送一点新鲜血液。另外,mORMot不支持Soap WebService,而Delphi的Soap写得非常好,没必要重复发明轮子,这个项目很好的补全这项功能。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/27 21:12:15
97楼: SynBroker暂时收工,版本号定为0.9.0.0。

SynBroker 0.9.0.0 版,基本稳定版,全部源码

让Delphi WebBroker/DataSnap通讯底层用上mORMot提供的http.sys调用,在Windows坏境实现高并发(万次以上)与高稳定(长期不运行不宕机)。
1.项目文件名以SynWeb开头,不是SynWeb开头的文件都不是必须的。一共4个文件,文件之间的引用关系是:SynWebApp->SynWebServer->SynWebReqRes->SynWebEnv。
2.SynHTTPWebBrokerBridge.pas用于替换IdHTTPWebBrokerBridge.pas,让大家少敲打几次键盘,这个文件中实质只有一行TSynHTTPWebBrokerBridge = TSynWebServer。
3.SynBrokerTest.dpr是Console类型服务端用例程序,SynBrokerTestGUI.dpr是GUI类型服务端用例程序。 
4.SoapClient.pas客户端用例程序,用于测试Soap调用。
5.在Delphi7/XE/10.2.3三个版本下编译测试通过。支持Win32位与Win64位编译。


重要的事情要多说几遍,SynBroker能够降生,离不开以下诸位的支持:
1.mORMot作者AB, Arnaud Bouchez,我敬仰的少数几位大师之一。mORMot这个项目充分体现了作者的工匠精神,是作者将现代软件工程最新理论付诸实践的产物。他简单、高效的风格非常契合我大道至简、美是简单的追求。
2.flier (小海 //爱喝可乐^_^),用中文将WebBroker系统架构刨析得最透彻的那位大咖,他还写了Soap分析,这位学者沉睡近20年的文字为我搞懂Web Broker节省大量时间。
3.Delphi窑洞洞主xalion,他那篇博文是这个项目的导火索。老司机们应该记得,当年51delphi为大家带来了多少福利。
4.本站站长及看帖并回复的朋友,是大家的关注点燃了我写代码的热情。
此帖子包含附件:c5soft_2018527211254.rar 大小:1.31M
----------------------------------------------
-
作者:
男 snakegao (snakegao) ★☆☆☆☆ -
盒子活跃会员
2018/5/27 21:57:58
98楼: 再次感谢c5soft的无私奉献!顶上去
----------------------------------------------
-
作者:
男 lsuper (lsuper) ★☆☆☆☆ -
盒子活跃会员
2018/5/27 22:36:43
99楼: 强烈建议 c5soft 把这个发到 github 上去 ?
----------------------------------------------
-
作者:
男 ritapl (ritapl) ★☆☆☆☆ -
盒子活跃会员
2018/5/28 10:18:17
100楼: 强烈建议 c5soft 把这个发到 github 上去!
能把http.sys与webbroker,datasnap完美结合,这本身就是很有意义的一个项目,虽然是洞主最早提出的,但楼主能将之完善,成熟也是功德无量!
----------------------------------------------
-
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2018/5/28 10:33:48
101楼: github sf.net 都可以。
强烈建议 c5soft 把这个发到 github 上去
----------------------------------------------
(C)(P)Flying Wang
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/28 10:47:37
101楼: 可能是因为我水平有限,我按楼主的方法用hppt.sys替代datasnap rest中的indy后,改善不大,作用发挥不明显。
1、楼主将FServer的port、Active设为只读,无法在项目中动态设置,只能在源码中指定端口,如果使用默认端口编译不会出错,如果修改源码指定端口,会出现一个编译错误;
2、用jmter模拟500个线程并发访问数据库查询(1000记录、5个字段)错误率为0,1000个线程错误率30%、3000个线程80%错误率。而使用indy1000个线程没有错误,2000个挂机。仔细比较平均访问时间、吞吐量、每秒传送数据,两者差别不大;用ab 测试没有数据库访问的静态网页,5000个并发,两者差别不大。
3、在win2008R2中,查看datasnap http.sys有内存泄漏,这个datasnap indy也有,但泄漏严重些,不过到达一定值以后不再增加(内存使用量、句柄数)。
从主观使用感觉看,无论从手机app还是win32访问http.sys和indy的datasnap rest做的三层,速度、稳定性没有差别,暂时没有体会到飞起来的感觉。
另外,我始终没有证明,这样的三层是否真的使用了morMot的http.sys。
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/28 17:17:14
102楼: http端口在与可执行文件同名的ini文件中配置:
SynWebServer.pas中有:
  FPort := FIniFile.ReadString('Server', 'Port', '8080');

自己创建一个与exe同名的INI文本文件,如SynBrokerTest.ini,文件中输入:
[Server]
Port=80

即将端口改为80
----------------------------------------------
-
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2018/5/28 17:24:31
103楼: var
  DefPort: Integer = 8080;
FPort := FIniFile.ReadString('Server', 'Port', DefPort);

这样就没问题了。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/28 17:37:28
103楼: 内存泄漏是对于客户端程序而言问题不大,因为运行时间不长,处理完业务就退出了。对于服务端程序,因为要长期运行,这是绝对不能容忍的,可能是致命的。
要想做出7x24小时无故障运行的服务端程序,一定要把内存泄漏彻底消灭。每增加一段代码,就要检查有无内存泄漏,即时解决。

连接mORMot底层,绝对没有内存泄漏的问题!

是不是真的使用了mORMot最简单的方法就是检查生成的exe大小,把indy替换为mORMot后,exe一定变小了才对。


http.sys的性能在Windows各个版本会有差别,尽量使用最新版本的操作系统。
----------------------------------------------
-
作者:
男 delphi_911 (YZY) ★☆☆☆☆ -
普通会员
2018/5/28 19:49:41
104楼: 后面这个版本加了content type,但是.net调用还是乱码
----------------------------------------------
-
作者:
男 dunken (dunken) ★☆☆☆☆ -
盒子活跃会员
2018/5/28 21:26:41
105楼: 感谢c5soft的无私奉献!顶
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/28 23:11:54
106楼: @delphi_911
要让DotNet能够享用Delphi写的Soap服务,改一下PascalInvoker.Converter的属性,如果还不行只有自己写一个TOPToSoapDomConvert了:

 TDotNetOPToSoapDomConvert = class(TOPToSoapDomConvert)
 ...
 end
此帖子包含附件:
JPEG 图像
大小:141.3K
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/29 8:30:25
107楼: C5SOFT:我编译的http.sys版本比indy版本始终大20K,看来没有用上http.sys。但我把工程中所有使用indy的地方都换了http.sys。
----------------------------------------------
-
作者:
男 nickemma (N.E Zhou) ★☆☆☆☆ -
普通会员
2018/5/29 9:03:05
108楼: 可以参考洞主原文上面,用web测试工具看看是否真的使用了http.sys

按此在新窗口浏览图片
----------------------------------------------
-
作者:
男 delphi_911 (YZY) ★☆☆☆☆ -
普通会员
2018/5/29 10:47:29
109楼: @c5soft (大道至简)
谢谢指导,解决.net调用乱码的问题,不过我调整了一下这里编译选项,不然XE7编译不对。

//{$IF (CompilerVersion<20.0) OR (CompilerVersion>30.0) }
{$IF CompilerVersion >= 18.5}

function UTF8ToWBString(const AVal: RawUTF8): WBString;
begin
  Result := UTF8ToString(AVal);
end;

function WBStringToUTF8(const AVal: WBString): RawUTF8;
begin
  Result := StringToUTF8(AVal);
end;
{$ELSE}

function UTF8ToWBString(const AVal: RawUTF8): WBString;
begin
  Result := CurrentAnsiConvert.UTF8ToAnsi(AVal);
end;

function WBStringToUTF8(const AVal: WBString): RawUTF8;
begin
  Result := CurrentAnsiConvert.AnsiToUTF8(AVal);
end;
{$IFEND}
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/29 10:51:11
109楼: 上面发过64位编译的文件大小对比,再发一个32位编译的文件大小对比,Release编译, 连接mORMot比连接Indy生成exe文件小了将近400K。
此帖子包含附件:
JPEG 图像
大小:33.0K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/29 11:01:37
110楼: 再做一个极端试验
用上面两个32位编译的exe本机对本机做压力测试,排除网络连接速度的影响,1000个并发,做50000次测试:
ab -n 50000  -c 1000 http://127.0.0.1:8080/
结果mORMot比indy快100倍。这是极端情况,静态文件,不连数据库,实际项目中不可能差这样多。较慢的网络速度与数据库速度把总体速度拉下来了。
此帖子包含附件:
JPEG 图像
大小:672.2K
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/29 11:18:48
111楼: 我有一个投入运营的生产项目,经历了从IntrawWeb换成Nodejs, 又从nodejs换成WebBroker ISAPI(http.sys),再由WebBroker ISAPI(http.sys)换成mORMot(http.sys)的过程。因为IntraWeb用的是Indy,相当于是从Indy换成了mORMot。从indy换成http.sys,系统的运行速度、稳定性与用户体验的改善是非常显著的。

由WebBroker ISAPI(http.sys)换成mORMot(http.sys),主要是让软件调试、发布及后期维护变得容易多了,再也不用去折腾IIS了。速度没有什么变化。
----------------------------------------------
-
作者:
男 qgc998 (区区) ▲▲▲▲▲ -
普通会员
2018/5/29 12:30:42
112楼: c5soft大神,新手想问一下:这个能用于C/S吗?
----------------------------------------------
-
作者:
男 c5soft (大道至简) ▲▲▲▲▲ -
普通会员
2018/5/29 13:05:22
113楼: DataSnap不就是C/S吗?不用Delphi的,用mORMot自带的Rest也行。
----------------------------------------------
-
作者:
男 yaoyl (云里雾里) ★☆☆☆☆ -
盒子活跃会员
2018/5/29 21:51:00
114楼: 感谢c5soft的无私奉献!
----------------------------------------------
Delphi老菜鸟~
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/29 22:36:18
115楼: 希望C5Soft大帅能够仔细分析一下在datasnap 和datasnap Rest中的应用,因为datasnap是emb力推的多层工具,用http.sys改进这并不要您深究datasnap工作机制,因为您对webbroke技术很了解,很容易就能做到,希望您重视一下这个很有意义的工作。我确实完全是按您的步骤做的,您介绍是步骤并不复杂,用您的单元替代原来的indy单元而已,但确定没效果,而且稳定性大幅降低。
另外,我的morMot版本是1.18。
----------------------------------------------
-
作者:
男 crystalmoon (crystalmoon) ★☆☆☆☆ -
盒子活跃会员
2018/5/30 8:40:38
116楼: @sxqwhxq
因为没有你具体的出错信息。我猜你的报错很大的可能性瓶颈不在http.sys,而在数据库查询上。用上了http.sys,还是要继续优化其他配套部分的。
----------------------------------------------
-
作者:
男 zxh3344 (zxh3344) ★☆☆☆☆ -
普通会员
2018/5/30 9:30:51
117楼: sxqwhxq 为什么不提供一下简单的例子让我们大家试试呢?如果单纯用于数据库操作,数据库成为瓶颈,HTTPSys优势不是特别明显,HTTPSys更稳定,电脑的资源利用有区别。再次感谢C5Soft无私奉献!
----------------------------------------------
-
作者:
男 gyh75 (ggg) ★☆☆☆☆ -
盒子活跃会员
2018/5/30 13:15:08
118楼: delphi开发的相关系统,大家可以关注下。
上位机开发之家:http://shangweiji.lofter.com
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2018/5/31 14:52:31
119楼: 目前,mOrMot包装的http.sys技术可以部分用于datasnap REST,从jmter2.11测试的报文已经有morMot公司的信息,反复测试表明性能有40%左右提升,而且内存泄漏比indy版本的datasnap有很大改善。
但只能部分用于datasnap rest,性能改善有限,原因在于rest关键组件TDSHTTPWebDispatche是根植于indy的,这个暂时没法剥离出来。
只能期待窑洞洞主出手了。
----------------------------------------------
-
作者:
男 lanhong (HDA) ★☆☆☆☆ -
普通会员
2018/5/31 21:38:42
120楼: 119楼,你对datasnap这么感冒吗?拿钱去砸窑洞洞主试试先
----------------------------------------------
-
作者:
男 dunken (dunken) ★☆☆☆☆ -
盒子活跃会员
2018/6/1 20:22:03
121楼:
----------------------------------------------
-
作者:
男 yesin119 (yesin119) ★☆☆☆☆ -
盒子活跃会员
2018/6/8 12:41:06
122楼: 大力顶,能看到神一样的C5,真是荣幸!C5在哪个城市呀?
----------------------------------------------
-
作者:
男 vga (vga) ★☆☆☆☆ -
盒子活跃会员
2019/1/2 10:28:37
123楼: 感谢c5soft的无私奉献!好贴不能沉呀!继续顶!!!
----------------------------------------------
-
作者:
男 jczxdai (草籽) ▲▲▲▲△ -
普通会员
2019/1/16 21:58:49
124楼: 2.发送自定义头如果Name相同,使用Response.SetCustomHeader(name,value),发送到浏览器的时候只有最后一个
  ·比如:Response.SetCustomHeader('test','test1');
   Response.SetCustomHeader('test','test2');
   Response.SetCustomHeader('test','test3');
   那么发送到浏览器的时候只有test:test3
  ·如果使用Response.CustomHeaders.Add(str)->Response.CustomHeaders.Add(Name+'='+Value)则没有问题

3.响应多个Cookie只会发送最后一个set-cookie例如:
    with Response.Cookies.Add do
    begin
      name:='cookie1';
      value:='cookie1';
    end
    with Response.Cookies.Add do
    begin
      name:='cookie2';
      value:='cookie2';
    end
    with Response.Cookies.Add do
    begin
      name:='cookie3';
      value:='cookie3';
    end
    只会发送Set-Cookie:cookie3=cookie3
  解决办法如下
  mORMot的SynCrtSock单元HTTP_RESPONSE.AddCustomHeader(P: PAnsiChar; var UnknownHeaders: HTTP_UNKNOWN_HEADERs; ForceCustomHeader: boolean): PAnsiChar;
  把    const KNOWNHEADERS: array[reqCacheControl..respWwwAuthenticate] of PAnsiChar = (
        'CACHE-CONTROL:','CONNECTION:','DATE:','KEEP-ALIVE:','PRAGMA:','TRAILER:',
        'TRANSFER-ENCODING:','UPGRADE:','VIA:','WARNING:','ALLOW:','CONTENT-LENGTH:',
        'CONTENT-TYPE:','CONTENT-ENCODING:','CONTENT-LANGUAGE:','CONTENT-LOCATION:',
        'CONTENT-MD5:','CONTENT-RANGE:','EXPIRES:','LAST-MODIFIED:',
        'ACCEPT-RANGES:','AGE:','ETAG:','LOCATION:','PROXY-AUTHENTICATE:',
        'RETRY-AFTER:','SERVER:','SET-COOKIE:','VARY:','WWW-AUTHENTICATE:');
  'SET-COOKIE:'改为''即可解决问题

4.SynWebReqRes单元OutCookiesAndCustomHeaders函数,//HeaderValue方法取得string是 经过URLEnCode的 空格会被转义为+
  Env.OutHeader(StringToUTF8('Set-Cookie: ' + GetHeaderValue(Cookies[i])));
  修改为
  Env.OutHeader(StringToUTF8('Set-Cookie: ' + URLDecode(Cookies[i].HeaderValue)));
----------------------------------------------
草籽天涯
作者:
男 jljaaj (小强) ▲▲▲△△ -
普通会员
2019/1/17 10:17:31
125楼: 请高手看下,D10.2.1这里编译不通过是怎么个问题??morMor下的是最新的。
此帖子包含附件:
JPEG 图像
大小:10.7K
----------------------------------------------
-
作者:
男 denkun (dk) ★☆☆☆☆ -
普通会员
2019/1/24 8:30:27
126楼: 赞一个
----------------------------------------------
-
作者:
男 jandjo (jandjo) ★☆☆☆☆ -
普通会员
2019/8/21 18:16:50
127楼: 我用带ssl的https总是失败
----------------------------------------------
-
作者:
男 vga (vga) ★☆☆☆☆ -
盒子活跃会员
2019/12/19 10:20:22
128楼: 好帖莫沉呀!!!
----------------------------------------------
-
作者:
男 ww66 (wzs) ★☆☆☆☆ -
普通会员
2019/12/19 21:05:35
129楼: 好,多谢
----------------------------------------------
http://www.inteLw.cn:8077
作者:
男 sumig (sumig) ★☆☆☆☆ -
盒子活跃会员
2020/1/9 8:28:43
130楼: 雖然看得不是很懂,還是多謝樓主無私的奉獻!
----------------------------------------------
-
作者:
男 aloneforu (aloneforu) ★☆☆☆☆ -
盒子活跃会员
2020/1/9 17:05:30
131楼: mark 学习一下
----------------------------------------------
浪迹软件开源WKE4DELPHI
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2020/1/9 21:53:59
132楼: WebBroker 是好东西,掌握了 WebBroker 就掌握了 http 的工作原理。
----------------------------------------------
-
作者:
男 joman (joman) ▲▲▲▲▲ -
普通会员
2020/1/20 10:05:50
133楼: 楼主的东西确实是好东西,有了楼主的东西才让delphi 开发web 成为可能。
是否使用了mormot 可以这样查看
浏览器访问接口F12 查看

按此在新窗口浏览图片
----------------------------------------------
DelphiWeb开发方案(开源):https://gitee.com/pearroom/DelphiWebMVC
作者:
男 baifafa (白花花) ★☆☆☆☆ -
盒子活跃会员
2021/1/14 17:10:57
134楼: 楼主大神的这个是个好器,难搞啊。

怎么Post不能取到值,奇怪了

procedure TWebModule1.WebModule1WebActionItemPostAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
    cName, cPhone: string;
begin
  cName := Request.QueryFields.Values['name']; //--这里取不到值
  cPhone := Request.QueryFields.Values['phone'];

{$IFDEF MORMOT}
  Response.ContentType := 'text/html; charset=utf8'; // 让汉字正确显示
{$ENDIF}
  Response.Content := cstHTMLBegin + RequestInfo(Request) + '<p>Name:' + cName +'</p>' +
    '<p>Phone:' +  cPhone +'</p>' +
    '<a href="/?' + Request.Content + '">返回</a>' +
    cstHTMLEnd;
end;

---另外让汉字正常,可以在定义
cstHTMLBegin = '<HTML><meta charset="utf-8"><BODY>'上加上utf-8,这样就不会乱码
----------------------------------------------
没有比没有更没有
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2021/1/14 17:14:00
135楼: WebBroker 是个好东西
----------------------------------------------
-
作者:
男 baifafa (白花花) ★☆☆☆☆ -
盒子活跃会员
2021/1/18 15:08:03
136楼: 没看到http://bbs.2ccc.com/topic.asp?topicid=548726 ;

post取值要用
cName := Request.ContentFields.Values['Name'];
cPhone := Request.ContentFields.Values['Phone'];
----------------------------------------------
没有比没有更没有
作者:
男 madwolf (林之白狼) ★☆☆☆☆ -
普通会员
2022/1/23 11:01:00
138楼: 这两天在看delphiwebmvc,看到底层用的c5soft大仙的通讯,
请问c5soft (大道至简)大仙能否传下最新版的synbroker?
感谢
----------------------------------------------
delphi加油!!
作者:
男 denkun (dk) ★☆☆☆☆ -
普通会员
2023/7/5 22:42:00
139楼: 感谢c5soft的无私奉献!好贴不能沉呀!继续顶!!!
mORMot2 下可以用吧?
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2023/7/6 8:06:46
140楼: 用rtc吧,开源、跨平台,稳定高并发。
----------------------------------------------
-
作者:
男 denkun (dk) ★☆☆☆☆ -
普通会员
2023/7/7 14:52:59
141楼: sxqwhxq (步惊云) rtc 比 mOrMot 更好?
----------------------------------------------
-
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2023/7/8 9:47:52
142楼: 我对mORMot没兴趣,没做过对比。我对 rtc有个粗浅的应用,感觉真的很不错。
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行390.625毫秒 RSS