Google

Programming with Rudiments using the Base Classes

Using the Daemon Class

Here is some sample code for a daemon process that writes "hello" every 2 seconds. Most daemons don't write anything to the console, but this one does for purposes of demonstration.

#include <rudiments/daemonprocess.h>
#include <iostream.h>
#include <unistd.h>
#include <stdlib.h>

class mydaemon: public daemonprocess {
        public:
                void    init();
                void    loop();
};

void    mydaemon::init() {
        runAsUser("nobody");
        runAsGroup("nobody");
        detach();
}

void    mydaemon::loop() {
        for (;;) {
                cout << "hello" << endl;
                sleep(2);
        }
}

mydaemon        *md;

void    shutDown() {
        delete md;
        exit(0);
}

main() {
        md=new mydaemon;
        md->handleShutDown((void *)shutDown);
        md->init();
        md->loop();
}
Using the Server Socket Class

Daemons are commonly used to serve data to clients over a network. Below is an example combining the daemon and serversocketpool classes. This server receives a string from the client and writes the same string back to the client.

#include <rudiments/daemonprocess.h>
#include <rudiments/serversocketpool.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>

class myserver: public daemonprocess, public serversocketpool {
        public:
                        myserver();
                        ~myserver();
                void    loop();
                void    session();
        private:
                serversocket    inetsocket;
                serversocket    unixsocket;
                genericsocket   *clientsocket;
};

myserver::myserver() : daemonprocess(), serversocketpool() {

        // run as a different user/group
        runAsUser("nobody");
        runAsGroup("nobody");

        // detach from the controlling tty
        detach();

        // open, bind and listen on an inet port and unix socket
        inetsocket.listenOnInetPort(8040,15);
        unixsocket.listenOnUnixPort("/tmp/mysocket",S_IRUSR|S_IWUSR,15);

        // add the sockets to the pool
        addSocket(&inetsocket);
        addSocket(&unixsocket);
}

myserver::~myserver() {
        inetsocket.closeSocket();
        unixsocket.closeSocket();
}

void    myserver::loop() {

        for (;;) {

                // accept connections, with no timeout
                serversocket    *whichsocket;
                waitForClientConnection(-1,-1,&whichsocket,&clientsocket);

                // fork to handle the new connection
                if (!fork()) {

                        // close the duplicated server socket,
                        // engage in a session with the client,
                        // close the client socket and exit
                        whichsocket->stopListening();
                        session();
                        clientsocket->closeSocket();
                        _exit(0);
                }

                // close the client socket, but leave the server
                // socket open to accept more connections
                clientsocket->closeSocket();
        }
}

void    myserver::session() {

        // read a string from the client
        short   bytes;
        readData(&bytes);
        char    *string=new char[bytes+1];
        readData(string,bytes);

        // write the same string back to the client
        writeData(bytes);
        writeData(string,bytes);

        // clean up
        delete[] string;
}


myserver        *ms;

void    shutDown() {
        delete ms;
        exit(0);
}

main() {
        ms=new myserver();
        ms->handleShutDown((void *)shutDown);
        ms->loop();
}

Notice that this server listens on both inet and unix ports. Inet ports allow clients and servers to talk across a network. Unix ports allow clients and servers on the same machine to talk through a pipe. Though clients and servers on the same machine could talk over inet ports, unix ports are much faster and use fewer system resources.

Using the Client Socket Class

Here's the code for a client that can talk to the server above. This client sends a string to the server, reads what the server sends back and prints it out. It does this once over an inet port and once over a unix port.

#include <rudiments/clientsocket.h>
#include <iostream.h>

class myclient: public clientsocket {
        public:
                void    inetSession(char *host, int port, char *message);
                void    unixSession(char *socket, char *message);
        private:
                void    session(char *message);
};

void    myclient::inetSession(char *host, int port, char *message) {
        connectToServer(host,port,0,1);
        session(message);
}

void    myclient::unixSession(char *socket, char *message) {
        connectToServer(socket,0,1);
        session(message);
}

void    myclient::session(char *message) {

        // write a message to the server
        writeData((short)strlen(message));
        writeData(message);

        // read a message back from the server
        short   bytes;
        readData(&bytes);
        char    *string=new char[bytes+1];
        readData(string,bytes);

        // write out the message we got from the server
        cout << string << endl;

        // clean up
        delete[] string;
}

main() {

        // declare an instance of our client
        myclient        mc;

        // connect to a known inet host/port and unix socket and 
        // send a message over each connection
        mc.inetSession("localhost",8040,"message over inet port"); 
        mc.unixSession("/tmp/mysocket","message over unix port");
}
Using the Complex Socket Initialization methods of the Server Class

Setting up a server to listen on a socket is actually a multi-step process. The listenOnInetPort(), listenOnUnixPort() and listenOnPorts() methods simplify this process but some applications may require a more flexible interface. If you need to set socket options or perform additional actions between the steps of socket initialization, you can use the Complex Socket Inititalization methods of the server class.

Below is an alternative implementation of the myserver constructor in which some socket options are set.

myserver::myserver() : daemonprocess(), serversocketpool() {

        // run as a different user/group
        runAsUser("nobody");
        runAsGroup("nobody");

        // detach from the controlling tty
        detach();

        // initialize the ports
        inetsocket.initInetPort(8040);
        unixsocket.initUnixPort("/tmp/mysocket",S_IRUSR|S_IWUSR,15);

        // set some socket options
        inetsocket.lingerOnClose(10);
        inetsocket.reuseAddresses();
        unixsocket.lingerOnClose(10);

        // bind to the ports
        inetsocket.bindSocket();
        unixsocket.bindSocket();

        // listen on the ports
        inetsocket.listenForClientConnection(15);
        unixsocket.listenForClientConnection(15);

        // add sockets to the pool
        addSocket(&inetsocket);
        addSocket(&unixsocket);
}