<?
// +----------------------------------------------------------------------+
// | PHP version 4.3.0 |
// +----------------------------------------------------------------------+
// | Simple class allow to create PHP Server application. |
// | phpServerApp version 0.9 beta |
// +----------------------------------------------------------------------+
// | Authors: Alexander Voytsekhovskyy <[email protected]> |
// +----------------------------------------------------------------------+
define ("MAX_KEEP_ALIVE", 30);
error_reporting(E_ALL);
// Класс, занимающийся обработкой конкретного клиента
class phpServerThread {
var $buffer;
var $lastActivity;
var $socket;
function phpServerThread($socket) {
$this->socket = $socket;
$this->buffer = '';
$this->lastActivity = time();
}
function response($str) {
$mess = "Re: ".$str."\n";
socket_write ($this->socket, $mess, strlen ($mess));
}
function destroy() {
@socket_close($this->socket);
}
}
class phpServerMultiTask {
var $host;
var $port;
var $run;
var $delay;
var $sock;
function phpServerMultiTask($host, $port, $delay = 100000) {
$this->host = $host;
$this->port = $port;
$this->delay = $delay;
$this->run = true;
if (!in_array("pcntl", get_loaded_extensions())) {
echo "--enable--pnctl REQUIRED \n";
}
if (!in_array("sockets", get_loaded_extensions())) {
echo "--enable--sockets REQUIRED \n";
}
error_reporting (E_ALL);
@set_time_limit (0);
$pid = @pcntl_fork();
if ($pid == -1) {
trigger_error ("could not fork child process", E_USER_ERROR);
} else if ($pid) {
exit(0);
}
if (!posix_setsid()) {
trigger_error ("could not detach from terminal", E_USER_ERROR);
}
pcntl_signal(SIGTERM, array($this, "sigHandler"));
pcntl_signal(SIGHUP, array($this, "sigHandler"));
pcntl_signal(SIGUSR1, array($this, "sigHandler"));
if (($this->sock = @socket_create (AF_INET, SOCK_STREAM, 0)) < 0) {
echo "socket_create() failed: reason: " . socket_strerror ($this->sock) . "\n"; exit(1);
}
if (($ret = @socket_bind ($this->sock, $this->host, $this->port)) < 0) {
echo "socket_bind() failed: reason: " . socket_strerror ($ret) . "\n"; exit(1);
}
if (($ret = @socket_listen ($this->sock, 5)) < 0) {
echo "socket_listen() failed: reason: " . socket_strerror ($ret) . "\n"; exit(1);
}
socket_set_nonblock($this->sock);
}
function run() {
$pool = array();
while ($this->run) {
usleep($this->delay);
// Принимаем клиентов, которые стоят в очереди
$currentTime = time();
if (($msgsock = @socket_accept($this->sock))) {
socket_set_nonblock($msgsock);
$pool[] =& new phpServerThread($msgsock);
}
// Обслуживаем клиентов
foreach ($pool as $key => $client) {
// Читаем все что они хотят сказать
if ($tmp = @socket_read($pool[$key]->socket, 1024)) {
$pool[$key]->buffer .= $tmp;
$pool[$key]->lastActivity = $currentTime;
}
// Если в буфере есть законченая фраза - обрабатываем
if ($pos = strrpos($pool[$key]->buffer, "\n")) {
$toSay = substr($pool[$key]->buffer, 0, $pos);
$pool[$key]->response($toSay);
// очищаем буфер
$pool[$key]->buffer = substr($pool[$key]->buffer, $pos + 1);
}
// Закрываем клиентов превысивщих ожидание
if ($currentTime - $pool[$key]->lastActivity > MAX_KEEP_ALIVE) {
$pool[$key]->destroy();
unset($pool[$key]);
}
}
}
echo "Server shutdown \n";
}
function sigHandler ($signo) {
switch($signo) {
case SIGTERM: {
$this->run = 0;
} break;
default: {
echo "Catch signal ".$signo."\n";
} break;
}
}
}
$a = new phpServerMultiTask("localhost", "1128");
$a->run();
?>