For my application, I need to have a central process responsible for interacting with many client processes. The client processes need a way to identify and communicate with the central process. Additionally, the central process may not be running, and the client process needs a way to identify that fact. This application will be running on a Unix-like system, so I'd thought about using named pipes sockets for the task. How would I, specifically, go about using named pipes sockets for this task (actual code would be greatly appreciated!)? If named pipes sockets are not ideal, are there better alternatives?
views:
81answers:
5Is this an application that already makes use of a database? If so I would use that rather than adding another whole communication medium to the mix.
D-Bus provides object-oriented IPC, plus includes an activation feature which will start up the server process if it is not already running. The downside is that network encapsulation is basically DIY.
Named pipes are not really ideal for this - they are best suited for single-reader, single-writer situations.
UNIX-domain sockets, however, are perfectly suited for it. They use the sockets API, with the endpoint name being a filesystem entry (as with a named pipe).
Here's a very simple example (you will of course want to add copious error checking!). First the server side:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define SOCKNAME "/tmp/foo"
int main()
{
int s1, s2;
int i;
struct sockaddr_un sa = { AF_UNIX, SOCKNAME };
unlink(SOCKNAME);
s1 = socket(AF_UNIX, SOCK_STREAM, 0);
bind(s1, (struct sockaddr *)&sa, sizeof sa);
listen(s1, 5);
for (i = 0; i < 10; i++)
{
struct sockaddr_un sa_client;
socklen_t sa_len = sizeof sa_client;
FILE *f;
s2 = accept(s1, (struct sockaddr *)&sa_client, &sa_len);
f = fdopen(s2, "r+");
fprintf(f, "Hello, you are client number %d\n", i + 1);
fclose(f);
}
return 0;
}
Now the client side:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SOCKNAME "/tmp/foo"
int main()
{
int s1;
struct sockaddr_un sa = { AF_UNIX, SOCKNAME };
FILE *f;
char buffer[1024];
s1 = socket(AF_UNIX, SOCK_STREAM, 0);
connect(s1, (struct sockaddr *)&sa, sizeof sa);
f = fdopen(s1, "r+");
while (fgets(buffer, sizeof buffer, f) != NULL)
{
printf("Message received: %s", buffer);
}
fclose(f);
return 0;
}
Note that you should actually create the socket under /var/run/yourappname
rather than in /tmp
.
man 7 unix
is a good resource for further investigation.
You need to read one of the standard text books on the subject - probably Stevens 'UNIX Network Programming, Vol 1, 3rd Edn'.
You have to make a number of decisions, including:
- Does the central server handle all the messages itself, or does it accept a connection from the other process, fork, and delegate the work to its child while it resumes listening for new connections?
- Does the central server need to keep a session running, or does it just respond to 'one (short) message at a time'?
These decisions radically impact the code that's required. If the process is dealing with one short message at a time, it might be appropriate to consider UDP instead of TCP. If the process is dealing with extended conversations with several correspondents and is not forking a child to handle them, then you can consider whether threaded programming is appropriate. If not, you need to consider timeliness and whether the central process can be held up indefinitely.
As indicated in a comment, you also need to consider how a process should deal with the central process not running - and you need to consider how fast that response should be. You also have to protect against the central process being so busy that it looks like it is not running, even though it is running but is just very busy dealing with other connections. How much trouble do you get into if the process that can't connect to the central process tries to kick off a new copy of it.
Based on the info in your question it sounds like you are building a distributed system which has a central message passing bus which components use for communications. I would recommend TCP sockets for the following reasons:
- TCP sockets will give you the flexibility to run the processes either on the same machine or separate machines.
- AFAIK, in the case where both processes are on the same machine, many TCP implementations such as the one on Linux will recognize this and short-circuit the TCP stack making the TCP socket as fast as a local Unix Domain Socket.
- Using TCP you can implement a "TCP Ping" allowing your clients to detect if the central process is running / responsive and to identify that process. You can see an implementation of a "TCP Ping" in the Perl Net::Ping package on CPAN. The networking source is close enough to C that you should be able to understand it. It's basically a non-blocking TCP connect.
- You can setup inetd to automatically start the service whenever a connection attempt is made. Since you probably only want one copy running at a time, you would use the wait parameter. This has the side effect that if the service crashes, the next connect attempt will cause inetd to restart it. See this example.