So I just developed my server listening on a port, made it able to receive multiple client connections and daemonized it: now I can start, stop, restart, ps au -> kill it, cat a logfile, have it ready on system reboot and everything I would expect from a regularly compiled application written in C++.
BUT... I can modify it whenever I like without recompiling it, it natively talks with its companion website, etc etc.
I tried mpdaemon and several other solutions... I already tested them all for you: at the end, nothing better than the easy way.
Tested with CentOS but you can easily apply it to Ubuntu.
PHP SERVER:
#!/usr/bin/php
<?
####### PHP ERROR HANDLING #######
if (function_exists('ini_set')) {
ini_set('display_errors', '1');
ini_set('error_reporting', '7');
ini_set('max_execution_time',0);// INFINITE
ini_set("memory_limit", "300M");
} else
error_reporting(E_ALL & ~E_NOTICE);
/*----------------------------------*/
####### INITIALIZE VARIABLES #######
date_default_timezone_set("Europe/Rome");
$client_socks = array(); //WILL CONTAIN ALL CLIENT SOCKETS
$client_data = array(); //WILL CONTAIN CLIENTS IP:PORT just for debug & compliance
$port = 4000;
$log = '/var/log/myDAEMON.log';
####### INCLUDE MYSQL AND OTHER CONFIGS #######
include("config.php");
/*----------------------------------*/
####### MYSQL CONNECTION #######
mysql_connect($dbhost, $dbuser, $dbpass) or die(mysql_error());
mysql_select_db($dbname) or die(mysql_error());
mysql_query("SET CHARACTER SET utf8");
/*----------------------------------*/
//init socket
$socket = stream_socket_server("tcp://0.0.0.0:".$port, $errno, $errorMessage) or die("Could not bind to socket: $errorMessage");
//fork the process to work in a daemonized environment
file_put_contents($log, date("d.m.y H:i",time())." starting up.\n", FILE_APPEND);
$pid = pcntl_fork();
if($pid == -1) {
file_put_contents($log, "Error: could not daemonize process.\n", FILE_APPEND);
return 1; //error
} else if($pid) {
return 0; //success
} else {
##############################
//THIS IS WHERE YOU SHOULD PLACE ANY MYSQL CONNECTION
//since it's after the fork (it will receive a new PID)
//else you will get crazy debugging the 2006 error "mysql server has gone"
mysql_connect($dbhost, $dbuser, $dbpass) or die(mysql_error());
mysql_select_db($dbname) or die(mysql_error());
mysql_query("SET CHARACTER SET utf8");
##############################
//the main process
while(true) {
//prepare readable sockets array
$read_socks = $client_socks; //will be filled below and then looped
$read_socks[] = $socket; //server starts here
//select all sockets one by one and apply long timeout
stream_select ( $read_socks, $write, $except, 300000 ) or die('something went wrong while selecting a socket');
//check for new connected clients
if (in_array($socket, $read_socks)) {
$new_client = stream_socket_accept($socket);
if ($new_client) {
//remote client info, ip, port number
$client_info = strtolower( stream_socket_get_name($new_client, true) );
echo "Connection accepted from " . $clientinfo . "\n";
//add it in array client_socks
$client_socks[] = $new_client;
$client_data[] = $client_info;
echo "Now there are total ". count($client_socks) . " clients.\n";
}
//clean read_socks
unset($read_socks[ array_search($socket, $read_socks) ]);
}
//messagges from the clients
foreach($read_socks as $sock) {
//whom client speaking to?
$clientkey = array_search($sock, $client_socks);
//here I read the stream
$data = fread($sock, 128);
if(!$data) {
unset($client_socks[ $clientkey ]);
unset($client_data[ $clientkey ]);
@fclose($sock);
echo "A client disconnected. Now there are total ". count($client_socks) . " clients.\n";
continue;
}
//PARSE DATA AND PUT IN MYSQL
[W H A T E V E R Y O U L I K E]
//FILL DB
$query = "INSERT INTO db SET everything you want";
$sql = mysql_query($query) or die(mysql_error());
}
}
}
?>
If you put some echos, please consider that I did in 2 ways:
- append to logfile
- echo out
Where you see that I echoed out, consider that this will echo in the shell and it's perfect for live debug as you start the socket. But in a production environment you would append to the logfile instead.
BASH SCRIPT /etc/init.d (copy e.g. crond and you will inherit the right permission, then write over this):
#!/bin/bash
#
# /etc/init.d/myDAEMON
#
# Starts myDAEMON
#
# chkconfig: 345 95 5
# description: Runs the myDAEMON daemon.
# processname: myDAEMON
# Source function library.
. /etc/init.d/functions
#startup values
log=/var/log/myDAEMON.log
#verify that the executable exists
test -x /var/www/html/myDAEMON.php || exit 0RETVAL=0
#
# Set prog, proc and bin variables.
#
prog="myDAEMON"
proc=/var/lock/subsys/myDAEMON
bin=/var/www/html/myDAEMON.php
start() {
# Check if myDAEMON is already running
if [ ! -f $proc ]; then
echo -n $"Starting $prog: "
daemon $bin --log=$log
RETVAL=$?
[ $RETVAL -eq 0 ] && touch $proc
echo
fi
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc $bin
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f $proc
echo
return $RETVAL
}
restart() {
stop
start
}
reload() {
restart
}
status_at() {
status $bin
}
case "$1" in
start)
start
;;
stop)
stop
;;
reload|restart)
restart
;;
condrestart)
if [ -f $proc ]; then
restart
fi
;;
status)
status_at
;;
*)
echo $"Usage: $0 {start|stop|restart|condrestart|status}"
exit 1
esac
exit $?
exit $RETVAL
Now you can type from the shell
service myDAEMON start
service myDAEMON stop
service myDAEMON restart
chkconfig --add myDAEMON
which means that you can start, stop, restart and start on launch, like you usually do for every other binary... ah, WHAT A FUN!!!!