Re: communication with a daemon

From: Larry I Smith (larryXiXsmith_at_verizon.net)
Date: 08/06/04


Date: Thu, 05 Aug 2004 23:59:08 GMT

Tobias Wagner wrote:
> Hi,
> I want to write a daemon and a client (in C). The client is started several
> times, the daemon only once. The client is structured as follows:
>
> if daemon is not running:
> start daemon
> tell daemon to increase a certain reference counter
> ask daemon for an integer
> do_something
> tell the daemon to decrease the reference counter
> exit
>
> Daemon and client live on the same host. How can I do this in a simple
> manner?
>

Here's a working example.

It's just a skeleton and could be enhanced significantly,
but maybe it'll get you started.

Regards,
Larry

-- 
Anti-spam address, change each 'X' to '.' to reply directly.
------------------------------------------
// daemon.cpp
// parent/child socket test program.
// compile with:  g++ -o daemon daemon.cpp
#include <errno.h>       // perror
#include <sys/types.h>   // socket stuff, fork
#include <sys/socket.h>  // socket stuff
#include <sys/wait.h>    // waitpid
#include <unistd.h>      // read, write, fork
#include <iostream>  // std::cout, std::endl, etc
#include <string>    // std::string::*
// read bytes from file/socket handle 'fd' and put them into
// string 'str'.  stop reading when a newline or read error is
// encountered.  the trailing newline is NOT put into 'str'.
// (i.e. a newline denotes the end of a discrete message).
// returns true on success, false on read error.
bool
read_line(int fd, std::string & str)
{
   char ch;
   str.erase();  // erase any existing content in 'str'
   // we don't know how much is coming, so we read
   // one char at a time.  we quit reading on error
   // or when a newline is read.
   while (1 == read(fd, &ch, 1))
   {
     if ('\n' == ch)
       return true;  // success
     // append one copy of the byte read to 'str'.
     // 'str' will auto-expand (in increments) as
     // req'd.
     str.append(1, ch);
   }
   return false;  // read error
}
// write string 'str' to file/socket handle 'fd'.
// if 'str' does not end with a newline, one is appended to the
// output (i.e. a newline denotes the end of a discrete message).
// returns true on success, false on write error.
bool
write_line(int fd, const std::string & str)
{
   std::string::size_type x;
   std::string::size_type len;
   len = str.length();  // get the length of 'str'
   // write each char individually.
   // C++ strings may contain any amount of arbitrary
   // binary data.  if we used the 'str.c_str()' method
   // to create a nul-terminated 'C' string from 'str',
   // then we might not get all of 'str' - if it contained
   // embedded '\0' bytes.
   for (x = 0; x < len; x++)
   {
     if (1 != write(fd, &str[x], 1))
       return false;  // return false on error
   }
   // if 'str' did not end with a newline, append one
   // to the output
   if (len > 0 && '\n' != str[len - 1])
     write(fd, "\n", 1);
   return true;  // success
}
int
main (int argc, char * argv[])
{
   pid_t child;
   int sv[2];
   // make a pair of connected sockets in sv[].
   // the parent process will read/write using sv[0].
   // the child process will read/write using sv[1].
   if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv))
   {
     perror("socketpair(sv) failed");
     return 1;
   }
   child = fork();  // start the child process
   if (child < 0)
   {
     perror("fork() failed");
     return 2;
   }
   if (0 == child)
   { // I am the child process.  I will read/write using sv[1].
     close(sv[0]);  // close the socket handle not used by me
     // create a C++ string 'str' with the specified
     // initial content.
     std::string str("child says hello");
     // send a line to my parent.
     // Note that we could have used:
     //   write_line(sv[1], "child says hello");
     // and the compiler would convert the quoted
     // string to a C++ std::string for us.
     write_line(sv[1], str);
     // read a line from my parent into 'str', then print it
     read_line(sv[1], str);
     std::cout << str << std::endl;
     close(sv[1]);  // close my socket handle
   }
   else
   { // I am the parent process.  I will read/write using sv[0].
     std::string str;
     close(sv[1]);  // close the socket handle not used by me
     // read a line from the child into 'str', then print it
     read_line(sv[0], str);
     std::cout << str << std::endl;
     // reset the content of 'str'
     str = "parent says hello";
     // send a line to the child.
     // Note that we could have used a quoted string
     // or a 'char *' variable in place of 'str'
     write_line(sv[0], str);
     close (sv[0]);  // close my socket handle
   } // end if
   // if we started a child ok, free its resources
   if (child > 0)
     waitpid(child, NULL, 0);
   return 0;
}


Relevant Pages

  • Re: communication with a daemon - Example Code
    ... > I want to write a daemon and a client. ... the trailing newline is NOT put into 'str'. ...
    (comp.os.linux.development.apps)
  • Re: postfix INST_BASE option
    ... system boot time. ... sendmaildaemon to listen for incoming network mail. ... This does not preclude a sendmaildaemon listening on ...
    (freebsd-questions)
  • Socket writing limit
    ... I am doing some socket programming in ruby and I was wondering if ... there was a limit to the amount of data you should write to a socket ... str += a.gets ...
    (comp.lang.ruby)