PHP
Розетки
Поиск…
Соединитель TCP-клиента
Создание сокета, использующего TCP (протокол управления передачей)
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
Убедитесь, что сокет успешно создан. Функция onSocketFailure
исходит из примера ошибок сокетов обработки в этом разделе.
if(!is_resource($socket)) onSocketFailure("Failed to create socket");
Подключите разъем к указанному адресу
Вторая строка изящно выходит из строя, если соединение не выполнено.
socket_connect($socket, "chat.stackoverflow.com", 6667)
or onSocketFailure("Failed to connect to chat.stackoverflow.com:6667", $socket);
Отправка данных на сервер
Функция socket_write
отправляет байты через сокет. В PHP байтовый массив представлен строкой, которая обычно нечувствительна к кодированию.
socket_write($socket, "NICK Alice\r\nUSER alice 0 * :Alice\r\n");
Получение данных с сервера
Следующий фрагмент получает некоторые данные с сервера, используя функцию socket_read
.
Передача PHP_NORMAL_READ
в качестве третьего параметра считывается до байта \r
/ \n
, и этот байт включен в возвращаемое значение.
Передача PHP_BINARY_READ
, напротив, считывает требуемый объем данных из потока.
Если socket_set_nonblock
был вызван перед и PHP_BINARY_READ
используется, socket_read
вернет false
немедленно. В противном случае метод блокируется до тех пор, пока не будут получены достаточные данные (чтобы достичь длины во втором параметре или достичь окончания строки), или сокет будет закрыт.
В этом примере читаются данные с предположительно IRC-сервера.
while(true) {
// read a line from the socket
$line = socket_read($socket, 1024, PHP_NORMAL_READ);
if(substr($line, -1) === "\r") {
// read/skip one byte from the socket
// we assume that the next byte in the stream must be a \n.
// this is actually bad in practice; the script is vulnerable to unexpected values
socket_read($socket, 1, PHP_BINARY_READ);
}
$message = parseLine($line);
if($message->type === "QUIT") break;
}
Закрытие гнезда
Закрытие сокета освобождает сокет и связанные с ним ресурсы.
socket_close($socket);
Разъем TCP-сервера
Создание гнезда
Создайте сокет, который использует TCP. Это то же самое, что и создание клиентского сокета.
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
Соединительная муфта
Свяжите соединения из заданной сети (параметр 2) для определенного порта (параметр 3) в гнездо.
Второй параметр обычно "0.0.0.0"
, который принимает соединение из всех сетей. Он также может
Одной из распространенных причин ошибок socket_bind
является то, что указанный адрес уже связан с другим процессом . Другие процессы обычно убивают (обычно вручную, чтобы предотвратить случайное убийство критических процессов), чтобы сокеты были освобождены.
socket_bind($socket, "0.0.0.0", 6667) or onSocketFailure("Failed to bind to 0.0.0.0:6667");
Установите сокет для прослушивания
Сделать сокет прослушивать входящие соединения с помощью socket_listen
. Второй параметр - это максимальное количество подключений для обеспечения очереди до их принятия.
socket_listen($socket, 5);
Обработка соединения
Сервер TCP фактически является сервером, который обрабатывает дочерние соединения. socket_accept
создает новое дочернее соединение.
$conn = socket_accept($socket);
Передача данных для соединения из socket_accept
такая же, как и для клиентского сокета TCP .
Когда это соединение должно быть закрыто, вызовите socket_close($conn);
непосредственно. Это не повлияет на исходный сокет TCP-сервера.
Закрытие сервера
С другой стороны, socket_close($socket);
следует вызывать, когда сервер больше не используется. Это также освободит TCP-адрес, позволяя другим процессам связываться с адресом.
Обработка ошибок сокетов
socket_last_error
может использоваться для получения идентификатора ошибки последней ошибки из расширения сокетов.
socket_strerror
может использоваться для преобразования идентификатора в удобочитаемые строки.
function onSocketFailure(string $message, $socket = null) {
if(is_resource($socket)) {
$message .= ": " . socket_strerror(socket_last_error($socket));
}
die($message);
}
Разъем UDP-сервера
Сервер UDP (протокол пользовательских дейтаграмм), в отличие от TCP, не основан на потоках. Он основан на пакетах, т.е. клиент отправляет данные в единицы, называемые «пакеты» на сервер, и клиент идентифицирует клиентов по их адресу. Нет встроенной функции, которая связывает разные пакеты, отправленные с одного и того же клиента (в отличие от TCP, где данные от одного и того же клиента обрабатываются определенным ресурсом, созданным socket_accept
). Можно думать, что новое TCP-соединение принимается и закрывается каждый раз, когда приходит пакет UDP.
Создание гнезда UDP-сервера
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
Связывание сокета с адресом
Параметры те же, что и для TCP-сервера.
socket_bind($socket, "0.0.0.0", 9000) or onSocketFailure("Failed to bind to 0.0.0.0:9000", $socket);
Отправка пакета
Эта строка отправляет $data
в пакете UDP в $address
: $port
.
socket_sendto($socket, $data, strlen($data), 0, $address, $port);
Получение пакета
Следующий фрагмент пытается управлять пакетами UDP с индексированным клиентом образом.
$clients = [];
while (true){
socket_recvfrom($socket, $buffer, 32768, 0, $ip, $port) === true
or onSocketFailure("Failed to receive packet", $socket);
$address = "$ip:$port";
if (!isset($clients[$address])) $clients[$address] = new Client();
$clients[$address]->handlePacket($buffer);
}
Закрытие сервера
socket_close
может использоваться на ресурсе сокета сервера UDP. Это освободит UDP-адрес, позволяя другим процессам связываться с этим адресом.