GPS-logger/server1.php

Материал из wiki.nntc.nnov.ru
Версия от 12:42, 11 февраля 2009; Gumanoed (обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к навигации Перейти к поиску
#!/usr/bin/php -q
<?php // Simple PHP TCP server
// -------------------------------------------------
// Простейший tcp-сервер на неблокирующих сокетах
// требуется наличие модулей sockets и pcntl
// -------------------------------------------------

// Инициализация сокета и начало его прослушивания
Function init_socket ($ip, $port)
{
	// создаем новый сокет
	if (($sockfd = socket_create (AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
		return -1;
	// устанавливаем полезную опцию
	socket_get_option ($sockfd, SOL_SOCKET, SO_REUSEADDR);
	// привязываем сокет к IP и порту
	if (socket_bind ($sockfd, $ip, $port) < 0)
		return -1;
	// начинаем слушать сокет
	if (socket_listen ($sockfd) < 0)
		return -1;
	return $sockfd;
}

// Прием нового соединения
Function accept_connection ($ls)
{
	GLOBAL $connections;

	// принимаем новое соединение
	$s = socket_accept ($ls);
	socket_getpeername ($s, $addr);
	// делаем сокет неблокирующим дабы процесс не вис на чтении из него
	socket_set_nonblock ($s);
	// записываем дескриптор сокета в массив. FIXME: количество соединений надо ограничивать
	$connections[] = $s;
	print "DEBUG: Connection from $addr accepted ".	strftime ("%R:%S", time ()) ."\n";
}
$db_ident = NULL;
$db_descript = "host=localhost dbname=postgres port=5432 user=postgres password=123321";

Function	db_write ($arr_dat)
{
	GLOBAL	$db_descript,	$db_ident;

	if (! $db_ident) {
		if (! ($db_ident = pg_connect ($db_descript))) {
			print "ERROR: pg_connect: Connection from $db_descript";
			return	-1;
		}
	}
	$query = "INSERT INTO granit (stationid,pos_tstamp,londegrees,latdegrees,lonminutes,latminutes,speedknots,course,track) ".
		sprintf ("VALUES (%d,%d, %d,%d,%d,%d, %d,%d,%d)", $arr_dat ['v2'], $arr_dat ['time'],
			$arr_dat ['grad2'], $arr_dat ['grad1'], $arr_dat ['seck2'], $arr_dat ['seck1'],
			$arr_dat ['xx1'], $arr_dat ['xx2'], $arr_dat ['track']);
//	echo	"$query\n";
	return	pg_query ($db_ident, $query);
}
// Чтение и обработка данных
Function read_socket ($rs)
{
	$data = socket_read ($rs, 1024, PHP_BINARY_READ);
	if ($data === false || $data == "") {
		printf ("DEBUG: socket_read: %s\n", socket_strerror(socket_last_error()));
		return -1;
	}
	// FIXME: сюда можно вставить вызов обработчика данных

	$pmark = substr ($data, 0, 6);
	if ("+RRCB~" == $pmark) {
		$arr_dat = unpack ("v2v/Vtime/CE/CSP/C2grad/v2seck/C2xx/strack/C4", substr ($data, 6));
		db_write ($arr_dat);
		// квитация приема
		$abuff = "BB+UGRC~". pack ("vVv", 6, $arr_dat ['time'], $arr_dat ['v2']) ."\r\n";
		socket_write  ($rs, $abuff);
	} else if ("+DDAT~" == $pmark) {
		$arr_dat = unpack ("v2v/Cblock/Cnform/Cnpack", substr ($data, 6));
		print_r ($arr_dat);
		$abuff = "+DDAT~";
		$abuff = pack("vvCCv", $arr_dat['v1'], $arr_dat['v2'], $arr_dat['nform'], $arr_dat['block'], $arr_dat['npack'])."\r\n";
		print (bin2hex ($abuff));
	//	socket_write  ($rs, $abuff);
	}
	return 0;
}

// Закрытие соединения
Function close_connection ($rs)
{
	GLOBAL $connections;

	socket_getpeername ($rs, $addr);
	// находим в массиве соединений нужное и закрываем его
	$k = array_search ($rs, $connections);
	unset ($connections[$k]);
	socket_close ($rs);
	print "DEBUG: Connection from $addr closed\n";
}

// Обработчик сигнала завершения работы
Function catch_interrupt ()
{
	GLOBAL $alive;
	
	print "DEBUG: Завершение работы\n";
	$alive = 0;
}

// main ================================================================

//$ip = "127.0.0.1";  // слушаемый IP адрес
$ip =	"192.168.10.12";
$port = "5555";     // слушаемый порт

$connections = array(); // массив активных соединений
$alive = 1;             // спецфлаг

// разрешаем обработку сигналов и инсталируем обработчик сигнала SIGINT (Ctrl-C)
declare (ticks = 1);
pcntl_signal (SIGINT, "catch_interrupt");

if (($ls = init_socket ($ip, $port)) < 0) {
	printf ("FATAL: %s\n", socket_strerror(socket_last_error()));
	exit();
}

// основной цикл
// крутимся пока не поступит сигнал завершения работы
while ($alive) {
	// определяем массив слушаемых и обрабатываемых сокетов
	$reads = array ($ls);                            // первый дескриптор - слушаемый сокет
	foreach ($connections as $c) {                   // остальные - активные соединения
		$reads[] = $c;
	}
	// ждем доступности данных на сокетах
	// $reads будет содержать _только_ дескрипторы, готовые для чтения
	$n = socket_select ($reads, $write = NULL, $except = NULL, 0);

	if ($n > 0) {                                     // один или более сокетов содержат данные для чтения
		if (in_array ($ls, $reads))	{         // получен новый запрос на соединение?
			$s = accept_connection ($ls);     // принимаем новое соединение
			$k = array_search ($ls, $reads);
			unset ($reads[$k]);               // удаляем дескриптор слушаемого сокета из массива
		}
		foreach ($reads as $rs) {                 // обрабатываем данные от сокетов (если таковые есть)
			if (read_socket ($rs) < 0) {      // производим чтение и обработку данных
				close_connection ($rs);   // при возникновении ошибки закрываем соединение
			}
		}
	}
	unset ($reads);
}
socket_close ($ls);
?>