Perl - Программирование сокетов
Что такое розетка?
Socket - это механизм Berkeley UNIX для создания виртуального дуплексного соединения между различными процессами. Позже это было перенесено на все известные ОС, что позволило осуществлять связь между системами в разных географических регионах, работающими на другом программном обеспечении ОС. Если бы не сокет, большая часть сетевого взаимодействия между системами никогда бы не произошла.
Присмотревшись; типичная компьютерная система в сети получает и отправляет информацию по желанию различных приложений, работающих в ней. Эта информация направляется в систему, поскольку ей назначается уникальный IP-адрес. В системе эта информация передается соответствующим приложениям, которые прослушивают разные порты. Например, интернет-браузер прослушивает порт 80 для получения информации от веб-сервера. Также мы можем написать наши собственные приложения, которые могут прослушивать и отправлять / получать информацию по определенному номеру порта.
А пока подведем итог, что сокет - это IP-адрес и порт, позволяющие соединению отправлять и получать данные по сети.
Чтобы объяснить вышеупомянутую концепцию сокета, мы рассмотрим пример клиент-серверного программирования с использованием Perl. Чтобы завершить архитектуру клиент-сервер, нам нужно будет выполнить следующие шаги:
Чтобы создать сервер
Создайте сокет, используя socket вызов.
Привяжите сокет к адресу порта, используя bind вызов.
Слушайте сокет по адресу порта, используя listen вызов.
Принимать клиентские подключения с помощью accept вызов.
Чтобы создать клиента
Создайте сокет с socket вызов.
Подключите (сокет) к серверу, используя connect вызов.
На следующей диаграмме показана полная последовательность вызовов, используемых клиентом и сервером для связи друг с другом.
Вызовы через сокеты на стороне сервера
Вызов socket ()
В socket()вызов - это первый вызов при установлении сетевого соединения - создание сокета. Этот вызов имеет следующий синтаксис -
socket( SOCKET, DOMAIN, TYPE, PROTOCOL );
Вышеупомянутый вызов создает СОКЕТ, а другие три аргумента являются целыми числами, которые должны иметь следующие значения для соединений TCP / IP.
DOMAINдолжен быть PF_INET. Вероятно, 2 на вашем компьютере.
TYPE должен быть SOCK_STREAM для TCP / IP-соединения.
PROTOCOL должно быть (getprotobyname('tcp'))[2]. Это конкретный протокол, такой как TCP, для разговора через сокет.
Таким образом, вызов функции сокета, выданный сервером, будет примерно таким:
use Socket # This defines PF_INET and SOCK_STREAM
socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]);
Вызов bind ()
Сокеты, созданные вызовом socket (), бесполезны, пока они не будут привязаны к имени хоста и номеру порта. Сервер использует следующиеbind() функция, чтобы указать порт, на котором они будут принимать соединения от клиентов.
bind( SOCKET, ADDRESS );
Здесь SOCKET - это дескриптор, возвращаемый вызовом socket (), а ADDRESS - это адрес сокета (для TCP / IP), содержащий три элемента:
Семейство адресов (для TCP / IP это AF_INET, вероятно, 2 в вашей системе).
Номер порта (например 21).
Интернет-адрес компьютера (например, 10.12.12.168).
Поскольку bind () используется сервером, которому не нужно знать свой собственный адрес, список аргументов выглядит так:
use Socket # This defines PF_INET and SOCK_STREAM
$port = 12345; # The unique port used by the sever to listen requests
$server_ip_address = "10.12.12.168";
bind( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address)))
or die "Can't bind to port $port! \n";
В or die предложение очень важно, потому что если сервер умирает без невыполненных соединений, порт не будет немедленно повторно использован, если вы не используете параметр SO_REUSEADDR, используя setsockopt()функция. Вотpack_sockaddr_in() функция используется для упаковки порта и IP-адреса в двоичный формат.
Вызов listen ()
Если это серверная программа, то необходимо вызвать listen()на указанном порту слушать, т. е. ждать входящих запросов. Этот вызов имеет следующий синтаксис -
listen( SOCKET, QUEUESIZE );
Вышеупомянутый вызов использует дескриптор SOCKET, возвращаемый вызовом socket (), а QUEUESIZE - это максимальное количество одновременно разрешенных невыполненных запросов на соединение.
Вызов accept ()
Если это серверная программа, то необходимо вызвать access()функция для приема входящих соединений. Этот вызов имеет следующий синтаксис -
accept( NEW_SOCKET, SOCKET );
Вызов accept принимает дескриптор SOCKET, возвращаемый функцией socket (), и после успешного завершения возвращается новый дескриптор сокета NEW_SOCKET для всей будущей связи между клиентом и сервером. Если вызов access () завершается неудачно, он возвращает FLASE, который определен в модуле Socket, который мы использовали изначально.
Обычно accept () используется в бесконечном цикле. Как только приходит одно соединение, сервер либо создает дочерний процесс для работы с ним, либо обслуживает его сам, а затем возвращается, чтобы прослушать другие соединения.
while(1) {
accept( NEW_SOCKET, SOCKT );
.......
}
Теперь все вызовы, связанные с сервером, завершены, и мы видим вызов, который потребуется клиенту.
Вызовы через сокеты на стороне клиента
Вызов connect ()
Если вы собираетесь подготовить клиентскую программу, то сначала воспользуйтесь socket() вызов для создания сокета, а затем вам придется использовать connect()вызов для подключения к серверу. Вы уже видели синтаксис вызова socket (), и он останется аналогичным вызову server socket (), но вот синтаксис дляconnect() звонок -
connect( SOCKET, ADDRESS );
Здесь SCOKET - это дескриптор сокета, возвращаемый вызовом socket (), выданным клиентом, а ADDRESS - это адрес сокета, аналогичный вызову привязки , за исключением того, что он содержит IP-адрес удаленного сервера.
$port = 21; # For example, the ftp port
$server_ip_address = "10.12.12.168";
connect( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address)))
or die "Can't connect to port $port! \n";
Если вы успешно подключитесь к серверу, вы можете начать отправлять свои команды на сервер, используя дескриптор SOCKET, иначе ваш клиент выйдет, выдав сообщение об ошибке.
Клиент - Пример сервера
Ниже приведен код Perl для реализации простой клиент-серверной программы с использованием сокета Perl. Здесь сервер прослушивает входящие запросы и после установления соединения просто отвечает Smile с сервера . Клиент читает это сообщение и печатает на экране. Давайте посмотрим, как это было сделано, если у нас есть сервер и клиент на одной машине.
Скрипт для создания сервера
#!/usr/bin/perl -w
# Filename : server.pl
use strict;
use Socket;
# use port 7890 as default
my $port = shift || 7890;
my $proto = getprotobyname('tcp');
my $server = "localhost"; # Host IP running the server
# create a socket, make it reusable
socket(SOCKET, PF_INET, SOCK_STREAM, $proto)
or die "Can't open socket $!\n";
setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR, 1)
or die "Can't set socket option to SO_REUSEADDR $!\n";
# bind to a port, then listen
bind( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
or die "Can't bind to port $port! \n";
listen(SOCKET, 5) or die "listen: $!";
print "SERVER started on port $port\n";
# accepting a connection
my $client_addr;
while ($client_addr = accept(NEW_SOCKET, SOCKET)) {
# send them a message, close connection
my $name = gethostbyaddr($client_addr, AF_INET );
print NEW_SOCKET "Smile from the server";
print "Connection recieved from $name\n";
close NEW_SOCKET;
}
Чтобы запустить сервер в фоновом режиме, введите следующую команду в командной строке Unix -
$perl sever.pl&
Скрипт для создания клиента
!/usr/bin/perl -w
# Filename : client.pl
use strict;
use Socket;
# initialize host and port
my $host = shift || 'localhost';
my $port = shift || 7890;
my $server = "localhost"; # Host IP running the server
# create the socket, connect to the port
socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2])
or die "Can't create a socket $!\n";
connect( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
or die "Can't connect to port $port! \n";
my $line;
while ($line = <SOCKET>) {
print "$line\n";
}
close SOCKET or die "close: $!";
Теперь давайте запустим наш клиент в командной строке, который подключится к серверу и прочитает сообщение, отправленное сервером, и отобразит его на экране следующим образом:
$perl client.pl
Smile from the server
NOTE - Если вы указываете фактический IP-адрес в точечной нотации, рекомендуется указывать IP-адрес в одном и том же формате как на клиенте, так и на сервере, чтобы избежать путаницы.