Socket recv: примеры (PHP)
socket_recv(resource socket, string &buf, int len, int flags): intФункция socket_recv() используется в PHP для получения данных из подключенного сокета. Она работает на более низком уровне по сравнению с функциями вроде fread() и предоставляет контроль над операцией чтения через флаги.
Функция применяется в сетевом программировании для создания TCP/UDP клиентов и серверов, где требуется точное управление процессом чтения данных из сокета, например, в протоколах с бинарными данными или при необходимости просмотра данных без их извлечения из буфера.
- socket (Socket): Объект сокета, созданный функцией
socket_create(). - buf (string): Переменная, в которую будут помещены принятые данные. Передается по ссылке.
- len (int): Максимальное количество байт для чтения.
- flags (int): Комбинация флагов, управляющих чтением:
MSG_OOB- чтение данных вне потока (out-of-band).MSG_PEEK- получение данных из начала буфера, но без их удаления из буфера.MSG_WAITALL- блокировка до тех пор, пока не будет прочитано запрошенное количество байт (len). Может не выполняться при получении сигнала или обрыве соединения.MSG_DONTWAIT- чтение в неблокирующем режиме.
Возвращаемое значение: Количество прочитанных байт или false в случае ошибки.
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '127.0.0.1', 8080);
$buf = '';
$bytes = socket_recv($socket, $buf, 1024, 0);
echo "Получено $bytes байт: $buf";
?>Получено 12 байт: Hello World!
<?php
$socket = //... подключенный сокет
$buf = '';
// Прочитать данные, но оставить их в буфере сокета
$bytes = socket_recv($socket, $buf, 5, MSG_PEEK);
echo "Заглянули в буфер: $buf\n";
// Чтение еще раз — данные все еще там
$buf2 = '';
$bytes2 = socket_recv($socket, $buf2, 5, 0);
echo "Прочитали окончательно: $buf2";
?>Заглянули в буфер: Hello Прочитали окончательно: Hello
<?php
$socket = //... подключенный сокет
$buf = '';
// Будет ждать ровно 8 байт
$bytes = socket_recv($socket, $buf, 8, MSG_WAITALL);
echo "Получено $bytes байт: $buf";
?>Получено 8 байт: Data1234
Функция socket_read() читает данные из сокета до достижения указанной длины, конца строки или конца файла. Она проще в использовании, но не поддерживает флаги, как socket_recv(). Предпочтительна для простых задач чтения потоковых данных.
$data = socket_read($socket, 1024);Работает с потоковыми сокетами, созданными через stream_socket_client()/stream_socket_server(). Поддерживает флаги, схожие с socket_recv(). Рекомендуется при использовании потокового контекста вместо расширения Socket.
$data = stream_socket_recvfrom($socket, 1024, 0, $peer);Метод recv() объекта сокета в Python принимает размер буфера и флаги. Похож на PHP-версию, но флаги (например, MSG_PEEK) импортируются из модуля socket.
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 8080))
data = s.recv(1024)
print(f"Received: {data}")Received: b'Hello'
В Node.js сокеты являются потоками. Метод read() считывает данные, если они доступны во внутреннем буфере. Для низкоуровневого контроля используется модуль net или dgram с событиями 'data'.
const net = require('net');
const client = net.connect(8080, '127.0.0.1', () => {});
client.on('data', (data) => {
console.log(`Received: ${data}`);
});Received: Hello
Функция ожидает ресурс или объект Socket. Передача другого типа приводит к ошибке.
<?php
$socket = 'not_a_socket';
$buf = '';
$result = socket_recv($socket, $buf, 1024, 0); // Warning: socket_recv() expects parameter 1 to be Socket, string given
?>Warning: socket_recv() expects parameter 1 to be Socket, string given
Передача неинициализированной переменной в качестве буфера может вызвать неожиданное поведение, хотя в современных версиях PHP это часто работает.
<?php
$socket = //... сокет
// $buf не объявлена
$bytes = socket_recv($socket, $buf, 1024, 0); // Переменная $buf будет создана
?>Указание нулевой или отрицательной длины приводит к тому, что функция не читает данные.
<?php
$socket = //... сокет
$buf = '';
$bytes = socket_recv($socket, $buf, 0, 0);
var_dump($bytes); // int(0)
?>int(0)
В PHP 8.0.0 параметр socket ожидает экземпляр класса Socket, а не ресурс (resource). В более ранних версиях передавался ресурс. Это изменение является частью общей типизации объектов вместо ресурсов.
// До PHP 8.0.0
$socket = socket_create(...); // Тип: resource
// Начиная с PHP 8.0.0
$socket = socket_create(...); // Тип: SocketЧасто в протоколах сначала передается размер пакета, затем данные. Использование MSG_WAITALL гарантирует чтение точного количества байт.
<?php
function read_packet($socket) {
$header = '';
// Читаем 4 байта (размер пакета в бинарном формате)
socket_recv($socket, $header, 4, MSG_WAITALL);
$size = unpack('N', $header)[1]; // Распаковываем беззнаковое 32-битное число (big endian)
$data = '';
if ($size > 0) {
socket_recv($socket, $data, $size, MSG_WAITALL);
}
return $data;
}
?>Использование флага MSG_DONTWAIT позволяет избежать блокировки, если данных нет.
<?php
socket_set_nonblock($socket);
$buf = '';
$bytes = socket_recv($socket, $buf, 1024, MSG_DONTWAIT);
if ($bytes === false) {
$error = socket_last_error($socket);
if ($error == SOCKET_EAGAIN || $error == SOCKET_EWOULDBLOCK) {
echo "Данных пока нет.\n";
} else {
echo "Произошла реальная ошибка.";
}
} else {
echo "Получено $bytes байт.";
}
?>Флаг MSG_OOB позволяет читать срочные данные, отправленные вне основного потока.
<?php
$oob_data = '';
// Попытка чтения внеполосных данных
$bytes = socket_recv($socket, $oob_data, 1024, MSG_OOB);
if ($bytes > 0) {
echo "Срочные данные: $oob_data";
}
?>