Сокеты Berkeley

редактировать

Сокеты Berkeley - это интерфейс прикладного программирования (API) для Интернет-сокетов и доменные сокеты Unix, используемые для межпроцессного взаимодействия (IPC). Обычно он реализуется как библиотека связываемых модулей. Он возник в операционной системе 4.2BSD Unix, выпущенной в 1983 году.

Сокет - это абстрактное представление (дескриптор ) для локальной конечной точки сетевого коммуникационного пути.. API сокетов Беркли представляет его как файловый дескриптор (дескриптор файла ) в философии Unix, который обеспечивает общий интерфейс для ввода и вывода в потоки. данных.

Сокеты Berkeley с небольшими изменениями превратились из стандарта де-факто в компонент спецификации POSIX. Термин сокеты POSIX по существу является синонимом сокетов Беркли, но они также известны как сокеты BSD, что свидетельствует о первой реализации в Распространении программного обеспечения Беркли.

Содержание
  • 1 История и реализации
    • 1.1 Сокеты BSD и POSIX
    • 1.2 Альтернативы
  • 2 Заголовочные файлы
  • 3 Функции Socket API
    • 3.1 socket
    • 3.2 bind
    • 3.3 listen
    • 3.4 accept
    • 3.5 connect
    • 3.6 gethostbyname и gethostbyaddr
  • 4 Протоколы и семейства адресов
    • 4.1 Необработанные сокеты
  • 5 Опции для сокетов
  • 6 Блокирующий и неблокирующий режим
  • 7 Завершающие сокеты
  • 8 Клиент- Пример сервера с использованием TCP
    • 8.1 Сервер
    • 8.2 Клиент
  • 9 Пример клиент-сервер с использованием UDP
    • 9.1 Сервер
    • 9.2 Клиент
  • 10 Ссылки
  • 11 Внешние ссылки
История и реализации

Сокеты Беркли возникли в операционной системе 4.2BSD Unix , выпущенной в 1983 году, как интерфейс программирования. Однако только в 1989 году Калифорнийский университет в Беркли не смог выпустить версии операционной системы и сетевой библиотеки, свободные от лицензионных ограничений проприетарной Unix ATT Corporation.

Все современные операционные системы реализуют версию интерфейса сокетов Беркли. Он стал стандартным интерфейсом для приложений, работающих в Интернете. Даже реализация Winsock для MS Windows, созданная независимыми разработчиками, полностью соответствует стандарту.

API сокетов BSD написан на языке программирования C. Большинство других языков программирования предоставляют аналогичные интерфейсы, обычно написанные как библиотека-оболочка на основе C API.

BSD и POSIX сокеты

По мере развития API сокетов Berkeley и в конечном итоге дало API сокетов POSIX, некоторые функции были объявлены устаревшими или удалены и заменены другими. POSIX API также разработан для повторного входа.

ActionBSDPOSIX
Преобразование из текстового адреса в упакованный адресinet_atoninet_pton
Преобразование упакованного адреса в текстовый адресinet_ntoainet_ntop
Прямой поиск имени хоста / службыgethostbyname, gethostbyaddr, getservbyname, getservbyportgetaddrinfo
Обратный поиск имени хоста / службыgethostbyaddr, getservbyportgetnameinfo

Альтернативы

На основе STREAMS Интерфейс транспортного уровня (TLI) API предлагает альтернативу API сокетов. Многие системы, которые предоставляют TLI API, также предоставляют API сокетов Berkeley.

Системы, отличные от Unix, часто предоставляют API сокетов Berkeley со слоем трансляции в собственный сетевой API. Plan 9 и Genode используют API файловой системы с управляющими файлами, а не с файловыми дескрипторами.

Заголовочные файлы

Интерфейс сокета Беркли определен в нескольких заголовочных файлах. Имена и содержимое этих файлов немного различаются между реализациями. Как правило, они включают:

ФайлОписание
sys/socket.hОсновные функции сокета и структуры данных.
netinet/in.hсемейства адресов AF_INET и AF_INET6 и их соответствующие семейства протоколов, PF_INET и PF_INET6. К ним относятся стандартные IP-адреса и номера портов TCP и UDP.
sys/un.hСемейство адресов PF_UNIX и PF_LOCAL. Используется для локальной связи между программами, работающими на одном компьютере.
arpa/inet.hФункции для управления числовыми IP-адресами.
netdb.hФункции для преобразования имен протоколов и имен хостов в числовые адреса. Ищет локальные данные, а также службы имен.
Функции Socket API
Блок-схема транзакции клиент-сервер с использованием сокетов с протоколом управления передачей (TCP).

API сокетов Berkeley обычно предоставляет следующие функции:

  • socket () создает новый сокет определенного типа, идентифицируемого целым числом, и выделяет ему системные ресурсы.
  • bind () обычно используется на стороне сервера и связывает сокет со структурой адреса сокета, то есть с указанным локальным IP-адрес и номер порта .
  • listen () используются на стороне сервера и заставляют привязанный TCP-сокет перейти в состояние прослушивания.
  • connect () используется на на стороне клиента и назначает сокету свободный номер локального порта. В случае TCP-сокета это вызывает попытку установить новое TCP-соединение.
  • accept () используется на стороне сервера. Он принимает полученную входящую попытку создать новое TCP-соединение от удаленного клиента и создает новый сокет, связанный с парой адресов сокета этого соединения.
  • send (), recv (), sendto (), и recvfrom () используются для отправки и получения данных. Стандартные функции write () и read () также могут использоваться.
  • close () заставляет систему высвобождать ресурсы, выделенные сокету. В случае TCP соединение разрывается.
  • gethostbyname () и gethostbyaddr () используются для разрешения имен и адресов хостов. Только IPv4.
  • select () используется для приостановки, ожидания, пока один или несколько сокетов из предоставленного списка будут готовы к чтению, готовы к записи или имеют ошибки.
  • опрос () используется для проверки состояния сокета в наборе сокетов. Набор может быть протестирован, чтобы узнать, можно ли в какой-либо сокет записывать, читать или возникла ли ошибка.
  • getsockopt () используется для получения текущего значения конкретной опции сокета для указанного сокета.
  • setsockopt () используется для установки конкретной опции сокета для указанного сокета.

socket

Функция socket () создает конечную точку для связи и возвращает файловый дескриптор для розетки. Он использует три аргумента:

  • домен, который указывает семейство протоколов созданного сокета. Например:
    • AF_INET для сетевого протокола IPv4 (только IPv4)
    • AF_INET6 для IPv6 (и в некоторых случаях обратно совместимый с IPv4)
    • AF_UNIX для локального сокета (с использованием специального узла файловой системы)
  • тип, одно из:
    • SOCK_STREAM (надежная потоковая служба или потоковые сокеты )
    • SOCK_DGRAM (служба дейтаграмм или Дейтаграмные сокеты )
    • SOCK_SEQPACKET (надежная упорядоченная служба пакетов)
    • SOCK_RAW (необработанные протоколы на верхнем уровне сети)
  • протокол, определяющий фактический используемый транспортный протокол. Наиболее распространенными являются IPPROTO_TCP, IPPROTO_SCTP, IPPROTO_UDP, IPPROTO_DCCP. Эти протоколы указаны в файле netinet / in.h. Значение 0 может использоваться для выбора протокола по умолчанию из выбранного домена и type.

Функция возвращает -1, если произошла ошибка. В противном случае она возвращает целое число, представляющее вновь назначенный дескриптор.

bind

bind () связывает сокет с адрес. Когда socket создается с помощью socket (), ему присваивается только семейство протоколов, но не назначается адрес. Это соединение должно быть выполнено до того, как сокет сможет принимать соединения от других хостов. Функция имеет три аргумента:

  • sockfd, дескриптор, представляющий сокет
  • my_addr, указатель на структуру sockaddr, представляющую адрес для привязки.
  • addrlen, поле типа socklen_t, определяющего размер структуры sockaddr.

Bind () возвращает 0 в случае успеха и -1 в случае ошибки.

listen

После того, как сокет был связан с адресом, listen () подготавливает его для входящих соединений. Однако это необходимо только для потоковых (ориентированных на соединение) режимов данных, то есть для типов сокетов (SOCK_STREAM, SOCK_SEQPACKET). listen () требует двух аргументов:

  • sockfd, действительный дескриптор сокета.
  • backlog, целое число, представляющее количество ожидающих соединений, которые могут быть поставлены в очередь в любой момент. Операционная система обычно ограничивает это значение.

Как только соединение принято, оно удаляется из очереди. В случае успеха возвращается 0. В случае ошибки возвращается -1.

accept

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

  • sockfd, дескриптор слушающего сокета, для которого установлено соединение.
  • cliaddr, указатель на структуру sockaddr для получения информации об адресе клиента.
  • addrlen, указатель на местоположение socklen_t, который указывает размер структуры адреса клиента, переданной в accept (). Когда accept () возвращается, это место содержит размер (в байтах) структуры.

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

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

connect

connect () устанавливает прямую связь с конкретным удаленным хостом, идентифицированным по его адресу, через сокет, идентифицированный его файловым дескриптором.

При использовании протокола с установлением соединения устанавливается соединение. Некоторые типы протоколов не требуют установления соединения, в первую очередь User Datagram Protocol. При использовании с протоколами без установления соединения connect определяет удаленный адрес для отправки и получения данных, позволяя использовать такие функции, как send и recv. В этих случаях функция подключения предотвращает прием дейтаграмм из других источников.

connect () возвращает целое число, представляющее код ошибки: 0 представляет успех, а –1 представляет ошибку. Исторически сложилось так, что в системах, производных от BSD, состояние дескриптора сокета не определено, если вызов для подключения терпит неудачу (как это указано в спецификации Single Unix), поэтому переносимые приложения должны немедленно закрыть дескриптор сокета и получить новый дескриптор с socket () в случае сбоя вызова connect ().

gethostbyname и gethostbyaddr

Функции gethostbyname () и gethostbyaddr () используются для разрешения имен и адресов хостов в система доменных имен или другие механизмы распознавателя локального хоста (например, поиск / etc / hosts). Они возвращают указатель на объект типа struct hostent, который описывает хост Internet Protocol. Функции используют следующие аргументы:

  • nameуказывает DNS-имя хоста.
  • addrуказывает указатель на struct in_addr, содержащую адрес хоста.
  • lenуказывает длину в байтах addr.
  • typeуказывает тип семейства адресов (например, AF_INET) адреса хоста.

Функции возвращают нулевой указатель в в случае ошибки, и в этом случае внешнее целое число h_errnoможет быть проверено, чтобы увидеть, является ли это временной ошибкой или недопустимым или неизвестным хостом. В противном случае возвращается действительная структура struct hostent *.

Эти функции не являются строго компонентом API сокетов BSD, но часто используются вместе с функциями API. Более того, эти функции теперь считаются устаревшими интерфейсами для запросов к системе доменных имен. Были определены новые функции, которые полностью не зависят от протокола (поддерживают IPv6). Эти новые функции - это getaddrinfo () и getnameinfo (), и они основаны на новой структуре данных addrinfo.

Протоколы и семейства адресов

API сокетов Berkeley - это общий интерфейс для сетевого и межпроцессного взаимодействия, который поддерживает использование различных сетевых протоколов и адресных архитектур.

Ниже приводится список семейств протоколов (которым предшествует стандартный символический идентификатор), определенных в современной реализации Linux или BSD :

ИдентификаторФункция или использование
PF_LOCAL, PF_UNIX, PF_FILEЛокальный для хоста (каналы и файловый домен)
PF_INETИнтернет-протокол версии 4
PF_AX25Любительское радио AX.25
PF_IPXNovell Межсетевой пакетный обмен
PF_APPLETALKAppleTalk
PF_NETROMЛюбительское радио NetROM (относящееся к AX.25)
PF_BRIDGEМногопротокольный мост
PF_ATMPVCАсинхронный режим передачи Постоянные виртуальные цепи
PF_ATMSVCРежим асинхронной передачи переключаемый виртуальный Цепи
PF_INET6Интернет-протокол версии 6
PF_DECnetЗарезервировано для проекта DECnet
PF_NETBEUIЗарезервировано для проекта 802.2LLC
PF_SECURITYSecurity callback pseudo AF
PF_KEYAPI управления ключами PF_KEY
PF_NETLINK, PF_RO UTEAPI маршрутизации
PF_PACKETСокеты для захвата пакетов
PF_ECONETAcorn Econet
PF_SNALinux Системная сетевая архитектура (SNA) Проект
PF_IRDAIrDA сокеты
PF_PPPOXPPP через X сокеты
PF_WANPIPESangoma Wanpipe API сокеты
PF_BLUETOOTHBluetooth сокеты

Сокет для связи создается с помощью функции socket ()путем указания желаемого семейства протоколов (PF_-identifier) ​​как Аргумент.

Исходная концепция дизайна интерфейса сокета, различающая типы (семейства) протоколов и конкретные типы адресов, которые каждый может использовать. Предполагалось, что семейство протоколов может иметь несколько типов адресов. Типы адресов определялись дополнительными символическими константами с использованием префикса AF вместо PF. AF-идентификаторы предназначены для всех структур данных, которые конкретно имеют дело с типом адреса, а не семейством протоколов. Однако эта концепция разделения протокола и типа адреса не нашла поддержки в реализации, и константы AF были определены соответствующим идентификатором протокола, оставляя различие между константами AF и PF в качестве технического аргумента. не имеет практических последствий. Действительно, существует большая путаница в правильном использовании обеих форм.

Спецификация POSIX.1-2008 не определяет никаких PF-констант, а только AF-констант

Необработанные сокеты

Необработанные сокеты предоставляют простой интерфейс, который обходит обработку стеком TCP / IP хоста. Они позволяют реализовать сетевые протоколы в пользовательском пространстве и помогают в отладке стека протоколов. Необработанные сокеты используются некоторыми службами, такими как ICMP, которые работают на Интернет-уровне модели TCP / IP.

Параметры для сокетов

После создания сокета можно установить для него параметры. Некоторые из наиболее распространенных опций:

  • TCP_NODELAY отключает алгоритм Нэгла.
  • SO_KEEPALIVE включает периодические эхо-запросы «живучести», если они поддерживаются ОС.
Блокирующий и неблокирующий режим

Сокеты Berkeley могут работать в одном из двух режимов: блокирующем или неблокирующем.

Блокирующий сокет не возвращает управление до тех пор, пока он не отправит (или не получит) некоторые или все данные, указанные для операции. Блокирующий сокет не отправляет все данные - это нормально. Приложение должно проверить возвращаемое значение, чтобы определить, сколько байтов было отправлено или получено, и оно должно повторно отправить любые данные, которые еще не обработаны. При использовании блокирующих сокетов особое внимание следует уделить accept (), поскольку он все еще может блокироваться после индикации удобочитаемости, если клиент отключается во время фазы подключения.

С другой стороны, неблокирующий сокет возвращает все, что находится в приемном буфере, и немедленно продолжает работу. В случае неправильного написания программы, использующие неблокирующие сокеты, особенно подвержены условиям гонки из-за разницы в скорости сетевого соединения.

Сокет обычно устанавливается в режим блокировки или неблокирования с помощью функций fcntl () или ioctl ().

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

Операционная система не освобождает ресурсы, выделенные для сокета, пока сокет не будет закрыт. Это особенно важно, если вызов подключения завершится неудачно и будет повторяться.

Когда приложение закрывает сокет, уничтожается только интерфейс к сокету. Ядро несет ответственность за внутреннее уничтожение сокета. Иногда сокет может переходить в состояние TIME_WAIT на стороне сервера на срок до 4 минут.

В системах SVR4 используется close ()может отбросить данные. В этих системах может потребоваться использование shutdown ()или SO_LINGER, чтобы гарантировать доставку всех данных.

Пример клиент-сервер с использованием TCP

Передача Протокол управления (TCP) - это ориентированный на соединение протокол, который обеспечивает множество функций исправления ошибок и повышения производительности для передачи байтовых потоков. Процесс создает сокет TCP, вызывая функцию socket ()с параметрами для семейства протоколов (PF INET, PF_INET6), режим сокета для Stream Сокеты (SOCK_STREAM) и идентификатор протокола IP для TCP (IPPROTO_TCP).

Сервер

Установка TCP-сервера включает следующие основные шаги:

  • Создание TCP-сокета с вызовом socket ()
  • Привязка сокета к прослушивающему порту (bind ()) после установки номера порта
  • Подготовка сокета для прослушивания подключений (превращение его в прослушивающий сокет) с помощью вызова listen ().
  • Принятие входящих подключений (accept ()). Это блокирует процесс до тех пор, пока не будет получено входящее соединение, и вернет дескриптор сокета для принятого соединения. Начальный дескриптор остается дескриптором прослушивания, и accept () может быть вызван снова в любое время с этим сокетом, пока он не будет закрыт.
  • Связь с удаленным хостом с помощью функций API send () и recv (), а также с функциями общего назначения write () и read ().
  • Закрытие каждого сокета, который был открыт после использования с помощью функции close ()

Следующая программа создает TCP-сервер, прослушивающий порт number 1100:

#include #include #include #include #include #include #include #include int main (void) {struct sockaddr_in sa; int SocketFD = сокет (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (SocketFD == -1) {ошибка ("не удается создать сокет"); выход (EXIT_FAILURE); } memset (sa, 0, sizeof sa); sa.sin_family = AF_INET; sa.sin_port = htons (1100); sa.sin_addr.s_addr = htonl (INADDR_ANY); если (привязка (SocketFD, (struct sockaddr *) sa, sizeof sa) == -1) {perror («сбой привязки»); закрыть (SocketFD); выход (EXIT_FAILURE); } если (прослушивание (SocketFD, 10) == -1) {ошибка ("прослушивание не удалось"); закрыть (SocketFD); выход (EXIT_FAILURE); } for (;;) {int ConnectFD = accept (SocketFD, NULL, NULL); if (0>ConnectFD) {ошибка ("ошибка принятия"); закрыть (SocketFD); выход (EXIT_FAILURE); } / * выполняем операции чтения и записи... чтение (ConnectFD, buff, size) * / if (shutdown (ConnectFD, SHUT_RDWR) == -1) {perror ("завершение не выполнено"); закрыть (ConnectFD); закрыть (SocketFD); выход (EXIT_FAILURE); } закрыть (ConnectFD); } закрыть (SocketFD); вернуть EXIT_SUCCESS; }

Клиент

Программирование клиентского приложения TCP включает следующие шаги:

  • Создание сокета TCP
  • Подключение к серверу (connect ()) путем передачи sockaddr_inструктура с sin_family, установленным на AF_INET, sin_port, установленным на порт, который конечная точка прослушивает (в сетевом порядке байтов), и sin_addrустановлен на IP-адрес слушающего сервера (также в сетевом порядке байтов.)
  • Связь с удаленным хостом с помощью функций API send () и recv (), а также с функциями общего назначения write () и read ().
  • Закрытие каждого сокета, открытого после использования, с помощью функции close ()
#include #include #include #include #include #include #include #include int main (void) {struct sockaddr_in sa; int res; int SocketFD; SocketFD = сокет (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (SocketFD == -1) {ошибка ("не удается создать сокет"); выход (EXIT_FAILURE); } memset (sa, 0, sizeof sa); sa.sin_family = AF_INET; sa.sin_port = htons (1100); res = inet_pton (AF_INET, «192.168.1.3», sa.sin_addr); if (connect (SocketFD, (struct sockaddr *) sa, sizeof sa) == -1) {perror ("сбой подключения"); закрыть (SocketFD); выход (EXIT_FAILURE); } / * выполняем операции чтения-записи... * / close (SocketFD); вернуть EXIT_SUCCESS; }
Пример клиент-сервер с использованием UDP

Протокол дейтаграмм пользователя (UDP) - это протокол без установления соединения без гарантии доставки. Пакеты UDP могут приходить не по порядку, несколько раз или не приходить вовсе. Благодаря такой минималистичной конструкции, UDP значительно меньше накладных расходов, чем TCP. Отсутствие соединения означает, что нет концепции потока или постоянного соединения между двумя хостами. Такие данные называются дейтаграммами (Datagram Sockets ).

Адресное пространство UDP, пространство номеров портов UDP (в терминологии ISO, TSAP ), полностью не пересекается с пространством портов TCP.

Сервер

Приложение может настроить UDP-сервер на порт номер 7654 следующим образом. Программа содержит бесконечный цикл, который принимает дейтаграммы UDP с функцией recvfrom ().

#include #include #include #include #include #include #include / * for close () для сокета * / #include int main (void) {int sock; struct sockaddr_in sa; char buffer [1024]; ssize_t recsize; socklen_t fromlen; memset (sa, 0, sizeof sa); sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl (INADDR_ANY); sa.sin_port = htons (7654); fromlen = sizeof sa; sock = сокет (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (bind (sock, (struct sockaddr *) sa, sizeof sa) == -1) {perror («ошибка привязки не удалась»); близко (носок); выход (EXIT_FAILURE); } for (;;) {recsize = recvfrom (sock, (void *) buffer, sizeof buffer, 0, (struct sockaddr *) sa, fromlen); if (recsize < 0) { fprintf(stderr, "%s\n", strerror(errno)); exit(EXIT_FAILURE); } printf("recsize: %d\n ", (int)recsize); sleep(1); printf("datagram: %.*s\n", (int)recsize, buffer); } }

Client

Ниже представлена ​​клиентская программа для отправки UDP-пакета, содержащего строку «Hello World!», на адрес 127.0.0.1 с номером порта 7654.

#include #include #include #include #include #include #include #include #include int main (void) {int sock; struct sockaddr_in sa; int bytes_sent; char buffer [200]; strcpy (buffer, "hello world!"); / * создать Интернет, дейтаграмму, сокет с использованием UDP * / sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock == -1) {/ * если не удалось инициализировать сокет, выйти * / printf ("Ошибка создания сокета"); exit (EXIT_FAILURE);} / * Обнулить адрес сокета * / memset (sa, 0, sizeof sa); / * Адрес IPv4 * / sa.sin_family = AF_INET; / * IPv4-адреса - это uint32_t, преобразовываем строковое представление октетов в соответствующее значение * / sa.sin_addr.s_addr = inet_addr ("127.0.0.1"); / * сокеты - это беззнаковые шорты, htons (x) гарантирует, что x находится в сетевом порядке байтов, установите порт на 7654 * / sa.sin_por t = htons (7654); bytes_sent = sendto (сок, буфер, strlen (буфер), 0, (struct sockaddr *) sa, sizeof sa); if (bytes_sent < 0) { printf("Error sending packet: %s\n", strerror(errno)); exit(EXIT_FAILURE); } close(sock); /* close the socket */ return 0; }

В этом коде буфер - это указатель на данные, которые должны быть отправлены, а длина_буфера определяет размер данных.

Ссылки

de jure стандартное определение интерфейса Sockets содержится в стандарте POSIX, известном как:

  • IEEE Std. 1003.1-2001 Стандарт информационных технологий - интерфейс переносимой операционной системы (POSIX).
  • Открыть Group Technical Standard: Base Specifications, Issue 6, December 2001.
  • ISO / IEC 9945: 2002

Информация об этом стандарте и текущей работе над ним доступна на веб-сайте Austin.

Расширения IPv6 для API базового сокета описаны в RFC 3493 и RFC 3542.

External ссылки

Эта статья основана на материалах, взятых из Free On-line Dictionary of Computing до 1 ноября 2008 г. и включенных в раздел " перелицензирование »условий GFDL версии 1.3 или новее.

Последняя правка сделана 2021-05-12 13:00:36
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте