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-адрес в одном и том же формате как на клиенте, так и на сервере, чтобы избежать путаницы.