Socket getpeername: примеры (PHP)
socket_getpeername(resource socket, string &address [, int &port]): boolФункция socket_getpeername() позволяет получить информацию об удаленной стороне сокетного соединения. Она используется для определения адреса и порта, к которому подключен сокет.
Функция применяется в сетевом программировании, когда необходимо идентифицировать удаленного клиента или сервер в рамках установленного соединения. Это может быть полезно для логирования, аутентификации или обработки данных в зависимости от источника.
Функция имеет три параметра:
- socket - экземпляр сокета, созданный с помощью
socket_create()или принятый черезsocket_accept(). - address - переменная, передаваемая по ссылке, в которую будет записан IP-адрес или путь Unix-сокета.
- port - переменная, передаваемая по ссылке, в которую будет записан номер порта (для сетевых сокетов).
Функция возвращает true при успехе и false при ошибке.
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'example.com', 80);
if (socket_getpeername($socket, $address, $port)) {
echo "Подключено к $address на порту $port";
}
?>Подключено к 93.184.216.34 на порту 80
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// Сокет не подключен
if (!socket_getpeername($socket, $address, $port)) {
echo "Ошибка: " . socket_strerror(socket_last_error($socket));
}
?>Ошибка: Socket is not connected
<?php
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
socket_connect($socket, '/tmp/my_socket');
if (socket_getpeername($socket, $address)) {
echo "Подключено к Unix-сокету: $address";
}
?>Подключено к Unix-сокету: /tmp/my_socket
В PHP существуют несколько функций для работы с сокетами, которые могут быть использованы в схожих сценариях:
- socket_getsockname() - получает локальный адрес и порт сокета. Полезна, когда нужно узнать, на каком интерфейсе и порту работает сервер.
- stream_socket_get_name() - аналог для потоковых сокетов, созданных через потоковый API. Работает с ресурсами потоков.
- socket_recvfrom() - получает данные и адрес отправителя для непривилегированных сокетов. Используется для UDP-сокетов.
Выбор функции зависит от контекста: socket_getpeername предназначена для установленных TCP-соединений или Unix-сокетов, тогда как socket_recvfrom подходит для датаграмм.
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('example.com', 80))
addr, port = s.getpeername()
print(f'Connected to {addr}:{port}')Connected to 93.184.216.34:80
const net = require('net');
const socket = net.createConnection(80, 'example.com', () => {
console.log(`Connected to ${socket.remoteAddress}:${socket.remotePort}`);
});Connected to 93.184.216.34:80
В MySQL нет прямой аналогии, но можно получить идентификатор соединения для текущей сессии:
SELECT CONNECTION_ID();42
В отличие от PHP, Python и Node.js предоставляют методы как часть объекта сокета, а не как отдельные функции.
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!socket_getpeername($socket, $address, $port)) {
$error = socket_last_error($socket);
echo "Ошибка: " . socket_strerror($error); // ENOTCONN
}
?>Ошибка: Socket is not connected
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'example.com', 80);
$address = null;
$port = null;
// Правильно: переменные передаются по ссылке, функция сама их инициализирует
if (socket_getpeername($socket, $address, $port)) {
echo "Адрес: $address, Порт: $port";
}
?>Адрес: 93.184.216.34, Порт: 80
<?php
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
// UDP-сокет не устанавливает соединение, поэтому getpeername может не сработать
socket_connect($socket, 'example.com', 80); // connect для UDP только устанавливает адрес по умолчанию
if (socket_getpeername($socket, $address, $port)) {
echo "Адрес: $address, Порт: $port";
}
?>Адрес: 93.184.216.34, Порт: 80
Примечание: Для UDP socket_connect() только устанавливает адрес по умолчанию, но соединение не устанавливается в том же смысле, что и для TCP.
В PHP 8 функция socket_getpeername() не претерпела значительных изменений. Однако, начиная с PHP 8.0, многие функции сокетов теперь выбрасывают исключение Error при неудаче, если это не отключено. Ранее они возвращали false и устанавливали код ошибки.
Пример в PHP 8:
<?php
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
try {
socket_getpeername($socket, $address, $port);
} catch (Error $e) {
echo "Исключение: " . $e->getMessage();
}
?>Исключение: socket_getpeername(): unable to retrieve peer address [0]: Socket is not connected
Это изменение делает обработку ошибок более последовательной с другими частями языка.
<?php
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($server, '0.0.0.0', 8080);
socket_listen($server);
while (true) {
$client = socket_accept($server);
if (socket_getpeername($client, $address, $port)) {
$logEntry = date('Y-m-d H:i:s') . " - Подключение от $address:$port\n";
file_put_contents('connections.log', $logEntry, FILE_APPEND);
}
socket_close($client);
}
?><?php
$trusted = ['192.168.1.1', '10.0.0.2'];
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '192.168.1.1', 80);
if (socket_getpeername($socket, $address, $port)) {
if (in_array($address, $trusted)) {
echo "Доверенное подключение к $address\n";
} else {
echo "Подключение к недоверенному адресу: $address\n";
}
}
?>Доверенное подключение к 192.168.1.1
<?php
$socket = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP);
socket_connect($socket, 'ipv6.google.com', 80);
if (socket_getpeername($socket, $address, $port)) {
echo "Подключение к IPv6: $address:$port\n";
}
?>Подключение к IPv6: 2a00:1450:401b:801::200e:80
<?php
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($server, '0.0.0.0', 9000);
socket_listen($server);
$clients = [];
while (true) {
$client = socket_accept($server);
$pid = pcntl_fork();
if ($pid == -1) {
die('Ошибка fork');
} else if ($pid) {
// Родительский процесс
$clients[] = $pid;
socket_close($client);
} else {
// Дочерний процесс
if (socket_getpeername($client, $address, $port)) {
echo "[PID: ".getpid()."] Обработка клиента $address:$port\n";
// Обработка данных...
}
socket_close($client);
exit(0);
}
}
?><?php
$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
$serverSocket = '/tmp/server.sock';
// Убедимся, что серверный сокет существует
if (file_exists($serverSocket)) {
socket_connect($socket, $serverSocket);
if (socket_getpeername($socket, $address)) {
echo "Подключено к Unix-сокету: $address\n";
}
} else {
echo "Серверный сокет не найден\n";
}
?>Подключено к Unix-сокету: /tmp/server.sock
Эти примеры демонстрируют разнообразные сценарии применения функции в реальных проектах.