Socket create pair: примеры (PHP)
socket_create_pair(int domain, int type, int protocol, array &fd): boolФункция socket_create_pair создает пару соединенных между собой сокетов, которые могут использоваться для межпроцессного взаимодействия (IPC) в рамках одного компьютера. Созданные сокеты являются неименованными и работают по принципу двусторонней связи (дуплекс).
Функция применяется в ситуациях, когда необходимо организовать обмен данными между родственными процессами, например, между родительским и дочерним процессом после вызова pcntl_fork(). Это эффективная альтернатива использованию пайпов (pipes) или других механизмов IPC.
Сигнатура функции: socket_create_pair(int $domain, int $type, int $protocol, array &$pair): bool
- $domain (обязательный): Семейство протоколов. Чаще всего используется AF_UNIX для коммуникации в пределах одной системы или AF_INET.
- $type (обязательный): Тип сокета. Например, SOCK_STREAM (надежный, с установкой соединения) или SOCK_DGRAM (датаграммы, без установки соединения).
- $protocol (обязательный): Конкретный протокол в рамках указанного домена. Обычно 0, что позволяет системе выбрать протокол по умолчанию для заданной комбинации домена и типа.
- &$pair (обязательный): Переменная, передаваемая по ссылке, в которую будет записан массив из двух ресурсов сокетов при успешном выполнении.
Функция возвращает true в случае успеха и false в случае неудачи.
Создание пары сокетов в домене Unix для последующего использования в fork.
<?
$sockets = [];
if (socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets) === false) {
echo "Не удалось создать пару сокетов: " . socket_strerror(socket_last_error());
} else {
echo "Пара сокетов успешно создана.\n";
echo "socket[0]: " . (is_resource($sockets[0]) ? 'Ресурс' : 'Не ресурс') . "\n";
echo "socket[1]: " . (is_resource($sockets[1]) ? 'Ресурс' : 'Не ресурс') . "\n";
}
?>Пара сокетов успешно создана. socket[0]: Ресурс socket[1]: Ресурс
Создание пары датаграммных сокетов.
<?
$sockets = [];
if (socket_create_pair(AF_INET, SOCK_DGRAM, 0, $sockets)) {
$msg = "Тестовое сообщение";
socket_write($sockets[0], $msg, strlen($msg));
$data = socket_read($sockets[1], 1024);
echo "Получено: $data\n";
}
?>Получено: Тестовое сообщение
- stream_socket_pair: Создает пару подключенных, неименованных потоковых сокетов. Возвращает массив потоковых ресурсов. Часто считается более высокоуровневой и удобной альтернативой, особенно при работе с потоковыми контекстами.
- pcntl_signal и разделяемая память: Для простых уведомлений между процессами иногда достаточно сигналов. Для сложного обмена данными можно использовать shmop или Semaphore.
- popen/proc_open: Для взаимодействия с внешними процессами через стандартные потоки ввода-вывода.
socket_create_pair предпочтительнее, когда нужен низкоуровневый контроль над сокетами или совместимость с существующим кодом на сокетах. stream_socket_pair проще интегрируется с остальными функциями потоков PHP (например, stream_select).
import os
# Создание пары сокетов
parent_conn, child_conn = os.pipe() # Создает анонимный канал (pipe)
# Или с использованием socket.socketpair()
import socket
sock1, sock2 = socket.socketpair()
sock1.send(b'Hello')
print(sock2.recv(1024)) # b'Hello'b'Hello'
В Node.js нет прямой аналогии для создания пар сокетов в одном процессе. Для IPC между процессами используются child_process.fork() и канал сообщений.
Socket create pair в MySQL
MySQL не предоставляет функций для низкоуровневой работы с сокетами в контексте IPC. Взаимодействие обычно происходит через сетевые соединения или встроенные функции для работы с данными.
Основное отличие PHP-функции - ее низкоуровневость и работа в контексте одного PHP-процесса с последующим fork, тогда как в Python socket.socketpair() возвращает полноценные объекты сокетов, а в Node.js акцент сделан на сетевые и межпроцессные коммуникации через события.
<?
$sockets = [];
// Попытка использовать несуществующий домен
if (!socket_create_pair(99999, SOCK_STREAM, 0, $sockets)) {
echo "Ошибка: " . socket_strerror(socket_last_error()) . "\n";
}
?>Ошибка: Invalid argument
<?
$sockets = [];
// Функция ожидает ссылку, но передается значение (в данном случае это вызовет предупреждение в строгом режиме)
// Корректно: socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets);
if (!socket_create_pair(AF_UNIX, SOCK_STREAM, 0, [$sockets])) {
echo "Ошибка создания пары.\n";
}
?>Warning: socket_create_pair() expects parameter 4 to be array, null given...
<?
$sockets = [];
socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets);
socket_close($sockets[0]);
if (socket_write($sockets[0], "test", 4) === false) {
echo "Запись в закрытый сокет невозможна.\n";
}
?>Запись в закрытый сокет невозможна.
Начиная с PHP 8.0, функция возвращает объекты Socket вместо ресурсов. Сокеты стали объектами.
В PHP 8.3 были улучшены сообщения об ошибках и общая стабильность работы с сокетами, но сигнатура функции socket_create_pair осталась неизменной.
<?
// Поведение в PHP 8.0+
$sockets = [];
socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets);
var_dump($sockets[0]);
?>object(Socket)#1 (0) {
}<?
$sockets = [];
if (!socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets)) {
die("Ошибка создания пары сокетов");
}
$pid = pcntl_fork();
if ($pid == -1) {
die("Не удалось создать дочерний процесс");
}
if ($pid) { // Родительский процесс
socket_close($sockets[0]); // Закрываем один конец в родителе
$msg = "Сообщение от родителя";
socket_write($sockets[1], $msg, strlen($msg));
echo "Родитель отправил: $msg\n";
$response = socket_read($sockets[1], 1024);
echo "Родитель получил: $response\n";
socket_close($sockets[1]);
pcntl_wait($status);
} else { // Дочерний процесс
socket_close($sockets[1]); // Закрываем другой конец в потомке
$data = socket_read($sockets[0], 1024);
echo "Дочерний процесс получил: $data\n";
$reply = "Ответ от дочернего процесса";
socket_write($sockets[0], $reply, strlen($reply));
echo "Дочерний процесс отправил: $reply\n";
socket_close($sockets[0]);
exit(0);
}
?>Родитель отправил: Сообщение от родителя Дочерний процесс получил: Сообщение от родителя Дочерний процесс отправил: Ответ от дочернего процесса Родитель получил: Ответ от дочернего процесса
<?
$sockets = [];
socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets);
// Записываем данные в один сокет
socket_write($sockets[0], "test data", 9);
$read = [$sockets[1]];
$write = $except = null;
// Ожидаем, пока сокет станет доступным для чтения
if (socket_select($read, $write, $except, 5) > 0) {
foreach ($read as $readySocket) {
$data = socket_read($readySocket, 1024);
echo "Данные, готовые к чтению: $data\n";
}
}
socket_close($sockets[0]);
socket_close($sockets[1]);
?>Данные, готовые к чтению: test data
Прямая передача файловых дескрипторов через socket_create_pair невозможна. Однако, можно передать метаданные (например, имя файла или содержимое) через сокет, а затем открыть файл в другом процессе.