Программирование sockets в PHP. Часть вторая
Автор: parrot 23.07.2017 15:49
В прошлой статье мы разобрали реализацию простейшего клиентского приложения на php. В этой статье мы разберем реализацию простейшего сервера на php. Тестировать наше серверное приложение нам поможет чудесная утилита NetCat (можете использовать telnet). Так же хочу предупредить вас о том, что большая часть хостинговых компаний не разрешает запускать скрипты на сервере больше чем на 30 секунд. Скорей всего тестировать этот скрипт вам придется либо на VDS, либо у себя на localhost.
Краткая логика приложения
Смысл нашего приложения прост как 3 копейки. Клиент подключается к нашему серверному приложения и посылает данные, сервер эти данные принимает, обрабатывает, немного видоизменяет и отсылает обратно клиенту. При посылке сообщения «quit» приложения заканчивает свою работу. Если в приложении возникает ошибка, оно заканчивает свою работу, но предварительно указывает в какой функции возникла ошибка.
Исходный код сервера
Исходник взят из книги php 5.1 руководство программиста и немного видоизменен
set_time_limit(0); $addr = '127.0.0.1'; $port = 123; $sock = socket(AF_INET, SOCK_STREAM, 0); if($sockРазбор исходного кода
set_time_limit(0);Функция set_time_limit() с аргументом 0 говорит серверу о том, что время для выполнения этого сценария неограниченно. Если вы установите, скажем 30 секунд, то php завершит работу сценария через указанный промежуток времени.
$sock = socket(AF_INET, SOCK_STREAM, 0);Созданием сокета занимается функция socket(), которая принимает 3 параметра. Первый параметр указывает тип сети и может принимать значение AF_INET и AF_UNIX. AF_UNIX указывает, что это будет локальный unix-socket, которые чаше всего используют для межпроцессного взаимодействия. Вам же везде и всегда нужно указывать AF_INET.
Второй параметр указывает тип создаваемого сокета и по документации может принимать значения SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW, SOCK_RDM, SOCK_PACKET. На самом же деле не везде и не всегда работают эти параметры, например, попробуйте под Windows создать SOCK_RAW. В реальной жизни из всех этих значений чаще всего используются SOCK_STREAM и SOCK_DGRAM, фактически эти значения указывают на то какой протокол транспортного уровня (соответственно TCP или UDP) будет использоваться, а точнее будет ли устанавливается логическое соединение или нет.
Третий параметр указывает протокол транспортного уровня TCP или UDP,их можно указать как 0 или 1, так же и константами SOL_TCP, SOL_UDP.
$err = bind($sock, $addr, $port);Функция bind() связывает данный ей первым параметром сокет с ip адресом (второй параметр) и портом (третий параметр).
$err = listen($sock, 5);Функция listen() разрешает прием данных в сокет $sock, второй параметр указывает количество воспринимаемых соединений. Это не значит, что вы сможете обрабатывать 5 подключений за раз, это значит, что вы сможете обработать 5 подключений последовательно (хотя все зависит от вашей системы и ее возможностей). Не стоит делать это значение слишком большим или слишком маленьким. В зависимости от возможностей вашей системы и назначения приложения выбирайте некий оптимум.
В случае возникновения ошибки все вышеуказанные функции возвращают отрицательное значение.
Далее запускается бесконечный цикл do{…}while(true) в котором мы будем ожидать подключения клиента.
$msgsock = accept_connect($sock);Функция ожидает подключения клиентского приложения, единственным параметром принимает созданный нами сокет $sock. Результатом работы функции так же является дескриптор сокета, который используется для обмена данными с клиентской стороной.
Далее запускается еще один бесконечный цикл do{…}while(true) в котором мы будем принимать данные от клиентской стороны, обрабатывать их и отвечать на них.
$err = read($msgsock, $buf, 2048);Функция read() читает данный из сокета $msgsock в буфер $buf, количество считываемых байт определяется 3 параметром и у нас равняется 2048. Функция заканчивает свою работу раньше, если найдет в тексте символ конца строки (\n) или нуль байт (\0).
Результатом своей работы функция возвращает количество полученных байт или номер ошибки.
write($msgsock, $talkback, strlen($talkback));Отвечает клиенту (пишет в дескриптор сокета) указанному первым параметром. Отсылаемое сообщение находится в переменной $talkback (второй параметр), размер этого сообщения указывается 3 параметром.
Результатов своей работы функция возвращает количество успешно записанных байт или номер ошибки.
close($msgsock); close($sock);Закрывает сокеты и разрывает тем самым все активные подключения.
strerror($err)Как вы уже заметили, при возникновении ошибки все функции возвращают отрицательное значение (номер ошибки), поэтому наличие ошибки мы проверяем простым условием:
If($errЕсли номер этой ошибки поместить в функцию strerror() она выведет понятное человеку описание ошибки.
Тестирование приложения
Для тестирования сервера нам надо отправить ему некоторое сообщение, при получении ответа «Вы ввели наше сообщение» мы убедимся в правильной работе нашего приложения.
Для того что бы отправить серверу сообщение мы возьмем утилиту NetCat, запустив ее и введя ip адрес и порт вашего серверного приложения на php вы можете отправлять любые данные вашему приложению.
nc 127.0.0.1 123 helloПосле чего сервер должен ответить вам:
Вы ввели helloДля того что бы закрыть соединение наберите quite.
Заключение
В этой статьей вы познакомились с написанием простейшего серверного приложения на php. Это приложение может служить чудесным каркасом для написания ваших собственных серверных приложений. В следующей статье мы напишем простейший клиент, для нашего серверного приложения, все более углубляясь в программирования сокетов на php.
Похожие статьи