| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > PHP: Общие вопросы > Сокеты в PHP. Пособие для начинающих. |
| Автор: AztEK 13.7.2006, 15:22 | ||||||||||||||||||||
| Сокеты в PHP. Пособие для начинающих. Сокеты как таковые (не только реализованные в PHP) – мощнейший инструмент сетевого программирования. Они позволяют передавать и получать данные на прикладном уровне. Наиболее частое использование сокетов в контексте web-программирования - это работа со страницами, расположенными на разных хостах и взаимодействие с различными типами протоколов, используемых в Интернете (HTTP, FTP, SMTP, IMAP и проч.). Для взаимодействия с сокетами в PHP чаще всего используется функция fsockopen, синтаксис которой приведён ниже. resource fsockopen ( string $host [, int $post [, int &$errno [, string &$errstr [, float $timeout]]]] ) $host - хост, к которому будет производиться подключение $port - порт, по которому будет производиться подключение $errno - переменная, в которую запишется номер ошибки если таковая произойдёт $errstr - переменная, в которую запишется текст ошибки если таковая произойдёт $timeout - время в течении которого мы будем будет производиться попытка соединения с хостом Мы разберём подключение к серверу по 80-му порту и использование протокола HTTP. Поэтому хотя бы основы HTTP надо знать (в общем то любому web-программисту надо их знать). Спецификацию HTTP можно скачать по ссылке, расположенной в конце статьи. Больше не будет теоретизировать, сразу перейдём к практике. Распространённые примеры использования сокетов. Пример 1. Передаём данные и получаем страницу. Создайте php-скрипт следующего содержания:
Он, как нетрудно догадаться, выводит переменные, которые мы передадим в теле HTTP-запроса: строку User-Agent(где клиент говорит о том, какой у него браузер и ОС), HTTP-Referer(откуда он пришёл) и тестовую cookie (они ведь тоже передаются в HTTP). Теперь напишем скрипт обращения к странице и передачи переменных.
Разберём построчно этот пример. $fp = fsockopen('localhost', 80); Открываем сокет с идентификатором $fp и присоединяемся к хосту localhost (напомню, что получить имя хоста из URL можно функцией gethostbyname). Обратите внимание – перед названием хоста НЕ НАДО писать http:// - мы вполне бы могли работать и не с этим протоколом. Теперь, когда создан сокет, мы может получать и передавать информацию по нему с помощью функций, используемых для работы с файлами (fread(), fwrite(), fgets(), feof()). Этим и займёмся. fputs($fp, "GET /test_sock.php HTTP/1.0\nUser-Agent: У меня Firefox 1.5 и Windows XP\nReferer: Я пришёл с microsoft.com\nCookie: test=test_cookie\n\n"); С помощью функции fputs передаём данные, используя формат HTTP. Давайте разберём, что же там написано.
В первой строке мы указываем, какую страницу на сервере мы хотим получить (/test_sock.php). Соответственно, если бы нам была нужна страница, расположенная в директории test на сервере, мы бы написали так: /test/test_sock.php, а если бы была нужна главная страница сервера, напишем просто /. HTTP/1.0 показывает, какую версию протокола HTTP мы будем использовать, обращаясь к серверу. В следующих строках мы будем передавать серверу информацию в виде
Это называется заголовок HTTP-запроса. Вот распространённые значения (все возможные значения можно прочитать в спецификации HTTP): User-Agent Пример: User-Agent: Mozilla/4.5 [en] (Win95; I) Строка, описывающая браузер и ОС. На основе этого заголовка создается переменная окружения HTTP_USER_AGENT. Referer Пример: Referer: php.net URL страницы, с которой клиент перешел на данную страницу. На основе этого заголовка создается переменная окружения HTTP_REFERER. Как видите, не стоит сильно доверять этой переменной при написании систем авторизации, поскольку клиент (или хакер) может передать в этом заголовке всё что угодно. Accept Пример: Accept: text/html, text/plain, image/gif, image/jpeg Эта строка используется браузером, что сказать серверу, какие типы данных он понимает На основе этого заголовка создается переменная окружения HTTP_ACCEPT_ENCODING. Cookie Пример: Cookie: a=1;b=2;c=3; Передаём cookie. На основе этого заголовка создается глобальный массив $_COOKIE. После того, как мы передали все необходимые нам переменные, идут подряд два символа перевода строки(\n\n). Это означает, что всё, что клиент хотел сказать серверу, он сказал и теперь ожидает ответа. while(!feof($fp)) echo fgets($fp); Используя функции feof() и fgets(), выводим ответ сервера на наш запрос. У моего сервера ответ получился такой:
Не буду сдаваться в подробности того, какие заголовки вывел сервер, всё это вы можете прочитать в документации. Как видите, послать серверу можно что угодно, поэтому дважды подумайте, прежде чем доверять переменным окружения. В умелых руках это серьёзное оружие взлома. P.S. Довольно часто получать содержание страницы в Интернете пытаются функциями наподобие file() и file_get_contents(). Почему этого не стоит делать, читайте http://vingrad.ru/PHP-PHPNETHTTP-003044. Пример 2. Определить, существует ли страница в Интернете. Довольно популярный вопрос, который обычно пробуют решать примерно так:
Сейчас разберёмся, как сделать это грамотнее. Немного отвлечёмся от программирования. Вот вы бродите по Интернету, открываете страницы и вдруг ошиблись при наборе адреса и попали на несуществующую страницу. Что делает ваш браузер? Конечно он хороший браузер и говорит, что такой страницы не существует. В тексте сообщения об ошибке наверняка попадётся число 404. Это даёт нам идею для реализации нашей задачи. Давайте вернёмся немного назад, к предыдущему примеру. Сервер первой строкой отдал нам следующее: HTTP/1.1 200 OK Что это значит? HTTP/1.1 – это ясно, версия протокола, на котором отдан ответ клиенту. Следующая часть уже интереснее, 200 – это так называемый код состояния, число, используя которое, сервер говорит, что он сделал с нашим запросом и чего нам следует теперь ожидать. В очередной раз отправляю вас к документации по HTTP, где написано, что код 200 означает, что «Запрос был удачно выполнен». Это хорошо. А что возвратит сервер, если страница не найдена? Правильно, уже знакомое нам 404. Итак, определить наличие страницы в Интернете можно так:
Справедливости ради, следует отметить, что сервер, не найдя страницу может и не возвращать 404. Вполне возможно, что он редиректнет нас, причем возвратит код 200. Здесь приведён простейший пример, в реальных условиях, возможно, потребуются дополнительные проверки. Пример 3. Передаём данные на сервер методом POST, не используя HTML-форму. Самый животрепещущий вопрос на тему сокетов Добавьте в скрипт, к которому мы обращались в прошлом примере строчку echo 'POST: ' . $_POST['test'] . "\n"; Сейчас будем ловить POST-данные. Теперь наш запрос к серверу будет выглядеть таким образом:
Разберём этот запрос. Вот он:
Рассмотрим, чем этот запрос отличается от запроса из предыдущего примера. Прежде всего, в первой строке используется "POST", а не "GET". Это значит, что после двух переносов строки будут идти данные, которые сервер, возможно, передаст PHP-интерпретатору. Кроме того, среди заголовков есть два новых для нас. Content-length Пример: Content-length: 2452 Длина данных, которые, грубо говоря, будут переданы после двух переносов строки. Используется, когда сервер отвечает на запрос или, как в нашем случае, если передаются POST-данные. Размер переданных данных должен быть обязательно равен этому значению. На основе этого заголовка создается переменная окружения CONTENT_LENGTH. Content-Type Пример: Content-Type: text/html Задаёт тип документа и его кодировку. Для передачи данных методом POST мы использовали application/x-www-form-urlencoded. Чтобы передать несколько переменных методом POST, перечислите их через символ «&» (совсем как в GET), например:
Полезные ссылки http://ru.wikipedia.org/wiki/HTTP http://www.ietf.org/rfc/rfc1945.txt http://www.ietf.org/rfc/rfc2616.txt http://ru.php.net/manual/en/function.fsockopen.php http://ru.php.net/manual/en/ref.sockets.php http://vingrad.ru/PHP-PHPNETHTTP-003044 Заключение Следует отметить, что подключаться к хосту можно совсем не обязательно на 80-й порт и работать не с протоколом HTTP. Использовать сокеты можно и для работы с FTP, почтой, ICQ и проч. Главное знать, какой порт и протокол использовать в том ли ином случае. Мы разобрали взаимодействие сокетов с HTTP-протоколом, самый простой и очевидный. Удачи вам в программировании! С уважением, AztEK. |
| Автор: AztEK 13.7.2006, 17:14 |
| GiV, да, спасибо. Действительно, это ошибка. Зачем то взял BNF функции из Котерова, а не c php.net. Исправил. |
| Автор: AztEK 15.7.2006, 16:03 |
| Что, больше никто ничего не может сказать? |
| Автор: nerezus 15.7.2006, 16:43 |
| Если честно, то тема абсолютно не раскрыта =( А я то уж было хотел неблок. сокеты почитать, открываю тему... и облом... |
| Автор: MoLeX 26.1.2008, 10:32 |
| Неплохая статья на мой взгляд. держи +1 |