WebScript.Ru
C:\   главная  ::   о сайте  ::  каталог скриптов  ::  гнездо  ::  форум  ::   авторам  :: Новостройки ::   ХОСТИНГ  ::

|| разделы::
|| поиск по сайту::

|| реклама::
|| новости почтой::
Рассылки Subscribe.Ru ::



Новости сайта WebScript.Ru
Популярные статьи

Hot 5 Stories

|| рекомендуем::




Демон на PHP


Прислал: Олег Крайнов [ 29.08.2006 @ 13:21 ]
Раздел:: [ Статьи по PHP ]


Введение

Приветствую, и сразу начнём ;). В этой статье мы напишем простенький демон на php, но для начала нам надо ознакомиться с сокетами и базовыми знаниями IP-протокола. Итак что же представляет собой сокет? Сокет - это программный интерфейс, предназначенный для передачи данных между приложениями на сетевом уровне. В PHP есть функции работающие с сокетами на уровне IP-протокола. Это гораздо более низкий уровень по сранению с уровнем, на котором работают функция fsockopen и потоки. В этой статье я научу тех, кто пока ещё не умеет работать с этими функциями. Работать будем в режиме CLI (command-line interface) т.е в коммандной строке, а не через браузер.

Что для этого нам понадобиться:

PHP интерпретатор - ну куда ж без него :). Кстати вебсервер apache или какой другой нам не понадобиться!
php_sockets.dll - библиотека (должна быть именно под вашу версию PHP)

Подключение модуля sockets

Для начала нам нужно проверить подключена ли у нас либа php_sockets.dll. Смотрим в php.ini (eg. %WINDIR%\php.ini) и смотрим в раздел "Dynamic Extensions". Там должна быть раскоментирована строчка "extension=php_sockets.dll". Далее смотрим директиву "extension_dir" она должна указывать на путь где лежат все динамически подключаемые модули. Лезем туда и смотрим присутсвует ли библиотека там. Если да то читаем дальше, если нет то скачайте модуль под вашу версию php и положите в эту директорию. Теперь проверим работает ли она. Существует несколько способов проверить это.
  • Из командной строки запустить php.exe с ключом -m. (php.exe -m);
  • Скрипт запустить и посмотреть существует ли раздел "sockets";
  • На хостинге (где у вас нету доступа к php.ini и ssh) можно проверить скриптом:
    <?php
        
    print "php_sockets.dll - ";
        if(
    extension_loaded('sockets'))
        {
            print 
    "loaded";
        } else {
            print 
    "not loaded";
        }
    ?>
Если у вас не подключена php_sockets.dll то смысла читать ниже - нету.

Пишем простой демон

Итак напишем простой демон который будет при подключении выводить какую нибудь рандомную надпись из файла. Принцип сервера-скрипта будет простой:
  • Создаём TCP сокет;
  • Привязываем сокет к определённому адресу и порту;
  • Слушаем сокет;
  • Клиент конектится, выводим рандомную фразу. Ждём до того пока не он не пошлёт комманду "bye".
Приступим к кодингу, думаю вопросов лишний не возникнет так-как код хорошо комментирован.

<?php

// Файл содержащий рандомные фразы разделённых "\r\n" (каждая фраза на новой строке)
$FileName "file.txt";

$FHandle file($FileName);

// Работаем вечно (выдаёт ошибку при safe_mode=1, @ для подавления)
@set_time_limit(0);

// Создание сокета TCP: resource socket_create(1, 2, 3);
// 1) AF_INET - семейство протокола или домен. Для соединений
//              осуществляемых через интернет используется AF_INET,
//              для UNIX используется AF_Unix (но об этом позже)
// 2) SOCK_STREAM - обычно используется для TCP (SOCK_DGRAM - UDP)
// 3) Протокол для TCP - SOL_TCP, UDP - SOL_UDP
// возвращает дескриптор сокета
if(($socket socket_create(AF_INETSOCK_STREAMSOL_TCP)) < 0)
{
    print(
"Невозможно создать сокет: " .
        
socket_strerror(socket_last_error()) . "\n");
}

// Биндим сокет на определённый адрес и порт: boolean socket_bind(1, 2, 3);
// 1) Дескриптор сокета
// 2) IP адрес, или путь до сокета в Unix
// 3) Порт (в нашем случае порт = 666)
if(($error socket_bind($socket"127.0.0.1"666)) < 0)
{
    print(
"Невозможно привязать сокет :" .
        
socket_strerror(socket_last_error()). "\n");
}

// Прослушиваем сокет: boolean socket_listen(1, 2);
// 1) дескриптор сокета
// backlog размер очереди запрросов ожидающих соединения
if(($error socket_listen($socket5)) < 0)
{
    print(
"Невозможно прослушать сокет: " .
        
socket_strerror(socket_last_error()) . "\n");
}

// Слушаем вечно ;)
while(TRUE)
{
    
// ожидаем соединение
    // socket_accept(дескрипток сокета) - принимает входящие соединение и делает на скрипт сервером.
    
if(($accept socket_accept($socket)) < 0)
    {
        print(
"Ошибка при чтении: " 
            
socket_strerror($message) . "\n");
        break;
    }
    
    
// выводим рандомную строку из файла
    
socket_write($acceptgetRandMessage($FHandle));
    print(
date("Y-m-d H:i:s"time())." STATUS: client connected.\n");
    
ob_flush();
    while(
TRUE)
    {
        
// Считываем заданное количество байт из указанного сокета
        
if(FALSE === ($line = @socket_read($accept2048)))
        {
            print(
"Невозможно прослушать сокет: " 
                
socket_strerror(socket_last_error()) . "\n");
            break 
2;
        }
        
        switch(
strtolower(trim($line)))
        {
            case 
"bye"  :
                print(
date("Y-m-d H:i:s"time())." STATUS: client close connection.\n");
                break 
2;
            break;
            case 
"more" :
                
// записываем данные из буфера в сокет
                
if(!@socket_write($acceptgetRandMessage($FHandle)."\r\n"))
                {
                    print(
date("Y-m-d H:i:s"time())." STATUS: client close connection.\n");
                    break 
2;
                }
            break;
            default :
                
// записываем данные из буфера в сокет
                
if(!@socket_write($accept"Unknown command, 'bye' to exit.\r\n"))
                {
                    print(
date("Y-m-d H:i:s"time())." STATUS: client close connection.\n");
                    break 
2;
                }
            break;
        }
        print(
date("Y-m-d H:i:s"time()). " READ: ".$line."\n");
        
ob_flush();
    }
    
// закрываем соединение
    
socket_close($accept);
}
// Закрываем сокет
socket_close($socket);

function 
getRandMessage(&$Array)
{
    return (
$Array[rand(0count($Array)-1)]);
}

?>


Думаю многое понятно. Назовём его например socket.php. Теперь запускаем наш скрипт-сервер командой: php socket.php в командной строке.

Тестируем приложение

Для начала выведем все активные TCP соединения
C:\Documents and Settings\t3rr4n>netstat -o -a -p TCP

Активные подключения

Имя    Локальный адрес        Внешний адрес          Состояние       PID
TCP    work-012f823131:http2   work-012f823131:0      LISTENING       2112
TCP    work-012f823131:epmap  work-012f823131:0      LISTENING       1188
TCP    work-012f823131:microsoft-ds  work-012f823131:0      LISTENING       4
TCP    work-012f823131:doom   work-012f823131:0      LISTENING       1552 <-- это мы висим
TCP    work-012f823131:1029   work-012f823131:0      LISTENING       884
TCP    work-012f823131:1048   work-012f823131:0      LISTENING       2032
TCP    work-012f823131:3306   work-012f823131:0      LISTENING       2444
TCP    work-012f823131:1046   205.188.8.253:http2s    ESTABLISHED     2032
TCP    work-012f823131:netbios-ssn  work-012f823131:0      LISTENING       4
DOOM это ассоциация с портом "666" (в игре "DooM" используется именно этот порт ;) ). Т.е наше приложение ожидает подключение. Проверим что это за приложение запущено по PID 1552:
C:\Documents and Settings\t3rr4n>tasklist | find "1552"
php.exe                     1552 Console                 0     4а064 КБ

C:\Documents and Settings\t3rr4n>tasklist | find "php.exe"
php.exe                     2716 Console                 0       812 КБ
php.exe                     1552 Console                 0     4а064 КБ
Теперь попробуем подключиться и посылать комманды (на рис. всё понятно). Я использовал известную программу NetCat, вы можете Telnet но лучше NC:
C:\Documents and Settings\t3rr4n>nc 127.0.0.1 666
Хай!

Ну на этом всё. Теперь вы можете тоже попробовать написать какой-нибудь демон, может быть бота или ещё что-то более интересное, ведь большинство приложений в сети используют именно сокеты, так что это основа основ. Кстати в большинстве языков программирования поддерживаются сокеты и принцип работы с ними везде одинаковый. Который я описал выше. В следующей статья я расскажу как работать с сокетами под Unix-like системы (это намного интереснее чем под win32). Ждите...

Много другой информации о программировании на PHP (и не только), можно прочитать у нас на сайте. © Lock-Team.RU - Проект по информационной безопасности в сети Интернет.


 :::::  dekkard пишет 07.10.2008 @ 13:55 
классная статья! как раз то, что нужно для тех, кто еще с сокетами не связывался.
но баги видны невооруженным глазом:
какой смысл сливать буфер вывода, если его даже включили?

решение - поставить
ob_start();
где-нибудь в начале файла и, по рекомендации php.net, вызывать
flush();
сразу после ob_flush();

спасибо
 :::::  acid пишет 17.05.2010 @ 14:32 
Выдает ошибку когда закрываешь содинение принудительно :( Скажите как определить ip адрес подключившегося к порту?
 :::::  Александр пишет 05.06.2010 @ 23:13 
Я бы тоже хотел это узнать... ?
 :::::  Тесте пишет 19.02.2011 @ 21:10 
Function getRealIpAddr() {
If (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
else If (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
Else {
$ip = $_SERVER['REMOTE_ADDR'];
}

Return $ip;
}
Имя:
Email:
URL

Введите сумму двух чисел девять и одинн (девять+одинн=?)
Запомнить мою информацию

* Html запрещен* Ваш E-mail опубликован не будет.

Copyright © 2000-2001 WebScript.Ru nas@webscript.ru
Design © 2001 by Parallax Design Studio (aka Spectator.ru)
Все торговые марки и авторские права на эту страницу принадлежат их соответствующим владельцам.
Сгенерировано за: 0.0182931