导航:
论坛 -> DELPHI技术
斑竹:liumazi,sephil
作者:
2016/10/18 8:49:23
标题:
一个用Pascal写的HTTP框架
浏览:2935
加入我的收藏
楼主:
https://www.habarisoft.com/daraja_framework.html 看介绍很不错,有空测试看看。 有兴趣的朋友也可以关注下。
----------------------------------------------
喜欢Delphi,关注Delphi,愿和广大爱好者交朋友。
作者:
akay (akay)
★☆☆☆☆
-
普通会员
2016/10/18 9:26:30
1楼:
基于indy的,但indy本身就问题多多。 里面贴出来的,用vs来写pascal
----------------------------------------------
-
作者:
2016/10/18 11:19:37
2楼:
对的基于indy,是收费的
----------------------------------------------
-
作者:
2016/10/18 14:18:03
3楼:
vs?
----------------------------------------------
学DELPHI http://www.studydelphi.com
作者:
2016/10/18 16:13:43
4楼:
indy不要紧的。unigui也是基于Indy,没有任何问题
----------------------------------------------
只有偏执狂才能生存!
作者:
2016/10/18 16:58:36
5楼:
真正的WEB服务器是不会用Indy写的。因为它是基于每连接每线程的。 其实真正的服务器需要下很多功夫,无法快速开发的。 比如说,字符串处理。玩服务器基本上就是玩内存。举个例子: var str:AnsiString; begin str:='HTTP 1.1/200 OK'#$D#$A; str:=str+xxxxxxx; str:=str+yyyyyyy; ...... end; 编译器实际上上怎么做的?第一行代码:先根据字符长度,为str分配17字节空间(这里不讨论头部计数器和锁占用的空间)。第二行代码,假设xxxxxx的长度为3,那么再申请一个20字节的空间,将原来17字节的内容拷贝过去,再在后面接上3个字节的内容,然后释放原来的17个字节。第三行同理。内存会变成怎么样? [ 17个字节的空洞][ 20字节的新内容].......... 这个时候,如果你需要分配一个18字节的内存,只能从[ 20字节的新内容]后面申请,因为内存块必须是连续的。换句话说,前面那个17字节的内存就废了。除非分配的是小于等于17字节的。 随着运行的时间越来越长,类似的空洞会越来越多。最后,如果你是32位应用程序,那么有可能面临很多错误(比如说:GetMem失败,对象创建失败)。 MFC的CString实质上原理类似。 服务器开发跟桌面应用是两码事,因为桌面应用程序,从你启动到结束,一般就运行几个小时,但服务器是24小时*365运行的,需要注意的事情海了去。很多时候,一些好像不要紧的细节,累加起来,就有质的区别。 服务器开发,不是有一个不错的网络库就OK的。网络仅是负责数据的收发,你如何快速处理收到的数据呢(比如说,使用传统锁来生产者消费者队列,或者双队列,或者原子队列,或者真正逻辑上完全无锁队列)?如果避免更多的内核和应用层切换?启动多少个线程刚好合适?选用什么加密算法?等等等等。不要小看效率,假如你的服务器长连接峰值是10万,一个加密算法提示了10毫秒,10毫秒乘以10万就是16分钟,8核服务器在理想状态下,最后那个登录的可怜虫也要多等待2分钟。仅仅追求连接数是毫无意义的,如果你的机器性能够强大,如果你使用完成端口,如果客户端仅是连接而不用做其它事情,一个最蹩脚的程序员写的也能同时支持百万级别的连接。但这个是操作系统的功劳,跟你的程序关系不大。仅连接不做事情的程序也没什么用处。 当然,桌面程序开发人员是不用关心这些的。如果仅是开发http server,我强烈建议直接调用操作系统的http.sys,这个也是IIS的本质。除了避免内核和应用层的切换,还可以避免很多问题。你自己实现一个其实是不可能比这个更好---你用的操作系统都是人家的,你会比他更了解系统么?
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
2016/10/18 17:59:03
6楼:
非常同意楼上的,我也是基于http.sys来开发的,真的是非常稳定。
----------------------------------------------
QQ: 9717005 我的Blog:http://www.cnblogs.com/anydelphi/
作者:
2016/10/18 22:15:29
7楼:
Delphi已经集成了FastMM,这个内存管理器对大中小块内存做了分别的优化。 例如小块内存,不是17,18字节这样的。而是xxK对齐(例如4K,不一定是)。 中块xxK字节对齐,大块xxK对齐。 这样,内存回收后小块的还可以给以后的小块重用。 尽量避免出现内存碎片导致不连续和浪费。 不过一切通用的算法和代码都不如专用的效率高,如果这样想把某种业务做到及至,那么需要针对这种业务做专用的处理。 HTTP.SYS避免了频繁的一次次的内核和应用层间的切换和数据传输,效率是非常高的。 另外Windows的IOCP模型比Linux的epoll效率还是要高很多的。 所以如果在Windows平台上基本没有什么Web服务器效率和通用性能高过IIS了。
----------------------------------------------
武稀松http://www.raysoftware.cn
作者:
2016/10/18 23:31:01
8楼:
FastMM是Delphi7后才集成的,Delphi7及之前的版本并不自带。另外,它的内存释放有时候有些问题,就是会发生释放并不成功的情况。老外有个修改版本丢在git上面。但是内存问题,除了碎片,还有很多其它讲究的地方,都是开发服务器需要注意的。 IOCP才是真正的异步模型,真正的异步。epoll并不是。我以前在Windows下实现过epoll模型,无非是使用纤程之类来实现完全的自己调度。如果一定要比较,Windows的IOCP模型的确是要比Linux的epoll效率高很多。 HTTP.SYS除了避免切换,也涉及到内存问题---驱动里面关键代码都是使用物理内存的,避免了内存不足虚拟内存跟磁盘IO之间的切换。这个切换在严重的情况下是卡电脑的。
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
2016/10/18 23:37:28
9楼:
另外,其实很多年前老外放在torry.net上面的一个基于IOCP的http模型都比indy的强大,里面也使用了很多lock free的技巧。当然,lock free其实只是原子锁,并非真正的无锁。真正的无锁比原子的效率至少高7倍以上。 类似wr960204说的,如果一个东西要做到极致,基本上不存在通用的可能。但极致本身是值得追求的,一些技巧也是可以通用的。比如说:相同一个函数,不同的写法,查看CPU反汇编,生成的代码行(你可以通俗看成是执行所需要花的CPU时间片)也是不一样。又比如说:如何合理利用CPU的cache提高效率(一个简单的例子是TRTLCriticalSection类型后面多定义一个padding数组)。等等等等。
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
2016/10/19 0:55:29
8楼:
使用场景不一样,如果在不需要那么高效的情况下或者是单机使用还是可以一试的。
----------------------------------------------
喜欢Delphi,关注Delphi,愿和广大爱好者交朋友。
作者:
2016/10/19 11:46:20
10楼:
过去看了一下 不想下载这东西...
----------------------------------------------
哦哟喂,看过来: http://zelig.cn
作者:
drroc (mvcxe)
★☆☆☆☆
-
盒子活跃会员
2016/10/19 15:05:21
11楼:
还好啊,开源的,为什么喷人家呢
----------------------------------------------
MVCXE中国首个DELPHI MVC WEB框架:https://www.mvcxe.com/
作者:
2016/10/19 20:42:11
12楼:
这不如去扩展nginx。。。
----------------------------------------------
--
作者:
2016/10/21 12:24:32
13楼:
我是针对5楼说的。 技术人员要避免完美主义。所谓大牛写的超棒服务器程序,或许一个普通的方案再加多1、2台服务器备用就解决了。什么真正服务器就不能用Indy,什么事情都要考虑适用性,成本和效率。 对于你说的第一个问题,根本解决方案是从架构入手,你想找个非常好的内存管理,很难,倒不如用双进程,原进程到一定程度自动结束释放,启动备用进程服务。这样成本更低,稳定性更高。 对于第二个,如果真要考虑这么细,还要考虑主板的性能和驱动程序的性能,一台服务器当性能长期满载是会容易出问题。 软件跟硬件的最大差别就在于汽车一个零件装得不好,有可能车毁人忙;软件相对要求要宽松很多很多。所以,不是写桌面程序的水平比写服务器的水平要低,只是服务器某些性能指标上要求相对高,桌面程序一样要下很多功夫,比服务器程序都要多。
----------------------------------------------
软件是什么,相信很多人都说不清。
作者:
2016/10/21 12:42:16
14楼:
写高性能的程序。 首先要看瓶颈在哪里,是CPU不够快,主板吞吐效率不高,硬盘 还是网络,还是某个加密程序还是有点慢。但你针对某配置服务器去写,迁移就有成本,所以没必要考虑得这么细。把主要的解决了,通用性强适当牺牲性能。况且也没必要搞得服务器满载。
----------------------------------------------
软件是什么,相信很多人都说不清。
作者:
2016/10/22 4:04:22
15楼:
我觉得你并未理解我的意思。 Indy是基于一个连接一个线程的,真的不适合于真正的服务器,否则也不会出现IOCP这种解决C10K、C100K问题的方案。默认情况下,32位进程大概启动2010个线程就会报存储空间不足,你看看真正的连接能支持多少个?更加不用说那么多线程切换带来的时间开销。 追求性能并不意味着不通用。如果针对某配置服务器去写,是没有必要的。所谓追求性能,很多时候是指选择适合的方案。比如说,加密算法,拿非对称算法来说,在相同的强度下,ECC算法就比RSA运算时间更加少。这个运算时间不可能仅针对具体的机器配置而不同。再比如说,生产者消费者队列(例如,生产者网络收发数据放到队列A,消费者处理队列从队列A获取、处理并删除),真正无锁的算法比lock-free处理速度高7倍左右),这些都是通用的,不是说换个机器就会反过来。 我有十年的客户端开发经验,“不是写桌面程序的水平比写服务器的水平要低,”,不是指低,比如说,你桌面程序点击按钮,调用一个函数,里面即使Sleep(125)也没什么影响。我的意思是,你要抛弃这种单机的想法,时刻抱着这个函数或算法是可能同时N个并发的,这个跟水平无关,但跟认识有关。另外一个意思是,要写一个真正好的服务器程序,需要对操作系统、线程、切换、内存等等都很了解,然后针对需求有所取舍,让程序函数之间很协调。而桌面程序,比如说一个多媒体播放器,你并不需要了解那么多,你可能有一些多媒体编码解码常识就好,也不需要考虑连续24*365长时间运行有可能带来的问题。 另外,任何成熟的服务器都会有性能监测。例如腾讯的服务器,CPU利用率一旦达到50%,监控程序就会报警。而追求性能的意义在于,比如说相同的机器,都是占用35%的CPU,但性能好的可能可以同时处理10万个连接和数据逻辑,而性能不好的,可能只有几千。 所以你的理解是:如果追求高性能,那么就要牺牲稳定性、通用性之类。这是并未真正理解我上面说的。下图是我以前写的IOCP的DEMO,我不相信Indy可以在相同开销下达到如此的网络利用率。
此帖子包含附件: 大小: 72.3K
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
2016/10/22 4:22:42
16楼:
例子中的ECC算法也不可能不通用。
此帖子包含附件: 大小: 38.2K
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
2016/10/22 4:22:57
17楼:
.
此帖子包含附件: 大小: 19.7K
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
2016/10/22 15:54:09
18楼:
既然说到这个份上了,顺便说说Indy这个控件吧。早年我也用过很多次Indy,对它的流程也比较熟悉了。Indy的优点实际上是做客户端的时候,控件内部使用阻塞模式,而调用者使用起来不阻塞。比如说,它的连接函数(下面说的均是Delphi7年代的Indy9版本,后面的没有再看过,所以不一定对应的起来)是有连接超时参数的,而阻塞Socket是很难控制超时的,它是怎么干的呢? 1、Connect函数放到一个线程里面: constructor TConnectThread.Create(ASocket: TSocket; var sAddr: TSockAddr); begin m_Sock := ASocket; m_SockAddr := sAddr; m_bConnected := False; inherited Create(False); end; destructor TConnectThread.Destroy; begin inherited Destroy; end; procedure TConnectThread.Execute; begin m_bConnected := WinSock2.Connect(m_Sock, m_SockAddr, Sizeof(TSockAddrIn)) = 0; Terminate; end; 2、对外的连接函数,类似这样: if nTimeOut = -1 then begin //Result:=connect(s,SockAddr,sizeof(TSockAddr))=0; MyConnectThread := TConnectThread.Create(ASocket, PSockAddr(@SockAddrIn)^); try while not MyConnectThread.Terminated do begin Sleep(1); Application.ProcessMessages; end; Result := MyConnectThread.m_bConnected; finally MyConnectThread.Free; end; end else begin MyConnectThread := TConnectThread.Create(ASocket, PSockAddr(@SockAddrIn)^); try nSleepTime := 125; while nTimeout > nSleepTime do begin Sleep(nSleepTime); nTimeout := nTimeout - nSleepTime; Application.ProcessMessages; if MyConnectThread.Terminated then begin nTimeout := 0; Break; end; end; Sleep(nTimeout); if MyConnectThread.Terminated then Result := MyConnectThread.m_bConnected else begin MyConnectThread.Terminate; closesocket(ASocket); ASocket := INVALID_SOCKET; MyConnectThread.WaitFor; end; finally MyConnectThread.Free; end; end; 也就是说,connect仍然是阻塞的,但是因为放到一个新线程里面,所以不会阻塞调用者的界面UI。比如说,设置的连接超时是3000毫秒,这个函数就是切小到125毫秒一次来连续循环Sleep+Application.ProceMessages响应界面。当超时时间到达而连接线程仍然阻塞未返回,就CloseSocket让连接线程的connect马上返回。 接收过程,它是中间有一个TMemorystream缓冲成员,首先从里面读取,如果里面数据不足够,才真正调用recv。总而言之,它一切就是靠线程来保证不影响界面。但实质上这个TMemorystream,就不细说了,自己测试吧,一切以测试结果为准。凡事不要想当然。就好像有人觉得在多线程里面通过SendMessage之类来实现“无锁”,这种就是想当然。如果实际写个测试程序,可能还不如临界区快,因为在线程内调用这种API,操作系统会在底层帮你上锁了。切记,不要想当然。 另外,Indy一切是函数形式的。拿接收数据来说,有两种函数原型: function Recv:Boolean;//函数方式 procedure Recv;//过程方式 Indy都是基于过程方式,如果函数失败,就Raise触发一个异常。所以使用的时候,总是: try xxxxxx except end; 我们先不说异常、中断带来的开销,光是这个调用就够别扭的。
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
2016/10/27 9:36:35
19楼:
是的 服务端开发和桌面开发是两个不同思路 前者要考虑性能 后者考虑的客户操作
----------------------------------------------
我为人人为我
作者:
2016/10/31 11:38:22
20楼:
都是牛人啊
----------------------------------------------
Delphi 的移动程序开发,是您不可再错失的机遇:http://blog.163.com/you888@188/blog/static/6723961920169319529515/
作者:
2016/10/31 14:24:28
21楼:
都对啊,高连接高并发的server不能用indy,对啊。 平时最多只有几十上百在线,并发更少的可以用indy,也没问题啊。 接收数据需要即时处理,尽快返回,整个过程只有XX毫秒, 尽力优化接收数据算法,省下10毫秒,那就是性能提升xx%。善哉。 接收数据到返回,整个过程需要XX秒, 尽力优化接收数据算法,省下10毫秒,那就是性能提升0.xx%。愚。
----------------------------------------------
-
作者:
2016/10/31 15:09:03
22楼:
DIOCP的http服务,性能也不错的。 DIOCP-RPC和DSS中间件都是基于DIOCP HTTP协议的。
----------------------------------------------
DIOCP官方社区|MyBean官方社区http://www.diocp.org/
作者:
2016/11/14 8:57:05
23楼:
好鸡毛热闹啊,惊涛还是骇浪啊,热闹忍不住来一发!一把年纪了还不减当年。
----------------------------------------------
-