Показать сообщение отдельно

[php] Сокеты для новчиков
  #8  
Старый 12.01.2009, 02:17
Design_Corn
Новичок
Регистрация: 15.07.2008
Сообщений: 10
Провел на форуме:
31746

Репутация: 9
Thumbs up [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 код:
<?php 
    
print "php_sockets.dll - "
    if(
extension_loaded('sockets')) 
    { 
        print 
"loaded"
    } else { 
        print 
"not loaded"
    } 
?>
Если у вас не подключена php_sockets.dll то смысла читать ниже - нету.

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

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

Приступим к кодингу, думаю вопросов лишний не возникнет так-как код хорошо комментирован.

PHP код:
<?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:http 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:https 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
Хай!


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