Download demo project - 10 Kb
This article presents a client/server model where the communication
between processes is done using shared memory. Since shared memory may
be used only on a single machine, all processes must run on a same computer.
This is an obvious limitation. However, the advantage is a speed of communication
(note that speed may be severely compromised by a bad implementation on
both sides - client and server). Another advantage is that this method
is available on any platform (Windows 95/98 as well as Windows NT).
Using shared memory enables us to design a system where we have a single
server and multiple clients communicating in both directions with the server.
Communication is initiated by the client -- server is normally in idle
state waiting for the client request. Communication is thread safe is a
sense that only a single client may exchange information with the server
at any moment of time.
Both client and server must create several global named objects:
-
File mapping object that is mapped to a pointer to application specific
structure within each process.
-
Two (2) named events for communication between the server and a single
client.
-
Mutex to synchronize excess to the server among multiple clients.
Synchronization among different clients is explained with the following
pseudo code:
if WaitForSingleObject(global named mutex object) is free then
execute communication session with the server (see below)
ReleaseMutex(global named mutex object)
This ensures that only a single client may execute a communication session
with the server. While the communication session is active, every other
client is waiting for the global named mutex object (of course, only if
it needs to communicate with the server at exactly the same moment as any
other client). This protection is not needed on the server side (it does
not need the global named mutex object) since client request is guarantied
to come from a single client at a time.
Following pseudo code shows how the communication session is performed
between the server and a client:
Client side
if WaitForSingleObject(global named mutex object) is free then
Fill application specific structure mapped as a shared memory
SetEvent(m_hExec)
if WaitForSingleObject(m_hDone, timeout) is WAIT_OBJECT_0 then
Handle values in the application specific structure returned from the server
else
Timeout waiting for the server
ReleaseMutex(global named mutex object)
Server side
if WaitForSingleObject(m_hExec, timeout) is WAIT_OBJECT_0 then
Get values from the application specific structure
Set return values
SetEvent(m_hDone)
The timeout used in a WaitForSingleObject on the client side depends on the
task that is done within the server. In order to speed up the communication,
server needs to be as fast as possible.
Timeout used in a WaitForSingleObject on the server side depends on
the server side implementation. Sample code (for simplicity) uses a timer
handler that periodically checks for client side requests. In a real production
code, one should use a separate thread and a WaitForMultipleObjects function
that waits for event m_hExec and at the same time for the event that will
shutdown the thread (application exit). In this case, timeout may be infinite.
This will improve server performance dramatically since it will be able
to respond to client request immediatelly (the delay may be only if it
is already handling another client request).
Usually, server is started first and any client started later will connect
to the server. Sample project is designed in a way that the first instance
is automatically the server and any other instance started later is a client.
The communication handles correctly the situation when the server is closed
while the clients are running. What needs the special consideration
is the initialization phase when the server and clients are distinct and
different applications. In this case, there is a possibility to prevent
starting the client if the server is not running or to allow the client
to run but to check (and connect) to the server when the client needs to
send something to the server. Following pseudo code shows initialization
of the client and the server:
Client side
m_hMap = OpenFileMapping(...)
if m_hMap is NULL then
Server is not running
else
pointer to structure = MapViewOfFile(m_hMap, ...)
Server side
m_hMap = CreateFileMapping(...)
if GetLastError() is ERROR_ALREADY_EXISTS then
Server is either started for the second time or previous server instance
is killed while the clients are still running.
pointer to structure = MapViewOfFile(m_hMap, ...)
Multiple instances of the server must be prevented. This can be done using
any of the techniques to prevent multiple instances of a single application.
This design is used in the Runtime
Monitoring Agent and performs very good. Multiple clients (from different
proceses and threads) are able to communicate with the single server in
a very fast and reliable manner.