4

Please read before tagging as duplicate.

I'm creating a set of applications which rely on smart cards for authentication. Up to now, each application has controlled the smart card reader individually. In a few weeks, some of my customers will be using more than one application at the same time. So, I thought maybe it would be more practical to create a service application which controls the authentication process. I'd like my desktop applications to tell the service application they are interested in the authentication process, and the service application would then provide them with information about current user. This part is easy, using named pipes. The hard part is, how can the service tell the desktop applications that an event has occurred (UserLogIn, UserLogOut, PermissionsChanged, ... to name a few). So far I have two methods in mind. CallBack functions, and Messages. Does anyone have a better idea? I'm sure someone has.

Warren P
  • 65,725
  • 40
  • 181
  • 316
iMan Biglari
  • 4,674
  • 1
  • 38
  • 83
  • 5
    You can use named pipes for that too. You need a thread that blocks on the pipe. When the service sends data down the pipe, the thread wakes up, reads it, and delivers the message to the main thread. Then it waits on the pipe for the next message. – David Heffernan Sep 05 '12 at 10:50
  • Sometimes you can use database server for that, providing all the application share the same database and server supports events – Arioch 'The Sep 05 '12 at 11:19
  • "Marshalling" is RPC term of turning local callback call into message and then into remote callback call. No dichotomy there :-) – Arioch 'The Sep 05 '12 at 12:20
  • 1
    You should probably REWRITE all your event handlers that need to be "invoked remotely" to just call an API/Interface that you can then invoke via the remote system as well. Code against interfaces, not implementation details like TButton.OnClick(Sender:TObject). I would code each event as an integer ID, just like window messages. – Warren P Sep 05 '12 at 15:46

3 Answers3

9

You want do to IPC (Inter Process Communication) with Delphi.

There are many links that can help you, Cromis IPC is just one to give you an idea what you are after.

A similar SO question to yours is here.

If you want to go pure Windows API, then take a look at how OutputDebugString communications is implemented.
Several tools can listen to the mechanism and many apps can send information to it.

Search for DBWIN_DATA_READY and DbWin32 for more information on how the protocol for OutputDebugString works.

This and this are good reading.

Community
  • 1
  • 1
Jeroen Wiert Pluimers
  • 23,965
  • 9
  • 74
  • 154
  • I need an event firing mechanism. So, I guess I have to use messages after all. BTW, what does RPC do? As the name suggests, it should be about calling a procedure in another process, right? – iMan Biglari Sep 05 '12 at 11:03
  • Isn't event handler a procedure ? – Arioch 'The Sep 05 '12 at 11:17
  • @Arioch'The I meant that I have no idea how RPC works. I'm searching the web at the moment for Delphi RPC source codes... – iMan Biglari Sep 05 '12 at 11:22
  • 1
    The question is not only about IPC, but implementing *callback events*. So Cromis IPC does not match the need here, unless each Desktop app becomes a server. – Arnaud Bouchez Sep 05 '12 at 11:26
  • @ArnaudBouchez Can you imagine implementing callback events without becoming a server ? and message passing is just an API implementation. HTTP server is still server. To make separate application use you internals - you have to expose them. And that is making you a server. No matter which method used. – Arioch 'The Sep 05 '12 at 12:12
  • 1
    I have contemplated a separate solutions for callbacks that would be hooked to my IPC. But due to lack of time I have not made any progress yet. To be honest it is very easy to make each client also a server. It also is very light on resources. But sure it is not an elegant solution. – Runner Sep 05 '12 at 12:16
  • @Arioch'The You are right, by "Server", I meant explicitly a server e.g. over IP, not a server-behavior-emulation (like WebSockets) at the application level. Cromis has no built-in support of such server-emulation functionality, even if it could implement it, but by hand. You can implement callbacks without becoming a server, but my experiment is a stateless approach is now better - see my answer. This is the known [REST / WebSockets trolling subject](http://bill.burkecentral.com/2012/02/28/web-sockets-a-disaster-in-waiting). This is just using a protocol for what it was meant for. :) – Arnaud Bouchez Sep 05 '12 at 13:20
  • @Arnaud for what i heard websockets turned to be insecure so not for authentication-related app. And it is for www browsers anyway – Arioch 'The Sep 05 '12 at 13:47
  • @Arioch'The Yes of course, websocket is for the web. But it is implemented on the blocking pattern you proposed. – Arnaud Bouchez Sep 05 '12 at 16:45
  • @Arnaud i read the article. The only arguments i saw against "long polling" were "HTTP server is not designed for this" and with no concretization of the server it looks as pure theory hardly applicable to this case, and "I would have loved to have a built-in and tested cross-browser mechanism" which is hardly applicable here as well. OTOH long polling reduces find-and-connect problems. You only should be able to connect to single server from all clients to make long polling work. – Arioch 'The Sep 06 '12 at 10:03
5

When it gets into IPC, some tips:

  • Do not be tied on one protocol: for instance, if you implements named pipe communication, you would later perhaps need to run it over a network, or even over HTTP;
  • Do not reinvent the wheel, nor use proprietary messages, but standard formats (like XML / JSON / BSON);
  • Callbacks events are somewhat difficult to implement, since the common pattern could be to implement a server for each Desktop client, to receive notifications from the server.

My recommendation is not to use callbacks, but polling on a stateless architecture, on the Desktop applications. You open a communication channel with the server, then every second / half second (use a TTimer in your UI), you make a small request asking for what did change (you can put a revision number or a time stamp of your last retrieval). Therefore, you synchronize your desktop data with pending events. Asking for updates on an existing connection is very fast, and will just send one IP packet over the network back and forth, if nothing changed. It is a very small task, and won't slow down nor the client nor the server (if you use some in-memory cache).

On practice, with real application, such a stateless architecture is very responsive, from the end-user point of view, and is much more easy to deploy. You do not need to create a server on each desktop application, so you don't have to open firewall ports or such. Since HTTP is stateless, it is even Internet friendly.

If you want to develop services, you can use DataSnap, something like RemObjects or you can try our Open Source mORmot framework which is able to create interface-based services with light JSON messages over REST, either in-process, using GDI messages, named pipes or TCP/HTTP - for free, with unbeatable performance, build-in security, and from Delphi 6 up to XE2. For your event-based task, just using the Client-Server ORM available in mORMot could be enough: create a table/class storing the events (you can even define a round-robin in-memory storage - no need to use SQLite3 engine nor a DB here), then ask for all pending events since the last refresh. And the server can safely be a background service, or a normal application - some mORMot users even have the same executable able to be either a stand-alone application, a server service, an application server, or a UI client, just by changing the configuration.

Edit / announcement:

On the mORMot roadmap, we added a new upcoming feature, to easily implement one-way callbacks from the server.

That is, add transparent "push" mode to our Service Oriented Architecture framework. Aim is to implement notification events triggered from the server side, very easily from Delphi code, via some interface definitions, even over a single HTTP connection - for instance, WCF does not allow this: it will need a dual binding, so will need to open a firewall port and such.

It will used for easy Event Collaboration, via a publish / subscribe pattern, and allow Event Sourcing. I will try to make it implement the two modes: polling and lock-and-wait. A direct answer to your question.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
  • 1
    I see no dichotomy between polling and server. The only difference is "who opens the connection". HTTP Comet for example. Firebird/Interbase for example. One side opens the connection, another pushes the events when ready. Polling is not obligatory returned with "no news", but can be locked until there is event, like Win32 GetMessage. So your MainForm is polling for WM_* no more than HTTP server is polling for new packets arrived. The split is between lock-and-wait vs no-wait, not between "who opens connection". – Arioch 'The Sep 05 '12 at 12:13
  • "using GDI messages" AFAIR services no more are allowed to have desktop window interaction, and UAC application isolate them too. That is probably not an option for topicstarter – Arioch 'The Sep 05 '12 at 12:18
  • @Arioch'The Locked pulling may be confusing, e.g. if the connection is broken. WebSockets are e.g. sometimes implemented with this pattern, but it is more difficult to implement than a periodic no-lock quick request. But lock-and-wait will also lock your desktop application, so it is not friendly within a TTimer event, so you'll need a dedicated thread. With direct-return pattern, you can have a Desktop application with just one thread, much easier to debug. Of course, GDI messages is not possible as a service, but is the fastest (faster than named pipes) between two apps on the same PC. – Arnaud Bouchez Sep 05 '12 at 12:59
  • Polling (every second) causes unneeded network traffic - when the number of clients increases, servers will be more and more busy with 'no-information-available' handling. A more scaleable solution is a combination of heartbeats and server->client packets sent only when there is actual data for the client. – mjn Sep 05 '12 at 13:26
  • 1
    @mjn OP was speaking either about local access, either about a corporate network, or a VPN. For an AJAX application with thousands of word-wide spread clients over the Internet, websockets do make sense. But such heartbeats + locking is to be tuned on the server, e.g. without wasting a thread per client: this is not an easy task, so is not my favorite here. On a corporate network, polling is easy to code and debug, and is very fast, with proper in-memory caching. Take a look at the led on your network plug: it is blinking all the time, and won't slow down your browser nor your favorite IDE. ;) – Arnaud Bouchez Sep 05 '12 at 13:37
  • Look at InterbaseExpress. TIBEvents spawns a thread (or maybe even several, don't remember) for waiting. Then it just uses PostMessage and here we are. Locked threads for messaging and single-thread for desktop app main code. I would anyway move callbacks into separate thread. Imagine the server is dead or lagging, you "heartbeat" wold make desktop application freeze every second in designed single-threaded. No, definitely dedicateda nd very simple thread would be better :-) – Arioch 'The Sep 05 '12 at 13:50
  • Firebird and Yaffil teams finished some shared-mem IPC, they named XNet, that Borland never complete. Guess it is soemthing about semaphores or such. It does not use GDI nor TCP, but combines best of both :-) – Arioch 'The Sep 05 '12 at 13:52
  • i wonder if someone managed to run D-Bus on Delphi (not on FPC) :-D – Arioch 'The Sep 05 '12 at 13:53
  • @Arioch'The Of course not, if the server is dead, the heartbeat should handle it as expected, closing the connection, and trying to refresh it later. In practice, I never experimented such a freeze in real-world applications implemented as I described above, unless an explicit error message is displayed. – Arnaud Bouchez Sep 05 '12 at 16:40
  • Well, okay, i still more believe into locking thread for message fetching, and then using PostMessage or similar queue to pass it to main thread. Getting message and working it over - are just different tasks for different threads. I think this stone kills both birds, simplicity of main program and reliability of separate thread. – Arioch 'The Sep 06 '12 at 08:53
0

You can use a simple TCP socket connection (bidirectional) to allow asynchronous server to client messages on the same socket.

An example is the Indy TIdTelnetClient class, it uses a thread for incoming messages from the server.

You can build a similar text-based protocol and only need a Indy TCP server instance in the service, and one Indy Client instance in the application(s).

mjn
  • 36,362
  • 28
  • 176
  • 378