Сокеты в Perl и PHP Сокеты в Perl Сокеты являются «конечными пунктами» в процессе обмена данными. Одни типы сокетов обеспечивают надежный обмен данными, другие почти ничего не гарантируют, зато обеспечивают низкий расход системных ресурсов. Обмен данными через сокеты может осуществляться на одном компьютере или через Интернет. Типы сокетов Рассмотрим два самых распространенных типа сокетов: потоковые и датаграммные. Потоковые сокеты обеспечивают двусторонние, последовательные и надежные коммуникации. Датаграммные сокеты не обеспечивают последовательную, надежную доставку, но они гарантируют, что в процессе чтения сохранятся границы сообщений. Типы сокетов Сокеты делятся по областям: сокеты Интернета и сокеты UNIX. Имя сокета Интернета содержит две составляющие: хост (IP-адрес) и номер порта. В мире UNIX сокеты представляют собой файлы. Кроме области и типа с сокетом также ассоциируется определенный протокол. Протоколы не имеют особого значения для рядового программиста, поскольку для конкретного сочетания области и типа сокета редко используется более одного протокола. Типы сокетов Области и типы обычно идентифицируются числовыми константами (которые возвращаются функциями, экспортируемыми модулями Socket и IO::Socket). Потоковые сокеты имеют тип SOCK_STREAM, а датаграммные – SOCK_DGRAM. Области Интернета соответствует константа PF_INET, а области UNIX – константа PF_UNIX. Типы сокетов Имена протоколов (например, TCP или UDP) тоже соответствуют числам, используемым операционной системой. Встроенная функция getprotobyname возвращает номер по имени протокола. Если функциям сокетов передается 0, система выберет подходящий протокол по умолчанию. Создание сокетов в Perl Perl содержит встроенные функции для создания сокетов и управления ими; они в основном дублируют свои прототипы на С. Хотя это удобно для получения низкоуровневого, прямого доступа к системе, большинство предпочитают работать с более удобными средствами. На помощь приходят классы IO::Socket::INET и IO::Socket::UNIX –они обеспечивают высокоуровневый интерфейс к низкоуровневым системным функциям. Функции создание сокетов socket - создает сокет; bind – назначает ему локальное имя; connect – подключает локальный сокет к другому (возможно, удаленному); listen - готовит сокет к подключениям со стороны других сокетов; accept - последовательно принимает подключения; при обмене данными с потоковыми сокетами можно использовать как print и <>, так и syswrite и sysread; при обмене с датаграммными сокетами – send и recv. Использование функций в Perl Типичный сервер вызывает socket, bind и listen, после чего в цикле вызывает accept в блокирующем режиме, ожидая входящих подключений. Типичный клиент вызывает socket и connect. Датаграммные клиенты ведут себя особым образом. Они не обязаны вызывать connect для передачи данных, поскольку могут указать место назначения в качестве аргумента send. Написание сервера TCP Сервер ожидает подключения клиентов по сети к определенному порту. Связь осуществляется через Интернет. Сервер TCP. Первый вариант. Use IO::Socket; $server-IO::Socket::INET>new(LocalPOrt=>$server_port, Type=>SOCK_STREAM, Listen=>10 or SOMAXCONN … обработка ошибки while($client=$server->accept()){ # $client – новое подключение } close($server); Сервер TCP. Второй вариант. Use Socket; # создать сокет Socket(SERVER,PF_INET, SOCK_STREAM,0); # Построить свой адрес сокета $my_addr=sockaddr_in($server_port, INADDR_ANY); bind(SERVER,$my_addr) …обработка ошибки # установить очередь для входящих соединений listen(SERVER,SOMAXCONN) … обработка ошибки # принимать и обрабатывать подключения while(accept(CLIENT,SERVER)){ # сделать что-то с CLIENT } close(SERVER) Написание клиента TCP Подключение к сокету на удаленном компьютере. Связь осуществляется через Интернет. Клиент TCP. Первый вариант. Use IO::Socket; $socket=IO::Socket::INET>new(PeerAddr=>$remote_host, PeerPort=>$remote_port, Proto =>”tcp”, Type =>SOCK_STREAM) …обработка ошибки # сделать что-то с сокетом print $socket “…”; $answer=<$socket>; # отключиться после завершения close($socket); Клиент TCP. Второй вариант. Use Socket; Socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname(‘tcp’)); # построить адрес удаленного компьютера $internet_addr=inet_aton($remote_host); … обработка ошибки $paddr=sockaddr_in($remote_port, internet_addr); # подключиться connect(TO_SERVER, $paddr) … обработка ошибки # сделать что-то с сокетом print TO_SERVER “…”; #отключиться после завершения close(TO_SERVER); Сокеты в PHP Язык PHP позволяет работать с сокетами. Посредством сокетов мы имеем возможность соединяться с серверами по протоколу TCP. Это означает, в частности, что сокет может быть использован, например, для формирования почтовых соединений на более низком уровне, чем позволяет функция mail(). С помощью сокетов на языке PHP можно написать HTTP прокси –сервер, который будет фильтровать и анализировать запросы каким угодно образом, а также скрывать клиентский IP, поскольку обращение к HTTP-серверам (Web-серверам) будет осуществляться от имени прокси-сервера с его IP, за которым не будет виден конечный клиентский адрес. Функции PHP для работы с сокетами Создание сокета: $sock = socket_create (AF_INET, SOCK_STREAM, 0) Ошибки создания: socket_strerror ($sock) Назначение сокету локального имени $address = '192.168.112.4'; $port =4; $ret = socket_bind ($sock, $address, $port) Ошибки реализации socket_strerror ($ret) Функции PHP для работы с сокетами Подготовка сокета к подключениям со стороны других сокетов, $ret = socket_listen ($sock, 25) Последовательно принимает подключения. $msgsock = socket_accept($sock) Печатаем через сокет socket_write($msgsock, $buf, strlen($buf)); Пишем в сокет $buf = socket_read ($msgsock, 2048) Файл Server.php <?php error_reporting (E_ALL); set_time_limit (0); ob_implicit_flush (); $address = 'gw'; $port =15001; echo "YES"; Файл Server.php if (($sock = socket_create (AF_INET, SOCK_STREAM, 0)) < 0) { echo “Error: " . socket_strerror ($sock) . "\n"; } if ( ($ret = socket_bind ($sock, $address, $port)) < 0) { echo “Error: " . socket_strerror ($ret) . "\n"; } if ( ($ret = socket_listen ($sock, 25)) < 0) { echo “Error: " . socket_strerror ($ret) . "\n"; } if ( @ ($msgsock = socket_accept($sock)) < 0) { echo “Error: " . socket_strerror ($msgsock) . "\n"; } Файл Server.php $buf="Testing string"; echo $buf; @ socket_write($msgsock, $buf, strlen($buf)); while ( ($buf1 = socket_read ($msgsock, 2048))!=FALSE ){ echo $buf1;?><br><? } @ socket_close ($msgsock); @ socket_close ($sock); ?> Файл Client.php !/usr/local/bin/php <?php error_reporting (E_ALL); echo "<h2>TCP/IP Connection</h2>\n"; $addr = 'gw'; $port = 15001; $soc = socket_create( AF_INET, SOCK_STREAM, 0 ); $result = socket_connect ( $soc,$addr, $port); Файл Client.php if ($result < 0) { echo “Error" . socket_strerror($result) . "\n"; } else { while ( ($buf = socket_read ($soc, 2048))!=FALSE ){ echo $buf;?><br><? $gr = "Test Client"; socket_write( $soc, $gr, strlen($gr) ); } socket_close( $soc ); } ?> Запуск сервера Обмен данными между сервером и клиентом YES Testing string Test Client TCP/IP Connection Testing string