Написание сервера TCP
Проблема
Вы хотите написать сервер, который ожидает подключения клиентов по сети к определенному порту.
Решение
Следующее решение предполагает, что связь осуществляется через Интернет.
Воспользуйтесь стандартным (для версии 5.004) классом IO::Socket::INET:
use IO::Socket:
$server = IO::Socket::INET->new(LocalPort => $server_port,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10 ) # or SOMAXCONN
or die "Couldn't be a tcp server on port $server_port : $@\n";
while ($client = $server->accept()) {
# $client - новое подключение
}
close($server);
Или создайте сокет вручную, что позволит получить полный контроль над ним:
use Socket;
# Создать сокет
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
# Чтобы мы могли быстро перезапустить сервер
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1);
# Построить свой адрес сокета
$my_addr = sockaddr_in($server_port, INADDR_ANY):
bind(SERVER, $my_addr)
or die "Couldn't bind to port $server_port : $!\n";
# Установить очередь для входящих соединений
listen(SERVER, SOMAXCONN)
or die "Couldn't listen on port $server__port : $!\n";
# Принимать и обрабатывать подключения
while (accept(CLIENT, SERVER)) {
# Сделать что-то с CLIENT
}
close(SERVER);
Комментарий
Написать сервер сложнее, чем клиент. Необязательная функция listen сообщает операционной
системе, сколько подключений могут находиться в очереди к серверу, ожидая обслуживания.
Функция setsockopt, использованная в решении, позволяет избежать двухминутного интервала
после уничтожения сервера перед ею перезапуском (полезна при тестировании). Функция bind
регистрирует сервер в ядре. Наконец, функция accept последовательно принимает входящие подключения.
Числовой аргумент listen определяет количество не принятых функцией accept подключений,
которые будут поставлены в очередь операционной системой перед тем, как клиенты начнут получать
ошибки «отказ в обслуживании». Исторически максимальное значение этого аргумента было равно 5,
но и сегодня многие операционные системы тайно устанавливают максимальный размер очереди
равным примерно 20. Сильно загруженные Web-серверы стали распространенным явлением, поэтому
многие поставщики увеличивают это значение. Максимальный размер очереди для вашей системы
хранится в константе SOMAXCONN модуля Socket.
Функции accept передаются два аргумента: файловый манипулятор, подключаемый к
удаленному клиенту, и файловый манипулятор сервера. Она возвращает IP-адрес и порт
клиента, упакованные inet_ntoa:
use Socket;
while ($client_address = accept(CLIENT, SERVER)) {
($port, $packed_ip) = sockaddr_in($client_address);
$dotted_quad = inet_ntoa($packed_ip);
# Обработать
}
В классах IO::Socket accept является методом, вызываемым для манипулятора сервера:
while (($client,$client_address) = $server->accept()) {
# ...
}
Если ожидающих подключений нет, программа блокируется на вызове accept до того, как
появится подключение. Если вы хотите гарантировать, что вызов accept не будет блокироваться,
воспользуйтесь неблокирующими сокетами:
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
$flags = fcntl($SERVER, F_GETFL, 0)
or die "Can't get flags for the socket: $!\n";
$flags = fcntl($SERVER, F_SETFL, $flags | O_NONBLOCK)
or die "Can't set flags for the socket: $!\n";
Если теперь при вызове accept не окажется ожидающих подключений, accept вернет
undef и присвоит $! значение EWOULDBLOCK.
Может показаться, что при возвращении нулевых флагов от F_GETFL будет вызвана функция
die, как и при неудачном вызове, возвращающем undef. Это не так — неошибочное возвращаемое
значение fcntl, как и для ioctl, преобразуется Perl в специальное значение "0 but true".
Для этой специальной строки даже действуют надоедливые предупреждения флага -w о нечисловых
величинах, поэтому вы можете использовать ее в своих функциях, когда возвращаемое значение
равно 0 и тем не менее истинно.
См. такжеОписание функций
socket,
bind,
listen,
accept,
fcntl
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|