Текст книги "Основы программирования в Linux"
Автор книги: Нейл Мэтью
Соавторы: Ричард Стоунс
Жанры:
Программирование
,сообщить о нарушении
Текущая страница: 55 (всего у книги 67 страниц)
Для того чтобы до конца понять системные вызовы, применявшиеся в рассмотренном примере, необходимо узнать кое-что об организации сети в системах UNIX.
Сокеты характеризуются тремя атрибутами: доменом, типом и протоколом. У них также есть адрес, используемый как имя сокета. Форматы адресов меняются в зависимости от домена, также называемого семейством протоколов (protocol family). Каждое семейство протоколов может применять одно или несколько семейств адресов, определяющих формат адреса.
Домены сокетов
Домены задают сетевую рабочую среду, которую будет использовать соединение сокетов. Самый популярный домен сокетов – AF_INET
, ссылающийся на сеть Интернет и применяемый во многих локальных сетях Linux и, конечно, в самом Интернете. Низкоуровневый протокол Internet Protocol (IP), у которого только одно адресное семейство, накладывает определенный способ задания компьютеров, входящих в сеть. Он называется IP-адресом.
Примечание
Для преодоления некоторых проблем стандартного протокола IP существенно ограниченного количества доступных адресов был разработан интернет-протокол нового поколения IPv6. Он использует другой домен сокетов
AF_INET6
и иной формат адресов. Ожидается, что со временем IPv6 заменит IP, но для этого потребуется много лет. Несмотря на то, что уже есть реализации IPv6 для Linux, их обсуждение выходит за рамки этой книги.
Несмотря на то, что у машин в Интернете почти всегда есть имена, их преобразуют в IP-адреса. Пример IP-адреса – 192.168.1.99. Все IP-адреса представлены четырьмя числами, каждое из которых меньше 256, и образуют так называемые четверки с точками. Когда клиент подключается по сети с помощью сокетов, ему нужен IP– адрес компьютера сервера.
На компьютере сервера может быть доступно несколько сервисов. Клиент может обратиться к конкретному сервису на компьютере, включенном в сеть, с помощью IP-порта. Внутри системы порт идентифицируется уникальным 16-разрядным целым числом, а за пределами системы – комбинацией IP-адреса и номера порта. Сокеты – это коммуникационные конечные точки, которые должны быть связаны с портами, прежде чем передача данных станет возможна.
Серверы ожидают запросов на соединения от определенных клиентов. У хорошо известных сервисов есть выделенные номера портов, которые используются всеми машинами под управлением ОС Linux и UNIX. Обычно, но не всегда, эти номера меньше 1024. Примерами могут служить буфер печати принтера (515), rlogin
(513), ftp
(21) и httpd
(80). Последний из названных – стандартный порт для Web-серверов. Обычно номера портов, меньшие 1024, зарезервированы для системных сервисов и могут обслуживаться процессами с правами суперпользователя. Стандарт X/Open определяет в заголовочном файле netdb.h константу IPPORT_RESERVED
для указания наибольшего номера зарезервированных портов.
Поскольку для стандартных сервисов есть стандартный набор номеров портов, компьютеры могут легко соединяться друг с другом, не угадывая правильный номер порта. Локальный сервисы могут применять адреса нестандартных портов.
Домен в первом упражнении, AF_UNIX
, – это домен файловой системы UNIX, который может использоваться сокетами, находящимися на единственном компьютере, возможно, даже не входящем в сеть. Если это так, то низкоуровневый протокол – это файловый ввод/вывод, а адреса – имена файлов. Для сокета сервера применялся адрес server_socket
, который, как вы видели, появлялся в текущем каталоге, когда вы выполняли серверное приложение.
Кроме того, могут применяться и другие домены: AF_ISO
для сетей на основе стандартных протоколов ISO и AF_XNS
для Xerox Network System (сетевая система Xerox). В этой книге мы их не будем обсуждать.
Типы сокетов
У домена сокетов может быть несколько способов обмена данными, у каждого из которых могут быть разные характеристики. В случае сокетов домена AF_UNIX
проблемы не возникают, т.к, они обеспечивают надежный двунаправленный обмен данными. В сетевых доменах необходимо знать характеристики базовой сети и их влияние на различные механизмы передачи данных.
Интернет-протоколы предоставляют два механизма передачи данных с разными уровнями обслуживания: потоки и дейтаграммы.
Потоковые сокеты
Потоковые сокеты (в чем-то подобные стандартным потокам ввода/вывода) обеспечивают соединение, представляющее собой последовательный и надежный двунаправленный поток байтов. Следовательно, гарантируется, что без указания возникшей ошибки данные не будут потеряны, продублированы или переупорядочены. Сообщения большого объема фрагментируются, передаются и снова собираются воедино. Это напоминает файловый поток, который принимает большие объемы данных и делит их на меньшие блоки для записи на физический диск. У потоковых сокетов предсказуемое поведение.
Потоковые сокеты, описываемые типом SOCK_STREAM
, реализованы в домене AF_INET
соединениями на базе протоколов TCP/IP. Кроме того, это обычный тип сокетов и в домене AF_UNIX
. В этой главе мы сосредоточимся на сокетах типа SOCK_STREAM
, поскольку они чаще всего применяются при программировании сетевых приложений.
Примечание
TCP/IP – сокращение для протоколов Transmission Control Protocol/Internet Protocol. Протокол IP – низкоуровневый протокол передачи пакетов, обеспечивающий выбор маршрута при пересылке данных в сети от одного компьютера к другому. Протокол TCP обеспечивает упорядочивание, управление потоком и ретрансляцию, гарантирующие полную и корректную передачу больших объемов данных или же сообщение о соответствующей ошибочной ситуации.
Дейтаграммные сокеты
В отличие от потоковых дейтаграммные сокеты, описываемые типом SOCK_DGRAM
, не устанавливают и не поддерживают соединение. Кроме того, существует ограничение для размера дейтаграммы, которая может отправляться. Она передается как единое сетевое сообщение, которое может быть потеряно, продублировано или прибыть несвоевременно, т.е. перед дейтаграммами, посланными после нее.
Дейтаграммные сокеты реализованы в домене AF_INET
с помощью соединений UDP/IP и предоставляют неупорядоченный ненадежный сервис. (UDP сокращенное название протокола User Datagram Protocol.) Однако они относительно экономичны с точки зрения расходования ресурсов, поскольку не нуждаются в поддержке сетевых соединений. Они быстры, т.к. не тратится время на установку сетевого соединения.
Дейтаграммы полезны для однократных запросов к информационным сервисам, для предоставления обычных сведений о состоянии или для выполнения низкоприоритетной регистрации данных. Их преимущество в том, что остановка сервера не причинит чрезмерных неудобств клиенту и не потребует перезапуска клиента. Поскольку серверы на базе дейтаграмм обычно сохраняют данные без соединения, их можно останавливать и запускать снова, не мешая их клиентам.
На этом мы закончим обсуждение дейтаграмм, дополнительную информацию см. в разд. «Дейтаграммы» в конце данной главы.
Протоколы сокетов
Если низкоуровневый механизм передачи данных позволяет применять несколько протоколов, предоставляющих сокет требуемого типа, можно выбрать конкретный протокол или сокет. В этой главе мы сосредоточимся на сокетах сети UNIX и ее файловой системы, которые не требуют от вас выбора протокола, отличного от заданного по умолчанию.
Создание сокетаСистемный вызов socket создает сокет и возвращает дескриптор, который может применяться для доступа к сокету:
#include
#include
int socket(int domain, int type, int protocol);
Созданный сокет – это одна конечная точка линии передачи. Параметр domain
задает семейство адресов, параметр type
определяет тип используемого с этим сокетом обмена данными, a protocol
– применяемый протокол.
В табл. 15.1 приведены имена доменов.
Таблица 15.1
AF_UNIX | Внутренние для UNIX (сокеты файловой системы) |
AF_INET | Интернет-протоколы ARPA (Advanced Research Projects Agency, управление перспективных исследований и разработок) (сокеты сети UNIX) |
AF_ISO | Протоколы стандарта ISO (International Standards Organization, Международная организация по стандартизации) |
AF_NS | Протоколы сетевых систем Xerox |
AF_IPX | Novell-протокол IPX |
AF_APPLETALK | Appletalk DDS (Appletalk Digital Data Service) |
К наиболее популярным доменам сокетов относятся AF_UNIX
, применяемый для локальных сокетов, реализуемых средствами файловых систем UNIX и Linux, и AF_INET
, используемый для сетевых сокетов UNIX. Сокеты домена AF_INET
могут применяться программами, взаимодействующими в сетях на базе протоколов TCP/IP, включая Интернет. Интерфейс ОС Windows Winsock также предоставляет доступ к этому домену сокетов.
Параметр сокета type задает характеристики обмена данными, применяемые для нового сокета. Возможными значениями могут быть SOCK_STREAM
и SOCK_DGRAM
.
□ SOCK_STREAM
– это упорядоченный, надежный, основанный на соединении, двунаправленный поток байтов. В случае домена сокетов AF_INET
этот тип обмена данными по умолчанию обеспечивается TCP-соединением, которое устанавливается между двумя конечными точками потоковых сокетов при подключении. Данные могут передаваться в двух направлениях по линии связи сокетов. Протоколы TCP включают в себя средства фрагментации и последующей повторной сборки сообщений больших объемов и повторной передачи любых их частей, которые могли быть потеряны в сети.
□ SOCK_DGRAM
– дейтаграммный сервис. Вы можете использовать такой сокет для отправки сообщений с фиксированным (обычно небольшим) максимальным объемом, но при этом нет гарантии, что сообщение будет доставлено или что сообщения не будут переупорядочены в сети. В случае сокетов домена AF_INET
этот тип передачи данных обеспечивается дейтаграммами UDP (User Datagram Protocol, пользовательский протокол дейтаграмм).
Протокол, применяемый для обмена данными, обычно определяется типом сокета и доменом. Как правило, выбора нет. Параметр protocol
применяется в тех случаях, когда выбор все же предоставляется. Задание 0 позволяет выбрать стандартный протокол, используемый во всех примерах данной главы.
Системный вызов socket
возвращает дескриптор, во многом похожий на низкоуровневый файловый дескриптор. Когда сокет подключен к концевой точке другого сокета, для отправки и получения данных с помощью сокетов можно применять системные вызовы read
и write
с дескриптором сокета. Системный вызов close
используется для удаления сокетного соединения.
Каждый домен сокетов требует своего формата адресов. В домене AF_UNIX
адрес описывается структурой sockaddr_un
, объявленной в заголовочном файле sys/un.h:
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[]; /* Путь к файлу */
};
Для того чтобы адреса разных типов могли передаваться в системные вызовы для обработки сокетов, все адресные форматы описываются похожей структурой, которая начинается с поля (в данном случае sun_family
), задающего тип адреса (домен сокета). В домене AF_UNIX
адрес задается именем файла в поле структуры sun_path
.
В современных системах Linux тип sa_family_t
, описанный в стандарте X/Open как объявляемый в заголовочном файле sys/un.h, интерпретируется как тип short
. Кроме того, размер pathname
, задаваемого в поле sun_path
, ограничен (в Linux указывается 108 символов; в других системах может применяться именованная константа, например, UNIX_MAX_PATH
). Поскольку размер адресной структуры может меняться, многие системные вызовы сокетов требуют или предоставляют на выходе длину, которая будет использоваться для копирования конкретной адресной структуры.
В домене AF_INET
адрес задается с помощью структуры с именем sockaddr_in
, определенной в файле netinet/in.h, которая содержит как минимум следующие элементы:
struct sockaddr_in {
short int sin_family; /* AF_INET */
unsigned short int sin_port; /* Номер порта */
struct in_addr sin_addr; /* Интернет-адрес */
};
Структура IP-адреса типа in_addr определена следующим образом:
struct in_addr {
unsigned long int s_addr;
};
Четыре байта IP-адреса образуют одно 32-разрядное значение. Сокет домена AF_INET
полностью описывается IP-адресом и номером порта. С точки зрения приложения все сокеты действуют как файловые дескрипторы, и их адреса задаются уникальными целочисленными значениями.
Для того чтобы сделать сокет (созданный с помощью вызова socket
) доступным для других процессов, серверная программа должна присвоить сокету имя. Сокеты домена AF_UNIX
связаны с полным именем файла в файловой системе, как вы видели в программе-примере server1. Сокеты домена AF_INET
связаны с номером IP-порта.
#include
int bind(int socket, const struct sockaddr *address, size_t address len);
Системный вызов bind
присваивает адрес, заданный в параметре address
, неименованному сокету, связанному с дескриптором сокета socket
. Длина адресной структуры передается в параметре address_len
:
Длина и формат адреса зависят от адресного семейства. В системном вызове bind
указатель конкретной адресной структуры должен быть приведен к обобщенному адресному типу (struct sockaddr*)
.
В случае успешного завершения bind
возвращает 0. Если он завершается аварийно, возвращается -1, и переменной errno
присваивается одно из значений, перечисленных в табл. 15.2.
Таблица 15.2
errno | |
---|---|
EBADF | Неверный файловый дескриптор |
ENOTSOCK | Файловый дескриптор не ссылается на сокет |
EINVAL | Файловый дескриптор ссылается на сокет, уже получивший имя |
EADDRNOTAVAIL | Недопустимый адрес |
EADDINUSE | У адреса уже есть связанный с ним сокет |
Для сокетов домена AF_UNIX есть несколько дополнительных значений | |
EACCESS | Невозможно создать имя в файловой системе из-за прав доступа |
ENOTDIR , ENAMETOOLONG | Означает недопустимое имя файла |
Создание очереди сокетов
Для приема запросов на входящие соединения на базе сокетов серверная программа должна создать очередь для хранения ждущих обработки запросов. Формируется она с помощью системного вызова listen
.
#include
int listen(int socket, int backlog);
Система Linux может ограничить количество ждущих обработки соединений, которые могут храниться в очереди. В соответствии с этим максимумом вызов listen
задает длину очереди, равной backlog
. Входящие соединения, не превышающие максимальной длины очереди, сохраняются в ожидании сокета; последующим запросам на соединение будет отказано, и клиентская попытка соединения завершится аварийно. Этот механизм реализуется вызовом listen
для того, чтобы можно было сохранить ждущие соединения запросы, пока серверная программа занята обработкой запроса предыдущего клиента. Очень часто параметр backlog
равен 5.
Функция listen
вернет 0 в случае успешного завершения и -1 в случае ошибки. Как и для системного вызова bind
, ошибки могут обозначаться константами EBADF
, EINVAL
И ENOTSOCK
.
После создания и именования сокета серверная программа может ждать запросы на выполнение соединения с сокетом с помощью системного вызова accept
:
#include
int accept(int socket, struct sockaddr *address, size_t *address_len);
Системный вызов accept
возвращает управление, когда клиентская программа пытается подключиться к сокету, заданному в параметре socket
. Этот клиент – первый из ждущих соединения в очереди данного сокета. Функция accept
создает новый сокет для обмена данными с клиентом и возвращает его дескриптор. У нового сокета будет тот же тип, что и у сокета сервера, ждущего запросы на соединения.
Предварительно сокету должно быть присвоено имя с помощью системного вызова bind
и у него должна быть очередь запросов на соединение, место для которой выделил системный вызов listen
. Адрес вызывающего клиента будет помещен в структуру sockaddr
, на которую указывает параметр address
. Если адрес клиента не представляет интереса, в этом параметре может задать пустой указатель.
Параметр address_len
задает длину адресной структуры клиента. Если адрес клиента длиннее, чем это значение, он будет урезан. Перед вызовом accept
в параметре address_len
должна быть задана ожидаемая длина адреса. По возвращении из вызова в address_len
будет установлена реальная длина адресной структуры запрашивающего соединение клиента.
Если нет запросов на соединение, ждущих в очереди сокета, вызов accept будет заблокирован (так что программа не сможет продолжить выполнение) до тех пор, пока клиент не сделает запрос на соединение. Вы можете изменить это поведение, применив флаг O_NONBLOCK
в файловом дескрипторе сокета с помощью вызова fcntl
в вашей программе следующим образом:
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, O_NONBLOCK | flags);
Функция accept
возвращает файловый дескриптор нового сокета, если есть запрос клиента, ожидающего соединения, и -1 в случае ошибки. Возможные значения ошибок такие же, как у вызовов bind
и listen
плюс дополнительная константа EWOULDBLOCK
в случае, когда задан флаг O_NONBLOCK
и нет ждущих запросов на соединение. Ошибка EINTR
возникнет, если процесс прерван во время блокировки в функции accept
.
Клиентские программы подключаются к серверам, устанавливая соединение между неименованным сокетом и сокетом сервера, ждущим подключений. Делают они это с помощью вызова connect
:
#include
int connect(int socket, const struct sockaddr *address, size_t address_len);
Сокет, заданный в параметре socket
, соединяется с сокетом сервера, заданным в параметре address
, длина которого равна address_len
. Сокет должен задаваться корректным файловым дескриптором, полученным из системного вызова socket
.
Если функция connect
завершается успешно, она возвращает 0, в случае ошибки вернется -1. Возможные ошибки на этот раз включают значения, перечисленные в табл. 15.3.
Таблица 15.3
errno | |
---|---|
EBADF | В параметре socket задан неверный файловый дескриптор |
EALREADY | Для этого сокета соединение уже обрабатывается |
ETIMEDOUT | Допустимое время ожидания соединения превышено |
ECONNREFUSED | Запрос на соединение отвергнут сервером |
Если соединение не может быть установлено немедленно, вызов connect
будет заблокирован на неопределенный период ожидания. Когда допустимое время ожидания будет превышено, соединение разорвется и вызов connect
завершится аварийно. Однако, если вызов прерван сигналом, который обрабатывается, connect завершится аварийно (со значением errno, равным EINTR
), но попытка соединения не будет прервана – соединение будет установлено асинхронно и программа должна будет позже проверить, успешно ли оно установлено.
Как и в случае вызова accept
, возможность блокировки в вызове connect
можно исключить установкой в файловом дескрипторе флага O_NONBLOCK
. В этом случае, если соединение не может быть установлено немедленно, вызов connect
завершится аварийно с переменной errno
, равной EINPROGRESS
, и соединение будет выполнено асинхронно.
Хотя асинхронные соединения трудно обрабатывать, вы можете применить вызов select
к файловому дескриптору сокета, чтобы убедиться в том, что сокет готов к записи. Мы обсудим вызов select
чуть позже в этой главе.
Вы можете разорвать сокетное соединение в серверной или клиентской программах, вызвав функцию close
, так же как в случае низкоуровневых файловых дескрипторов. Сокеты следует закрывать на обоих концах. На сервере это нужно делать, когда read
вернет ноль. Имейте в виду, что вызов close
может быть заблокирован, если сокет, у которого есть непереданные данные, обладает типом, ориентированным на соединение, и установленным параметром SOCK_LINGER
. Дополнительную информацию об установке параметров сокета вы узнаете позже в этой главе.
Теперь, когда мы описали основные системные вызовы, связанные с сокетами, давайте повнимательнее рассмотрим программы-примеры. Вы попытаетесь переработать их, заменив сокет файловой системы сетевым сокетом. Недостаток сокета файловой системы состоит в том, что если автор не использует полное имя файла, он создается в текущем каталоге серверной программы. Для того чтобы сделать его полезным в большинстве случаев, следует создать сокет в общедоступном каталоге (например, /tmp), подходящем для сервера и его клиентов. В случае сетевых серверов достаточно выбрать неиспользуемый номер порта.
Для примера выберите номер порта 9734. Это произвольный выбор, позволяющий избежать использования портов стандартных сервисов (вы не должны применять номера портов, меньшие 1024, поскольку они зарезервированы для системного использования). Другие номера портов с обеспечиваемыми ими сервисами часто приводятся в системном файле /etc/services. При написании программ, использующих сокеты, всегда выбирайте номер порта, которого нет в этом файле конфигурации.
Примечание
Вам следует знать, что в программах client2.c и server2.c умышленно допущена ошибка, которую вы устраните в программах client3.c и server3.c. Пожалуйста, не используйте текст примеров client2.c и server2.c в собственных программах.
Вы будете выполнять ваши серверную и клиентскую программы в локальной сети, но сетевые сокеты полезны не только в локальной сети, любая машина с подключением к Интернету (даже по модемной линии связи) может применять сетевые сокеты для обмена данными с другими компьютерами. Программу, основанную на сетевых подключениях, можно применять даже на изолированном компьютере с ОС UNIX, т. к. такой компьютер обычно настроен на использование виртуальной сети или внутренней петли (loopback network), включающей только его самого. Для демонстрационных целей данный пример использует виртуальную сеть, которая может быть также полезна для отладки сетевых приложений, поскольку она устраняет любые внешние сетевые проблемы.
Виртуальная сеть состоит из единственного компьютера, традиционно именуемого localhost
, со стандартным IP-адресом 127.0.0.1. Это локальная машина. Ее адрес вы сможете найти в файле сетевых узлов etc/hosts наряду с именами и адресами других узлов, входящих в совместно используемые сети.
У каждой сети, с которой компьютер обменивается данными, есть связанный с ней аппаратный интерфейс. У компьютера в каждой сети может быть свое имя и конечно будут разные IP-адреса. Например, у машины Нейла с именем tilde три сетевых интерфейса и, следовательно, три адреса. Они записаны в файле /etc/hosts следующим образом.
127.0.0.1 localhost # Петля
192.168.1.1 tilde.localnet # Локальная частная сеть Ethernet
158.152.X.X tilde.demon.co.uk # Модемная линия связи
Первая строка – пример виртуальной сети, ко второй сети доступ осуществляется с помощью адаптера Ethernet, а третья – модемная линия связи с провайдером интернет-сервисов. Вы можете написать программу, применяющую сетевые сокеты, для связи с серверами с помощью любого из приведенных интерфейсов без каких-либо корректировок.
Выполните упражнения 15.3 и 15.4.
Упражнение 15.3. Сетевой клиент
Далее приведена измененная программа-клиент client2.c, предназначенная для использования сетевого соединения на базе сокета в виртуальной сети. Она содержит незначительную ошибку, связанную с аппаратной зависимостью, но мы обсудим ее чуть позже в этой главе.
1. Включите необходимые директивы #include
и задайте переменные:
#include
#include
#include
#include
#include
#include
#include
int main() {
int sockfd;
int len;
struct sockaddr_in address;
int result;
char ch = 'A';
2. Создайте сокет клиента:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
3. Присвойте имя сокету по согласованию с сервером:
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(«127.0.0.1»);
address.sin_port = 9734;
len = sizeof(address);
Оставшаяся часть программы такая же, как в приведенном ранее в этой главе примере. Когда вы выполните эту версию, она завершится аварийно, потому что на данном компьютере нет сервера, выполняющегося на порте 9734.
$ ./client2
oops: client2: Connection refused
$
Как это работает
Клиентская программа использует структуру sockaddr_in
из заголовочного файла netinet/in.h для задания адреса AF_INET
. Она пытается подключиться к серверу, размещенному на узле с IP-адресом 127.0.0.1. Программа применяет функцию inet_addr
для преобразования текстового представления IP-адреса в форму, подходящую для адресации сокетов. На страницах интерактивного справочного руководства для inet вы найдете дополнительную информацию о других функциях, преобразующих адреса.
Упражнение 15.4. Сетевой сервер
Вам также нужно модифицировать серверную программу, ждущую подключений на выбранном вами номере порта. Далее приведена откорректированная программа сервера server2.c.
1. Вставьте необходимые заголовочные файлы и задайте переменные:
#include
#include
#include
#include
#include
#include
#include
int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
2. Создайте неименованный сокет для сервера:
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
3. Дайте имя сокету:
server_address.sin_family = AF_INET;
server_address.sin_port.s_addr = inet_addr(«127.0.0.1»);
server_address.sin_port = 9734;
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
С этой строки и далее текст примера точно совпадает с программным кодом в файле server1.c. Выполнение client2 и server2 продемонстрирует то же поведение, что и при запуске программ client1 и server1.
Как это работает
Серверная программа создает сокет домена AF_INET
и выполняет необходимые действия для приема запросов на подключение к нему. Сокет связывается с выбранным вами портом. Заданный адрес определяет, каким машинам разрешено подсоединяться. Задавая такой же адрес виртуальной сети, как в клиентской программе, вы ограничиваете соединения только локальной машиной.
Если вы хотите разрешить серверу устанавливать соединения с удаленными клиентами, необходимо задать набор IP-адресов, которые разрешены. Можно применить специальное значение INADDR_ANY
для того, чтобы показать, что будете принимать запросы на подключение от всех интерфейсов, имеющихся на вашем компьютере. Если необходимо, вы можете разграничить интерфейсы разных сетей, чтобы отделить соединения локальной сети от соединений глобальной сети. Константа INADDR_ANY
– 32-разрядное целое число, которое можно использовать в поле sin_addr.s_addr
адресной структуры. Но прежде вам нужно решить проблему.