Учебники

Perl — Socket Программирование

Socket — это механизм Berkeley UNIX для создания виртуального дуплексного соединения между различными процессами. Позже это было перенесено на каждую известную ОС, обеспечивающую связь между системами в разных географических точках, работающих на разных ОС. Если бы не сокет, большая часть сетевого взаимодействия между системами никогда бы не произошла.

Приглядеться; типичная компьютерная система в сети получает и отправляет информацию по желанию различных приложений, работающих в ней. Эта информация направляется в систему, поскольку ей назначается уникальный IP-адрес. В системе эта информация передается соответствующим приложениям, которые прослушивают разные порты. Например, интернет-браузер прослушивает через порт 80 информацию, полученную с веб-сервера. Также мы можем написать наши пользовательские приложения, которые могут прослушивать и отправлять / получать информацию о конкретном номере порта.

А пока давайте подведем итог, что сокет — это IP-адрес и порт, позволяющий соединению отправлять и получать данные по сети.

Чтобы объяснить вышеупомянутую концепцию сокетов, мы возьмем пример программирования клиент-сервер с использованием Perl. Чтобы завершить архитектуру клиент-сервер, нам нужно пройти следующие шаги:

Создать сервер

  • Создайте сокет с помощью вызова сокета .

  • Свяжите сокет с адресом порта, используя вызов связывания .

  • Прослушивание сокета по адресу порта с помощью прослушивания вызова.

  • Примите клиентские соединения, используя принять вызов.

Создайте сокет с помощью вызова сокета .

Свяжите сокет с адресом порта, используя вызов связывания .

Прослушивание сокета по адресу порта с помощью прослушивания вызова.

Примите клиентские соединения, используя принять вызов.

Создать клиента

  • Создайте сокет с вызовом сокета .

  • Соединитесь (сокет) с сервером, используя вызов connect .

Создайте сокет с вызовом сокета .

Соединитесь (сокет) с сервером, используя вызов connect .

Следующая диаграмма показывает полную последовательность вызовов, используемых Клиентом и Сервером для связи друг с другом —

Perl Socket

Звонки на стороне сервера

Вызов сокета ()

Вызов socket () является первым вызовом, при установлении сетевого соединения создается сокет. Этот вызов имеет следующий синтаксис —

socket( SOCKET, DOMAIN, TYPE, PROTOCOL );

Вышеуказанный вызов создает SOCKET, а остальные три аргумента являются целыми числами, которые должны иметь следующие значения для соединений TCP / IP.

  • ДОМЕН должен быть PF_INET. Это вероятно 2 на вашем компьютере.

  • TYPE должен быть SOCK_STREAM для соединения TCP / IP.

  • PROTOCOL должен быть (getprotobyname (‘tcp’)) [2] . Это особый протокол, такой как TCP, который будет передаваться через сокет.

ДОМЕН должен быть 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).

Семейство адресов (для 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( SOCKET, QUEUESIZE );

Вышеупомянутый вызов использует дескриптор SOCKET, возвращаемый вызовом socket (), а QUEUESIZE — это максимальное количество ожидающих запросов на соединение, разрешенных одновременно.

Принять () вызов

Если это серверная программа, то необходимо выполнить вызов функции access (), чтобы принять входящие соединения. Этот вызов имеет следующий синтаксис —

accept( NEW_SOCKET, SOCKET );

Прием вызова принимает дескриптор SOCKET, возвращаемый функцией socket (), и после успешного завершения возвращается новый дескриптор сокета NEW_SOCKET для всей будущей связи между клиентом и сервером. Если вызов access () не удался, он возвращает FLASE, который определен в модуле Socket, который мы использовали изначально.

Обычно accept () используется в бесконечном цикле. Как только приходит одно соединение, сервер либо создает дочерний процесс для его обработки, либо обслуживает его сам, а затем возвращается, чтобы прослушать другие соединения.

while(1) {
   accept( NEW_SOCKET, SOCKT );
   .......
}

Теперь все вызовы, связанные с сервером, завершены, и давайте посмотрим вызов, который потребуется клиенту.

Звонки на стороне клиента

Вызов connect ()

Если вы собираетесь подготовить клиентскую программу, то сначала вы будете использовать вызов socket () для создания сокета, а затем вам придется использовать вызов connect () для подключения к серверу. Вы уже видели синтаксис вызова socket (), и он останется похожим на вызов сервера 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

ПРИМЕЧАНИЕ. — Если вы указываете фактический IP-адрес в точечной нотации, рекомендуется указывать IP-адрес в одном и том же формате как на клиенте, так и на сервере, чтобы избежать путаницы.