进程间通信

发布于 2024-09-30 03:30:49 字数 1401 浏览 1 评论 0原文

我有两个应用程序:X 和 Y。X 是主应用程序,它处理大量 XML 文件。它已经有十多年的历史了,已经使用了六种技术来存储、处理和处理这些XML文件。
Y是我正在开发的一个调试工具,它可以以更多种方式处理和显示XML文件。人类可读的形式。基本上,它只是有一个样式表集合,用于检测 XML 格式,如果它识别该格式,它会将 XML 转换为 HTML,并显示在 TWebBrowser 组件中。

问题:
当 Y 处于活动状态时,我希望 X 将它处理的任何 XML 发送给 Y 以用于显示目的。但只有当 Y 运行时!如果Y没有运行,X就不会做任何事情。
Y的检测需要随时完成,并且需要很快。我考虑过使用 TCP/IP 通信,但由于缺少 Y 导致的延迟太长。特别是因为有时要处理大量 XML。命名管道和类似的基于网络的解决方案也存在同样的问题。我需要快速确定 Y 是否正在运行且可用,如果是,则快速发送 XML,然后继续 X。
我还考虑过使 Y 成为基于 COM 的应用程序,或者添加带有事件的基于 COM 的 DLL这将允许进程间通信。 DLL 解决方案会很有趣,因为它会向 X 公开一个方法来上传 XML 文件,然后向 Y 发送一个事件来处理 XML。 这似乎是最好的选择,尽管我还需要检查 DLL 是否已注册。如果没有,那么 X 甚至无法调用它!
应用程序 X 也将由不会收到 Y 或附加 DLL 的客户使用,因此在大多数情况下,DLL 将不会被注册。 (正如我所说,它是为了在调试过程中提供帮助...)

但也许还有其他选择? TCP/IP 太慢,COM 有点太复杂。


X 和 Y 将在同一系统上运行。或者系统上只有 X,而 Y 完全缺失。


关于使用内存映射文件...虽然实用,但我需要记住,大多数时候,Y 不会运行,因此 MMF 会浪费内存。 XML 数据在 X 中的大小可达 4 MB,因此在内存中拥有多个此大小的块有点过大了。它可用于在 X 和 Y 之间发送状态消息,但应用程序 X 的内存有时会出现一些问题。虽然 MMF 可以连接到物理文件,但我试图完全避免写入任何临时文件。< br>这是一个很好的解决方案,但我担心还不够好。


我认为一些额外的解释是适当的。应用程序 X 是一个将使用几个小时的应用程序,用户执行大量操作,这些操作会转换为大量需要处理的 XML 数据。应用程序 X 是一个桌面应用程序,它与多个 Web 应用程序 (REST)、Web 服务 (SOAP) 和其他应用程序进行通信,其中大部分是通过 XML 进行的。
应用程序 Y 只是为了查看 X 正在运行的进程的内部情况。基本上,X 工作了 20 分钟,Y 就会弹出。从那一刻起,X 应该开始向 Y 发送 XML,直到 Y 再次消失或直到 X 终止。在大多数情况下,Y 只会运行以捕获正在运行的任务的一小部分,并且它甚至可能启动多次。但我可能以错误的方向思考整件事。也许X应该是Y注册的服务器...当Y找不到X时,这不是一个真正的问题。但是X找不到Y不会导致延迟或其他问题...

I have two applications: X and Y.
X is the main application and it handles a lot of XML files. It has a history of more than 10 years and half a dozen techniques have been used to store, process and handle these XML files.
Y is a debugging tool that I am developing, which can process and display XML files in a more human-readable form. Basically, it just has a collection of stylesheets that will detect the XML format and if it recognizes the format, it will transform the XML to HTML which is displayed in a TWebBrowser component.

Problem:
When Y is active, I want X to send any XML it proceses to Y for displaying purposes. But only when Y is running! If Y is not running, X just won't do anything.
The detection of Y needs to be done on any moment and needs to be fast. I've considered using TCP/IP communication but the delay caused by a missing Y is just too long. Especially since a lot of XML is processed sometimes. Same problem with named pipes and similar network-based solutions. I need to quickly determine if Y is running and available and if so, send the XML fast and then continue X.
I've also considered to make Y a COM-based application or maybe add a COM-based DLL with events that would allow the inter-process communication. The DLL solution would be interesting since it would expose a method to X to upload an XML file, then send an event to Y to process the XML. This seems to be the best option although I would also need to check if the DLL is registered or not. If not, then X can't even call it!
The application X will also be used by customers who won't receive Y or the additional DLL so in most cases, the DLL will not be registered. (As I said, it's meant to help during debugging...)

But maybe there are other options? TCP/IP is too slow, COM is a bit too complex.

X and Y will be running on the same system. Or just X will be on a system and Y is missing completely.


About using memory-mapped files... While practical, I need to keep in mind that most of the times, Y won't be running thus the MMF will waste memory. XML data can be up to 4 MB in size within X thus having multiple blocks of this size in-memory is a bit overkill. It can be used to send status messages between X and Y but memory is sometimes a bit of a problem with application X. And while a MMF can be connected to a physical file, I'm trying to avoid writing any temporary files altogether.
It's a good solution, but I fear not good enough.


Some additional explanations are in order, I think. Application X is an application which will be used for several hours, with users doing a lot of actions that translate to lots of XML data that gets processed. Application X is a desktop application that communicates with several web applications (REST), web services (SOAP) and other applications and most of this is through XML.
Application Y is just meant to peek inside the processes that X is running. Basically, X is working for 20 minutes and Y pops up. From that moment on, X should start sending XML to Y until Y disappears again or until X is terminated. In most cases, Y will just be running to capture just a small portion of the running tasks and it's possibly even started multiple times. But I might be thinking about the whole thing in the wrong direction. Maybe X should be a server with Y registering to it... It's not a real problem when Y can't find X. But X not finding Y cannot result in delays or other problems...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

摘星┃星的人 2024-10-07 03:30:50

以下是根据不同的客户端/服务器调查得出的一些有关速度的真实数据。

所有基准测试均在一台计算机上本地运行。直接访问每秒可实现超过 15000 次查询,HTTP/1.1 远程访问每秒可实现 4300 次以上查询。这是在使用 Centrino2 CPU 并开启防病毒功能的笔记本电脑上进行的基准测试。

2.5. Client server access: 
  - Http client keep alive: 3001 assertions passed
     first in 7.87ms, done in 153.37ms i.e. 6520/s, average 153us
  - Http client multi connect: 3001 assertions passed
     first in 151us, done in 305.98ms i.e. 3268/s, average 305us
  - Named pipe access: 3003 assertions passed
     first in 78.67ms, done in 187.15ms i.e. 5343/s, average 187us
  - Local window messages: 3002 assertions passed
     first in 148us, done in 112.90ms i.e. 8857/s, average 112us
  - Direct in process access: 3001 assertions passed
     first in 44us, done in 41.69ms i.e. 23981/s, average 41us
  Total failed: 0 / 15014  - Client server access PASSED

该基准测试同时测试客户端和服务器速度,并且不是多线程的(即使我们的框架是多线程安全的)。

因此您可以猜测,对于每个请求的 JSON 内容的 4 KB 数据块:

  1. 直接访问(如您的 dll 方法)是最快的,并且消耗的资源更少。
  2. 然后是 GDI 消息。
  3. 然后命名管道。
  4. 然后是 FastCGI 和 HTTP(取决于 FastCGI 的 Web 服务器,HTTP 类的消耗非常低)。

保持活动连接是 HTTP/1.1 连接,多重连接是普通 HTTP/1.0,每个请求都有一个新连接。多连接并没有那么糟糕,因为从服务器的角度来看,我们使用了基于 I/O 完成端口的高效线程池。

请参阅http://synopse.info/forum/viewtopic.php?id=90

Here are some real data about speed, according to diverse client/server investigation.

All benchmarks were run locally on one computer. You can achieve more than 15000 queries per second on direct access, 4300 queries per second on HTTP/1.1 remote access. This was benchmarked on a Notebook using a Centrino2 CPU, with AntiVirus ON.

2.5. Client server access: 
  - Http client keep alive: 3001 assertions passed
     first in 7.87ms, done in 153.37ms i.e. 6520/s, average 153us
  - Http client multi connect: 3001 assertions passed
     first in 151us, done in 305.98ms i.e. 3268/s, average 305us
  - Named pipe access: 3003 assertions passed
     first in 78.67ms, done in 187.15ms i.e. 5343/s, average 187us
  - Local window messages: 3002 assertions passed
     first in 148us, done in 112.90ms i.e. 8857/s, average 112us
  - Direct in process access: 3001 assertions passed
     first in 44us, done in 41.69ms i.e. 23981/s, average 41us
  Total failed: 0 / 15014  - Client server access PASSED

This benchmark tests both client and server speed, and is not multithreaded (even if our framework is multi-thread safe).

So you can guess that, for a 4 KB data block of JSON content for each request:

  1. The direct access (like your dll approach) is the fastest, and less resource consuming.
  2. Then GDI messages.
  3. Then named pipes.
  4. Then FastCGI and HTTP (depending on your web server for FastCGI, the HTTP classes are very low consuming).

Keep alive connections are HTTP/1.1 connections, and multi connect is plain HTTP/1.0, with a new connection for every request. Multi-connect is not so bad, because from the server point of view, we used an efficient Thread Pool based on I/O completion ports.

See http://synopse.info/forum/viewtopic.php?id=90

墨落成白 2024-10-07 03:30:50

使用内存映射文件。它们非常适合您的特定任务。如果您没有时间或没有意愿实施,我们的 MsgConnect 及其 MMF 传输将来救援定制方案。

Use memory-mapped files. They are great for your particular tasks. And our MsgConnect with it's MMF transport will come to rescue if you don't have time or intention to implement custom scheme.

合约呢 2024-10-07 03:30:50

我会转到内存映射文件方向,但我不会直接在代码路径中实现。相反,我会通过一个中间对象来执行对内存映射文件的写入,这样它就可以替换为仅如果数据不在位,则丢弃该数据。

当程序首次启动(或被告知通过配置更改进行检查)时,系统将创建“不执行任何操作”的存根或“通过内存映射文件记录”对象。这还使您能够在需要时添加稍后的调试器...例如用于网络日志记录的 UDP 记录器等。

您可以使用“FindWindow”调用来查看调试器是否正在运行。

I would go the memory mapped files direction, but I would not implement directly in the code path..instead I would go through an intermediate object that would perform the writing to the memory mapped file, this way it could be replaced with one that just discarded the data if it was not in place.

When the program first starts (or is told to check via a configuration change) the system would either create the stub "do nothing" or the "log via memory mapped files" object. This also gives you the capability of adding a later debugger when the need arises...such as a UDP logger for network logging, etc.

You can use the "FindWindow" call to see if your debugger is running.

醉殇 2024-10-07 03:30:50

如果您愿意使用临时文件作为传输,那么这将很容易

  1. 两个程序在启动时注册相同的自定义消息
    MsgAppNotifyID := RegisterWindowMessage(......);

  2. 程序 Y 必须具有处理自定义消息的代码
    使用 SetWindowLong 或任何等效的东西

  3. 程序X,使用FindWindow查看程序Y是否正在运行

  4. 程序X,如果Y正在运行,使用一致的文件名在两端的已知位置/目录上创建临时文件,例如 XXYY1234 (XXYYn) 格式,其中 1234=n

  5. 节目 X,使用 BroadcastSystemMessage 向节目 Y 发出信号
    通知接收者 := BSM_APPLICATIONS;
    广播系统消息(BSF_IGNOECURRENTTASK
    或 BSF_POSTMESSAGE 或 BSF_FORCEIFHUNG、@NotifyRecipients、MsgAppNotifyID、任何自定义值、n);

  6. 程序 y,使用 WParam 作为 n 处理上述消息并重建用于处理的文件

Cheers
祝你好运

If you are willing to use temporary file as transport, then it will be easy

  1. Both programs register a same custom message on start up
    MsgAppNotifyID := RegisterWindowMessage(......);

  2. Program Y must have codes to handle the custom message
    using SetWindowLong or anything equivalent

  3. Program X, using FindWindow to see if program Y is running or not

  4. Program X, If Y is running, Create a temp file on known location/directory of both end using consistent file name such as XXYY1234 (XXYYn) format where 1234=n

  5. Program X, use BroadcastSystemMessage to signal program Y
    NotifyRecipients := BSM_APPLICATIONS;
    BroadcastSystemMessage(BSF_IGNORECURRENTTASK
    or BSF_POSTMESSAGE or BSF_FORCEIFHUNG, @NotifyRecipients, MsgAppNotifyID, any custom value, n);

  6. Program y, process above message using WParam as n and reconstruct the file for process

Cheers
Good luck

画尸师 2024-10-07 03:30:50

运行一个仅在连接上(作为触发器)的 TCP 服务器非常快并且应该执行您想要的操作

running a TCP server which just on a connect (as a trigger) is really fast and should do what you want

喜爱纠缠 2024-10-07 03:30:49

查看我的 IPC:

http://www.cromis.net/blog/ downloads/cromis-ipc/

它速度快、免费并且具有可设置的超时,因此您可以将其设置为非常小的量(例如 50 毫秒)。因为它非常快(典型的消息周期请求 -> 处理 -> 响应需要不到 1 毫秒,大约 0.1 毫秒),因此您可以有非常小的超时。它内置了客户端服务器,所以很多客户端都没有问题。它以线程方式运行,后面有任务池,因此不会冻结您的程序,并且它具有非常灵活的数据包,可以轻松写入/读取数据。

正如已经说过的,您甚至可以通过其他方式检查调试器是否正在运行。

  • 检查进程
  • 检查进程的主窗口
  • 使用互斥体
  • ...

Have a look at my IPC at:

http://www.cromis.net/blog/downloads/cromis-ipc/

It is fast, free and has a setable timeout, so you can set it to a very small amount (50ms for example). Because it is very fast (typical message cycle request -> process -> response takes less than 1ms, around 0.1ms) you can have very small timeouts. It has client server build into it, so many clients are no problem. It runs threaded with task pool behind so it does not freeze your program and it has very flexible data packets to ease writing / reading the data.

As already said you can even check with other means if the debugger is running.

  • Check for process
  • Check for main window of the process
  • Use a Mutex
  • ...
涙—继续流 2024-10-07 03:30:49

您可以做得更简单,因为您只是想查明一个应用程序是否正在从另一个应用程序运行。只要它们由同一用户在同一台​​计算机上运行,​​您就可以让 X 只需使用 FindWindow() 查看 Y 当前是否正在运行。只需确保为 Y 指定一个有意义的名称(在下面的示例中,它是 TXMLFormatterForm):

var
  XMLWindow: HWnd;
begin
  XMLWindow := FindWindow('TXMLFormatterForm', nil);
  if XMLWindow > 0 then
    // Y is running
end;

您还可以使用 Y 的窗口标题(标题),只要您确定它是不同的即可:

XMLWindow := FindWindow(nil, 'Workshop Alex's XML Formatter');

You can do it more simply, since you're just trying to find out if one app is running from another one. As long as they're running on the same machine by the same user, you can have X simply use FindWindow() to see if Y is currently running. Just make sure you give Y a meaningful name (in the sample below, it's TXMLFormatterForm):

var
  XMLWindow: HWnd;
begin
  XMLWindow := FindWindow('TXMLFormatterForm', nil);
  if XMLWindow > 0 then
    // Y is running
end;

You can also use Y's window caption (title), as long as you're sure it's distinct:

XMLWindow := FindWindow(nil, 'Workshop Alex's XML Formatter');
血之狂魔 2024-10-07 03:30:49

您可以让 X 将其输出写入 内存映射文件 - Y如果正在运行,可以检索数据。这样X就不会关心Y是否起来了。

X 可以在已知位置写入某种控制信息(例如,存储从映射文件中的偏移量 0 开始的最后 1000 个写入的 XML 的偏移量),并使用文件的其余部分作为原始数据的循环缓冲区。

如果您需要 Y 作为 X 中操作的决定因素,请让 Y 创建映射文件,然后使用它的存在/不存在来检查“通道”X 端的数据生成。有创建者和第二个用户的示例代码此处< /a>.

You could have X write its output to a memory-mapped file - Y can retrieve the data if it is running. This way X does not care whether or not Y is up.

X could write some kind of control info at a known location (eg. store the offsets of last 1000 written XMLs starting at offset 0 in the mapped file) and use the rest of the file as a circular buffer for the raw data.

If you need Y to be the determining factor for actions in X, have Y create the mapped file, and then use its presence/absence as a check on the data production on the X side of the 'channel'. There is example code for creator and second user here.

新一帅帅 2024-10-07 03:30:49

命名管道速度很快,因为它们的实现基于内存映射文件。可能会很慢的是服务器故障时的超时...

如果您需要在同一台计算机上快速响应,为什么不使用好的旧GDI消息呢?

即使没有用户界面或视觉形式,您也可以在普通控制台或后台服务应用程序中使用这些消息(如果是服务应用程序,安全设置必须指定该服务必须与桌面交互,即必须能够接收和发送消息)。

诀窍是处理 WM_COPYDATA 消息。
例如,请参阅我们的 TSQLRestClientURIMessage 类以及 TSQLRestServer 的 ExportServerMessage/AnswerToMessage 方法,如 http://synopse.info/fossil/finfo?name=SQLite3/SQLite3Commons.pas

在实践中,我发现对于少量数据(最多 64 KB 或每条消息都是如此)。

您可以在 寻找替代方案进程间通信中使用的 Windows 消息

Named pipes are fast, because they are based on memory mapped files, for their implementation. What could be slow is the timeout in case of server failure...

If you need to have fast response on the same computer, why don't you use good old GDI messages?

You can use these messages, even with no User Interface or visual form, in plain console or background service applications (in case of a service application, the security settings must specify that this service must interact with the desktop, that is, must be able to receive and send messages).

The trick is to handle WM_COPYDATA messages.
See for example our TSQLRestClientURIMessage class, and the ExportServerMessage/AnswerToMessage methods of TSQLRestServer, as implemented in http://synopse.info/fossil/finfo?name=SQLite3/SQLite3Commons.pas

In practice, I found out that GDI messages are much faster than named pipes for small amount of data (up to 64 KB or such per message).

You have alternatives in Looking for an alternative to windows messages used in inter-process communication

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文