Whats The Easiest Way to Send Messages to My Linux Daemon App

Whats the easiest way to send messages to my linux daemon app?

Whats is the standard way apps which run on the command line communicate to its daemon process?

There are a number of ways to do this:

Dropboxes and Signals

A variety of locations are being used to store "pid files" containing a daemon's process ID number: /var/run/<app>/<app>.pid, /var/run/<app>.pid (thanks @Adam Katz for edit), /run/<app>/<app>.pid, /run/<app>.pid, (see Askubuntu: Why has /var/run been migrated to /run?).

When the pid of the daemon process is known, a command line program (which is running as a separate process) could communicate with the daemon in these ways:

  1. Writing something into a prearranged place. This could be an ordinary file, a database table, or any convenient spot readable by the server.
  2. Sending a signal to the daemon. The common way to do this locally is with the kill system call, int kill(pid_t pid, int sig);.

Old School Example: The server multiplexing daemon xinetd would reread its configuration file after receiving SIGHUP.

The send-a-signal methodology has been made redundant by the inotify API whereby a process can subscribe to file system events. Using signals is useful when you don't want the daemon to act on every file change, since not every change may leave the file in a valid state, as when modifying a system config file.

FIFO or Pipe

A fifo or pipe is simply a special file that blocks processes reading it until some other process has written to it. You can make a named pipe/fifo in the file system with mkfifo. The only tricky thing about this is that pipes should generally be opened unbuffered, e.g. with open() as opposed to fopen(). Scripting languages sometimes make a facility for pipe-friendly reading/writing: Perl had a line-buffered mode set with $|=1 that was useful for pipes.

More commonly, you see anonymous pipes all the time on the command line with the | symbol separating commands which are executed as separate processes.

Sockets

What about something newer, like mySQL? The mysql database system consists of a command line client mysql and a server mysqld and may also serve other clients either on the local machine or over the internet.

mySQL communicates using a socket. The server listens to a socket for connections, and forks new processes giving a socket descriptor to the child for processing. When the child is done processing, it can exit.

There are UNIX sockets and Internet sockets, with different namespaces. One guide to programming sockets in C on Linux would be the sockets chapter of the The GNU C Library manual.

No-wait I/O is an alternative to forking off processes. This is done in C with the select() system call, which allows having a process wait for an event on one or more files, including sockets, or a timeout. The GNU C Library docs includes a no-wait I/O socket server example

NodeJS is a server for the Javascript language, written as a single-threaded server using no-wait I/O, and shows that these techniques are still relevant in modern systems.

"Callbacks"

I'm assuming its impossible to ask linux to call a callback when I type in myapp foo bar?

Maybe. But it might be too much work to be worth the trouble.

When you type myapp foo bar into "Linux", that's not Linux, you are typing that into your command shell, which is a program running in its own process separate from everything else.

So, unless the functionality you want is built into the command shell, there is normally no way for that command shell to send messages to your other program without starting a new process.

The default command shell for many (but not all) Linux systems is /bin/bash. To communicate with a daemon that listens to sockets from bash we would need a socket opening procedure in bash. And, sure enough, it exists!

One can listen to a socket in bash. This is the basis for a daemon:

From: Simple Socket Server in Bash? answer by dtmilano:

Q: I have a simple debugging solution which writes things to 127.0.0.1:4444 and I'd like to be able to simply bind up a port from bash and print everything that comes across. Is there an easy way to do this?

A:

$ exec 3<>/dev/tcp/127.0.0.1/4444

$ cat <&3

One can also open a socket from bash to a remote process, i.e. communicate with a a daemon:

From: TCP connection, bash only

we learn exec 5<>"/dev/tcp/${SERVER}/${PORT}" redirects a TCP link to file descriptor 5 for both input and output.

Not all bash programs are compiled with TCP support. It is apparently Linux-distribution dependent. At least according to a comment on this answer by William Pursell

There are other shells besides bash. Many shells were developed back in the *nix days. ksh Korn shell. csh C-shell. Bourne shell sh. Ash shell. Wikipedia keeps a list of shells. And these shells each have their own advantages and disadvantages and are not entirely compatible with each other's formatting!

Fast forward about 30 years, and there aren't so many in common use now.

But an important feature exists here: each user can choose his own login shell. See the chsh command.

So where I am going here is that if bash doesn't support the communications you need to do, you could set up a command shell where special messages can be sent without opening a new process. This might save you a few milliseconds, and usually isn't worth it. But nothing is stopping you. You might even set up an ipython command shell, as suggested in https://stackoverflow.com/a/209670/103081, and python can import most anything you need to do socket communications with your specialized daemon.

Is it possible to pass input to a running service or daemon?

On Linux, all running processes have a special directory under /proc containing information and hooks into the process. Each subdirectory of /proc is the PID of a running process. So if you know the PID of a particular process you can get information about it. E.g.:

$ sleep 100 & ls /proc/$!
...
cmdline
...
cwd
environ
exe
fd
fdinfo
...
status
...

Of note is the fd directory, which contains all the file descriptors associated with the process. 0, 1, and 2 exist for (almost?) all processes, and 0 is the default stdin. So writing to /proc/$PID/fd/0 will write to that process' stdin.

A more robust alternative is to set up a named pipe connected to your process' stdin; then you can write to that pipe and the process will read it without needing to rely on the /proc file system.

See also Writing to stdin of background process on ServerFault.

Send message to a Python daemon script from another init script without using IPC

You can use named pipe. First you instantiate named pipe using mkfifo, which creates file representing the pipe. Then you open this file in both scripts - in one for writing and in another one for reading. After that you can just write some data to the opened file in one script and read it back in another.

Note that pipes are unidirectional, which means that if you need to communicate in both directions, then you need to create two pipes.

A simple way to send mails from a C application on Unix

Here's a nice SMTP library, libESMTP

Custom Linux service status message using Java Service Wrapper

I got a half-solution. Inspecting the wrapper script code, as suggested by @Naytzyrhc, I found that the wrapper lib reads 3 files to create the status message:

  1. bin/my-app.pid to print the PID of the running process;
  2. bin/my-app.status to print the status of the wrapper itself;
  3. bin/my-app.java.status to print the status of the wrapped application.

So, in the application code, to override the status message, just write the message in the my-app.java.status file.

There's only one gotcha: if the status message contains line breaks, the service my-app status doesn't print them, because it uses the echo command (as stated in this question Capturing multiple line output into a Bash variable). To solve this problem, just change the line from:

eval echo `gettext '$APP_LONG_NAME is running: PID:$pid, Wrapper:$STATUS, Java:$JAVASTATUS'`

to:

eval echo `gettext '$APP_LONG_NAME is running: PID:$pid, Wrapper:$STATUS, Java:"$JAVASTATUS"'`

(Using double quotes on $JAVASTATUS).

This is a half-solution because it doesn't fire an event to the running application, as I wanted. But it works for customizing the status message: it depends on the application how often the message is updated.



Related Topics



Leave a reply



Submit