简体   繁体   English

Delphi 7 Indy 9多线程HTTP服务器

[英]Delphi 7 Indy 9 multithreaded HTTP Server

I need to write a multithreaded HTTP server. 我需要编写一个多线程HTTP服务器。 I know Indy handles the threading via IdThreadMgrPool. 我知道Indy通过IdThreadMgrPool处理线程。

My requirements are straightforward: have a server that accepts multiple simultaneous clients (web browser POST requests), runs a limited number of threads that call a Delphi DLL (likely separate to the connection threads), and returns the results. 我的要求很简单:拥有一台服务器,它可以接受多个并发客户端(Web浏览器POST请求),运行有限数量的调用Delphi DLL的线程(可能与连接线程分开),并返回结果。

Non-blocking would be the ultimate (like node.js). 无阻塞将是最终的选择(例如node.js)。

There are several SO posts on this topic. 关于此主题有几篇SO帖子。 What I can't find here (or via Google) is an example of how to use IdThreadMgrPool. 我在这里(或通过Google)找不到的是如何使用IdThreadMgrPool的示例。 I see posts that say it must be used, but no example how. 我看到有帖子说必须使用它,但没有示例如何使用。 There is no example on Indy's website either. 在Indy的网站上也没有任何示例。

Could someone point me to an example? 有人可以指出一个例子吗? Or is there a FOS framework that will work for this? 还是有一个FOS框架对此适用?

One idea is to have Indy spawn multiple threads as normal, then to have these threads access a controlled pool of threads that run the DLL. 一种想法是让Indy正常产生多个线程,然后让这些线程访问运行DLL的受控线程池。 If this is plausible, then I just need to know the "normal" case usage example. 如果这是合理的话,那么我只需要知道“正常”案例用法示例即可。

To use TIdThreadMgrPool , at a minimum all you have to do is create an instance of it, assign that to the TIdHTTPServer.ThreadMgr property, and set its PoolSize property. 要使用TIdThreadMgrPool ,至少要做的就是创建一个实例,将其分配给TIdHTTPServer.ThreadMgr属性,并设置其PoolSize属性。 All of that can be done at design-time. 所有这些都可以在设计时完成。

Keep in mind that the PoolSize does not limit the number of connections on the server. 请记住, PoolSize不会限制服务器上的连接数。 The server has its own MaxConnections property for that purpose. 服务器为此具有自己的MaxConnections属性。 For example, you could have a PoolSize of 10 and have 15 clients connected simultaneously, and thus 15 threads running. 例如,您的PoolSize为10,同时连接了15个客户端,因此有15个线程在运行。 When they disconnect, 10 threads will be put back in the pool and 5 threads will be terminated. 当它们断开连接时,会将10个线程放回池中,并终止5个线程。

To customize the pool threads, you can derive a new class from TIdPeerThread , optionally override its virtual BeforeExecute() and AfterExecute() methods to perform per-thread initializations the cleanups, and then assign that class to the server's (not the ThreadMgr's) ThreadClass property at runtime before activating the server. 若要自定义池线程,可以从TIdPeerThread派生一个新类,可以选择重写其虚拟的BeforeExecute()AfterExecute()方法以执行每个线程的初始化清理,然后将该类分配给服务器(而不是ThreadMgr的) ThreadClass激活服务器之前在运行时添加属性。 Inside your server event handlers, you can then typecast the provided TIdPeerThread object to your custom class and use it as needed. 然后,在服务器事件处理程序内部,可以将提供的TIdPeerThread对象转换为自定义类,并根据需要使用它。

You can add methods to your custom thread class and have them internally access the DLL, throttling as needed. 您可以将方法添加到自定义线程类中,并使它们在内部访问DLL,并根据需要进行限制。 The simplest throttle would be to use a single shared semaphore to control the number of threads that can enter the semaphore at a time. 最简单的限制是使用单个共享信号量来控制一次可以进入该信号量的线程数。 In that regard, you can then limit to, say, 2 threads at a time even if 15 threads are running. 因此,即使正在运行15个线程,也可以一次限制为2个线程。

Since you say you want to "run the DLL in a thread", a semaphore will likely not be enough. 因为您说要“在线程中运行DLL”,所以信号量可能还不够。 In that case, I would recommend using an I/O Completion Port instead. 在这种情况下,我建议改用I / O完成端口 You can have your custom thread class post a request to the IOCP using PostQueuedCompletionStatus() and wait for the response to come back. 您可以让您的自定义线程类使用PostQueuedCompletionStatus()将请求发布到IOCP,然后等待响应返回。 Throttling is accomplished by the number of threads you create to service the IOCP, such as one thread per CPU core. 节流由您创建的为IOCP服务的线程数来完成,例如每个CPU内核一个线程。 Each IOCP thread would use GetQueuedCompletionStatus() in a loop to receive posted requests. 每个IOCP线程将在循环中使用GetQueuedCompletionStatus()来接收发布的请求。

Indy is not asynchronous, so you would not be able to post a request to the IOCP and let it send a response back to the client directly when ready. Indy不是异步的,因此您将无法将请求发布到IOCP,并使其在准备好后直接将响应发送回客户端。 The server sends a response back to the client using the same thread that manages the client connection. 服务器使用管理客户端连接的相同线程将响应发送回客户端。 So the client thread will have to post a request to the IOCP and wait for its response, then send that response to the client. 因此,客户端线程将必须向IOCP发送请求,并等待其响应,然后将该响应发送给客户端。 You can define a record that contains a TEvent , input values needed for calling the DLL, and output values for the DLL's response. 您可以定义一条包含TEvent ,记录调用DLL所需的输入值以及DLL响应的输出值的记录。 Then create an instance of that record, post a pointer to it to the IOCP, and wait for the TEvent to be signalled. 然后创建该记录的实例,将指向它的指针发布到IOCP,然后等待TEvent发出信号。 When an IOCP thread receives the record pointer, it can call the DLL as needed, fill the record with the response, and then signal the record's TEvent . 当IOCP线程接收到记录指针时,它可以根据需要调用DLL,用响应填充记录,然后用信号通知记录的TEvent The waiting client thread will then be unblocked and can send the record's response data to the client as needed. 等待中的客户端线程将被解除阻塞,并可以根据需要将记录的响应数据发送到客户端。

Indy server does not scale well. Indy服务器无法很好地扩展。

Consider using http.sys kernel mode server, iocp based. 考虑使用基于iocp的http.sys内核模式服务器。

Our open source SynCrtSock unit feature a high performance http server, and works perfectly from Delphi 5 up to XE6. 我们的开源SynCrtSock单元具有高性能的http服务器,并且可以在Delphi 5到XE6上完美运行。

See for instance this sample code . 例如,参见此示例代码

If you have a Windows server available I would suggest writing an ISAPI DLL with Delphi 7 and deploying it on IIS, which will handle all your server side issues, particularly if you have Server 2008 R2 with IIS 7.5 (or better). 如果您有可用的Windows服务器,建议您使用Delphi 7编写ISAPI DLL并将其部署在IIS上,这将处理所有服务器端问题,尤其是当您使用带有IIS 7.5(或更高版本)的Server 2008 R2时。 Your client side can use Indy to connect to IIS, and the Indy client combined with Delphi ISAPI's request/response model support several features which make it easy to pass data from your client into your server side request handler and back to your client. 您的客户端可以使用Indy连接到IIS,并且Indy客户端与Delphi ISAPI的请求/响应模型相结合,支持多种功能,可以轻松地将数据从客户端传递到服务器端请求处理程序中,再传递回客户端。 No ASP.NET required - all native Delphi and the "classic" ISAPI application model. 无需ASP.NET-所有本机Delphi和“经典” ISAPI应用程序模型。

Delphi 7 will generate the ISAPI application code - you get an action editor to handle requests when IIS sends them to your DLL, which is determined by the URL your client sends. Delphi 7将生成ISAPI应用程序代码-当IIS将请求发送到DLL时,您将获得一个动作编辑器来处理请求,该请求由客户端发送的URL决定。 You have the ability to persist session information, create global caches and you have essentially all the non-visual aspects of the VCL available within the context of your ISAPI DLL. 您可以保留会话信息,创建全局缓存,并且在ISAPI DLL的上下文中,基本上可以使用VCL的所有非可视方面。

IIS handles the threading - will probably handle far more simultaneous connections than you need - and also gives you the ability to determine how many instances of your DLL can be loaded at once, as well as many other options, such as recycling, various forms of authentication and levels of security. IIS处理线程-可能处理的并发连接远远超出您的需要-并且还使您能够确定一次可以加载DLL的实例的数量,以及许多其他选项,例如回收,各种形式的身份验证和安全级别。 You can use the application pooling abilities of IIS for scaling, etc. 您可以使用IIS的应用程序池功能进行扩展等。

I have developed several large scale enterprise level solutions using this architecture (Indy clients embedded in Delphi exe's). 我已经使用这种体系结构开发了几种大型企业级解决方案(Delphi exe中嵌入了Indy客户端)。 It is stable and relatively "painless" once you get down the basics of Delphi's ISAPI application model and the bugaboos of IIS deployment. 一旦掌握了Delphi的ISAPI应用程序模型的基础知识和IIS部署的缺陷,它就会变得稳定且相对“无痛”。

If you have this option available, why reinvent the wheel? 如果您有此选项,为什么还要重新发明轮子呢?

See an example here: http://sourceforge.net/p/xxm/code/HEAD/tree/trunk/Delphi/http/ 在此处查看示例: http : //sourceforge.net/p/xxm/code/HEAD/tree/trunk/Delphi/http/

The thread pool logic is here: http://sourceforge.net/p/xxm/code/HEAD/tree/trunk/Delphi/common/xxmThreadPool.pas 线程池逻辑在这里: http : //sourceforge.net/p/xxm/code/HEAD/tree/trunk/Delphi/common/xxmThreadPool.pas

Xxm actually provides an interface you can code against so the result is portable over IIS, Apache or the plain HTTP server with multi-threading. Xxm实际上提供了您可以针对其进行编码的接口,因此结果可以通过IIS,Apache或具有多线程的 HTTP服务器进行移植。 There's also a http.sys version and a connector to run locally right into Internet Explorer (great for debugging). 还有一个http.sys版本和一个连接器,可直接在Internet Explorer中本地运行(非常适合调试)。 Each of these also have an 'auto-update' version, that will hot-swap the projects DLL and use it for any new requests (great for live servers). 它们每个都有一个“自动更新”版本,该版本将热交换项目DLL,并将其用于任何新请求(对于实时服务器而言非常有用)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM