GPS-logger/server1.php
Версия от 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); ?>