Spec-Zone.ru › Ruby 3.2

класс Socket

Родитель:
BasicSocket

Class Socket предоставляет доступ к реализациям сокетов операционной системы. Его можно использовать для предоставления более специфичной функциональности операционной системы, чем классы сокетов, специфичные для протокола.

Константы, определенные в Socket::Constants, также определены в Socket. Например, Socket::AF_INET можно использовать так же, как Socket::Constants::AF_INET. Список констант см. в Socket::Constants.

Что такое сокет?

Сокеты — это конечные точки двунаправленного канала связи. Сокеты могут взаимодействовать внутри процесса, между процессами на одном компьютере или между различными компьютерами. Существует множество типов сокетов: TCPSocket, UDPSocket или UNIXSocket, например.

Сокеты имеют свою собственную терминологию:

домен: Семейство протоколов:

  • Socket::PF_INET

  • Socket::PF_INET6

  • Socket::PF_UNIX

  • и т. д.

тип: Тип связи между двумя конечными точками, обычно

  • Socket::SOCK_STREAM

  • Socket::SOCK_DGRAM.

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

имя хоста: Идентификатор сетевого интерфейса:

  • строка (имя хоста, IPv4 или IPv6 адрес или broadcast, который указывает на адрес широковещательной передачи)

  • строка нулевой длины, которая указывает на INADDR_ANY

  • целое число (интерпретируется как двоичный адрес в порядке байтов хоста).

Быстрый старт

Многие классы, такие как TCPSocket, UDPSocket или UNIXSocket, упрощают использование сокетов по сравнению с эквивалентным интерфейсом программирования на C.

Давайте создадим интернет-сокет, используя IPv4-протокол, аналогично C:

require 'socket'

s = Socket.new Socket::AF_INET, Socket::SOCK_STREAM
s.connect Socket.pack_sockaddr_in(80, 'example.com')

Вы также можете использовать класс TCPSocket:

s = TCPSocket.new 'example.com', 80

Простой сервер может выглядеть так:

require 'socket'

server = TCPServer.new 2000 # Server bound to port 2000

loop do
  client = server.accept    # Wait for a client to connect
  client.puts "Hello !"
  client.puts "Time is #{Time.now}"
  client.close
end

Простой клиент может выглядеть так:

require 'socket'

s = TCPSocket.new 'localhost', 2000

while line = s.gets # Read lines from socket
  puts line         # and print them
end

s.close             # close socket when done

Обработка Exception

Реализация Ruby Socket генерирует исключения на основе ошибки, сгенерированной системной зависимой реализацией. Вот почему методы документированы таким образом, чтобы изолировать исключения систем, основанных на Unix, от исключений, основанных на Windows. Если требуется дополнительная информация об определенном исключении, обратитесь к страницам руководства Unix или справочнику WinSock Windows.

Удобные методы

Хотя общий способ создания сокета — Socket.new, для большинства случаев существуют несколько методов создания сокета.

Сокет клиента TCP

Socket.tcp, TCPSocket.open

Сокет сервера TCP

Socket.tcp_server_loop, TCPServer.open

Сокет клиента UNIX

Socket.unix, UNIXSocket.open

Сокет сервера UNIX

Socket.unix_server_loop, UNIXServer.open

Документация подготовлена

  • Захом Деннисом

  • Самом Робертсом

  • Программирование на Ruby от The Pragmatic Bookshelf.

Большая часть материала в этой документации взята с разрешения из Программирование на Ruby от The Pragmatic Bookshelf.

Константы

AF_ALG

Интерфейс к ядру крипто API

AF_APPLETALK

Протокол AppleTalk

AF_ATM

Режим асинхронной передачи

AF_AX25

Протокол AX.25

AF_BLUETOOTH

Протокол сокетов Bluetooth низкого уровня

AF_CAN

Протокол автомобисной шины Controller Area Network

AF_CCITT

Протоколы CCITT (теперь ITU-T)

AF_CHAOS

Протоколы MIT CHAOS

AF_CNT

Технология компьютерных сетей

AF_COIP

Ориентированный на соединение IP

AF_DATAKIT

Протокол Datakit

AF_DEC

Протокол DECnet

AF_DECnet

Протокол DECnet

AF_DLI

Протокол DEC Direct Data Link Interface

AF_E164

Рекомендация CCITT (ITU-T) E.164

AF_ECMA

Протоколы европейских производителей компьютеров

AF_HYLINK

Протокол NSC Hyperchannel

AF_IB

Родное адресование InfiniBand

AF_IMPLINK

Протокол ARPANET IMP

AF_INET

Протокол IPv4

AF_INET6

Протокол IPv6

AF_IPX

Протокол IPX

AF_ISDN

Интегрированная цифровая сеть с услугами

AF_ISO

Протоколы ISO Открытых систем

AF_KCM

Интерфейс KCM (множитель подключений ядра)

AF_KEY

Протокол управления ключами, первоначально разработанный для использования с IPsec

AF_LAT

Протокол локальной транспортной системы

AF_LINK

Интерфейс уровня канала

AF_LLC

Протокол управления логическим каналом (IEEE 802.2 LLC)

AF_LOCAL

Внутрисетевые протоколы

AF_MAX

Максимальная семейство адресов для этой платформы

AF_MPLS

Многопротокольная коммутация меток

AF_NATM

Нативный доступ ATM

AF_NDRV

Нативный доступ к сети драйвера

AF_NETBIOS

NetBIOS

AF_NETGRAPH

Сокеты Netgraph

AF_NETLINK

Kernel устройство пользовательского интерфейса

AF_NS

Протоколы XEROX NS

AF_OSI

Протоколы ISO Открытых систем

AF_PACKET

Прямой доступ к уровню канала

AF_PPP

Протокол точка-точка

AF_PPPOX

Общий транспортный уровень PPP для настройки туннелей L2 (L2TP и PPPoE)

AF_PUP

Протокол PARC Universal Packet

AF_RDS

Протокол надежных дейтаграммных сокетов (RDS)

AF_ROUTE

Внутренний протокол маршрутизации

AF_SIP

Простой интернет-протокол

AF_SNA

Протокол IBM SNA

AF_SYSTEM
AF_TIPC

Протокол TIPC, «кластерные сокеты области»

AF_UNIX

Сокеты UNIX

AF_UNSPEC

Неопределенный протокол, любая поддерживаемая семейство адресов

AF_VSOCK

Протокол VSOCK (первоначально «VMWare VSockets») для межвиртуальной коммуникации

AF_XDP

Интерфейс XDP (быстрый путь данных)

AI_ADDRCONFIG

Принять только если какой-либо адрес назначен

AI_ALL

Разрешить все адреса

AI_CANONNAME

Заполнить каноническое имя

AI_DEFAULT

Флаги по умолчанию для getaddrinfo

AI_MASK

Действительная маска флагов для getaddrinfo (не для использования приложением)

AI_NUMERICHOST

Запретить разрешение имени хоста

AI_NUMERICSERV

Запретить разрешение имени службы

AI_PASSIVE

Получить адрес для использования с bind()

AI_V4MAPPED

Принять IPv4-отображенные IPv6 адреса

AI_V4MAPPED_CFG

Принять IPv4-отображенные адреса, если ядро их поддерживает

EAI_ADDRFAMILY

Семейство адресов для имени хоста не поддерживается

EAI_AGAIN

Временное сбое в разрешении имени

EAI_BADFLAGS

Недопустимые флаги

EAI_BADHINTS

Неверное значение для подсказок

EAI_FAIL

Невосстановимая ошибка в разрешении имени

EAI_FAMILY

Семейство адресов не поддерживается

EAI_MAX

Максимальный код ошибки из getaddrinfo

EAI_MEMORY

Ошибка выделения памяти

EAI_NODATA

Нет адреса, связанного с именем хоста

EAI_NONAME

Имя хоста или имя службы не известны

EAI_OVERFLOW

Переполнение буфера аргументов

EAI_PROTOCOL

Решенный протокол неизвестен

EAI_SERVICE

Имя службы не поддерживается для типа сокета

EAI_SOCKTYPE

Socket тип сокета не поддерживается

EAI_SYSTEM

Возвращена системная ошибка в errno

IFF_802_1Q_VLAN

Устройство VLAN 802.1Q

IFF_ALLMULTI

получать все пакеты многоадресной рассылки

IFF_ALTPHYS

использовать альтернативное физическое соединение

IFF_AUTOMEDIA

Автоматический выбор среды активен

IFF_BONDING

главный или подчиненный агрегирования

IFF_BRIDGE_PORT

устройство, используемое в качестве порта моста

IFF_BROADCAST

адрес широковещательной передачи действителен

IFF_CANTCHANGE

флаги не изменяемы

IFF_CANTCONFIG

невозможно настроить с помощью ioctl(2)

IFF_DEBUG

включить отладку

IFF_DISABLE_NETPOLL

выключить netpoll во время выполнения

IFF_DONT_BRIDGE

запретить мостирование этого устройства

IFF_DORMANT

драйвер сигнализирует о приостановке

IFF_DRV_OACTIVE

очередь аппаратного транзита TX заполнена

IFF_DRV_RUNNING

ресурсы выделены

IFF_DYING

интерфейс завершает работу

IFF_DYNAMIC

устройство коммутируемого доступа с изменяемыми адресами

IFF_EBRIDGE

устройство моста Ethernet

IFF_ECHO

отправленные пакеты эха

IFF_ISATAP

интерфейс ISATAP (RFC4214)

IFF_LINK0

побитовое значение уровня канала, бит 0

IFF_LINK1

побитовое значение уровня канала, бит 1

IFF_LINK2

побитовое значение уровня канала, бит 2

IFF_LIVE_ADDR_CHANGE

изменение аппаратного адреса во время работы

IFF_LOOPBACK

петлевое соединение

IFF_LOWER_UP

драйвер сигнализирует о работе L1

IFF_MACVLAN_PORT

устройство, используемое в качестве порта macvlan

IFF_MASTER

главный балансировщик нагрузки

IFF_MASTER_8023AD

главный агрегатор, 802.3ad.

IFF_MASTER_ALB

главный агрегатор, балансировка ALB.

IFF_MASTER_ARPMON

главный агрегатор, ARP-мониторинг используется

IFF_MONITOR

режим мониторинга по запросу пользователя

IFF_MULTICAST

поддерживает многоадресную рассылку

IFF_NOARP

протокол разрешения адресов не используется

IFF_NOTRAILERS

избегать использования трейлеров

IFF_OACTIVE

передача данных в процессе

IFF_OVS_DATAPATH

устройство, используемое в качестве порта Open vSwitch datapath

IFF_POINTOPOINT

соединение точка-точка

IFF_PORTSEL

можно задать тип среды

IFF_PPROMISC

запрос на прослушивание promiscuous по запросу пользователя

IFF_PROMISC

получать все пакеты

IFF_RENAMING

интерфейс переименовывается

IFF_ROUTE

установлена запись маршрутизации

IFF_RUNNING

ресурсы выделены

IFF_SIMPLEX

не слышит собственные трансляции

IFF_SLAVE

подчиненный балансировщик нагрузки

IFF_SLAVE_INACTIVE

подчиненный агрегатор не активный

IFF_SLAVE_NEEDARP

требуются ARP для проверки

IFF_SMART

интерфейс управляет собственными маршрутами

IFF_STATICARP

статический ARP

IFF_SUPP_NOFCS

отправка пользовательской FCS

IFF_TEAM_PORT

используется как порт команды

IFF_TX_SKB_SHARING

совместное использование skb при передаче

IFF_UNICAST_FLT

фильтрация одноадресной рассылки

IFF_UP

интерфейс активен

IFF_VOLATILE

изменяемые флаги

IFF_WAN_HDLC

устройство WAN HDLC

IFF_XMIT_DST_RELEASE

dev_hard_start_xmit() разрешено освобождать skb->dst

IFNAMSIZ

Максимальный размер имени интерфейса

IF_NAMESIZE

Максимальный размер имени интерфейса

INADDR_ALLHOSTS_GROUP

Группа многоадресной рассылки для всех систем в этом подмножестве

INADDR_ANY

Сокет, привязанный к INADDR_ANY, получает пакеты со всех интерфейсов и отправляет их с использованием стандартного IP-адреса.

INADDR_BROADCAST

Адрес широковещательной передачи сети.

INADDR_LOOPBACK

Адрес обратной связи.

INADDR_MAX_LOCAL_GROUP

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

INADDR_NONE

Маска для соответствия отсутствию действительного IP-адреса.

INADDR_UNSPEC_GROUP

Зарезервированная группа мультивещания.

INET6_ADDRSTRLEN

Максимальная длина строки IPv6-адреса.

INET_ADDRSTRLEN

Максимальная длина строки IPv4-адреса.

IPPORT_RESERVED

Минимальный стандартный адрес для привязки или подключения.

IPPORT_USERRESERVED

Максимальный стандартный адрес для привязки или подключения.

IPPROTO_AH

Заголовок аутентификации IP6.

IPPROTO_BIP
IPPROTO_DSTOPTS

Опция назначения IP6.

IPPROTO_EGP

Протокол внешних шлюзов.

IPPROTO_EON

ISO cnlp.

IPPROTO_ESP

Защищенная полезная нагрузка IP6.

IPPROTO_FRAGMENT

Заголовок фрагментации IP6.

IPPROTO_GGP

Протокол шлюза к шлюзу.

IPPROTO_HELLO

Протокол маршрутизации «hello».

IPPROTO_HOPOPTS

Опции IP6 "прыжок за прыжком".

IPPROTO_ICMP

Протокол сообщений управления.

IPPROTO_ICMPV6

ICMP6.

IPPROTO_IDP

XNS IDP.

IPPROTO_IGMP

Протокол управления группами.

IPPROTO_IP

Протокол-заглушка для IP.

IPPROTO_IPV6

Заголовок IP6.

IPPROTO_MAX

Максимальное значение константы IPPROTO.

IPPROTO_ND

Протокол сетевого диска Sun.

IPPROTO_NONE

IP6 без следующего заголовка.

IPPROTO_PUP

Протокол универсальных пакетов PARC.

IPPROTO_RAW

Сырой пакет IP.

IPPROTO_ROUTING

Заголовок маршрутизации IP6.

IPPROTO_TCP

TCP.

IPPROTO_TP

Класс 4 транспортного протокола ISO.

IPPROTO_UDP

UDP.

IPPROTO_XTP

Протокол транспортного ускорения.

IPV6_CHECKSUM

Смещение контрольной суммы для сырых сокетов.

IPV6_DONTFRAG

Не фрагментировать пакеты.

IPV6_DSTOPTS

Опция назначения.

IPV6_HOPLIMIT

Предел переходов.

IPV6_HOPOPTS

Опция "прыжок за прыжком".

IPV6_JOIN_GROUP

Присоединение к членству в группе.

IPV6_LEAVE_GROUP

Выход из членства в группе.

IPV6_MULTICAST_HOPS

Переходы IP6 мультивещания.

IPV6_MULTICAST_IF

Интерфейс IP6 мультивещания.

IPV6_MULTICAST_LOOP

Петля обратной связи IP6 мультивещания.

IPV6_NEXTHOP

Следующий адрес перехода.

IPV6_PATHMTU

Получение текущего пути MTU.

IPV6_PKTINFO

Получение информации о пакете с датаграммой.

IPV6_RECVDSTOPTS

Получение всех опций IP6 для ответа.

IPV6_RECVHOPLIMIT

Получение предела переходов с датаграммой.

IPV6_RECVHOPOPTS

Получение опций "прыжок за прыжком".

IPV6_RECVPATHMTU

Получение текущего пути MTU с датаграммой.

IPV6_RECVPKTINFO

Получение адреса назначения IP и входящего интерфейса.

IPV6_RECVRTHDR

Получение заголовка маршрутизации.

IPV6_RECVTCLASS

Получение класса трафика.

IPV6_RTHDR

Позволяет удалить заголовки маршрутизации.

IPV6_RTHDRDSTOPTS

Позволяет удалить заголовок опций назначения.

IPV6_RTHDR_TYPE_0

Тип заголовка маршрутизации 0.

IPV6_TCLASS

Указать класс трафика.

IPV6_UNICAST_HOPS

Переходы IP6 одноадресной передачи.

IPV6_USE_MIN_MTU

Использовать минимальный размер MTU.

IPV6_V6ONLY

Только привязка IPv6 с подстановкой по умолчанию.

IPX_TYPE
IP_ADD_MEMBERSHIP

Добавление членства в группу мультивещания.

IP_ADD_SOURCE_MEMBERSHIP

Добавление членства в группу мультивещания.

IP_BLOCK_SOURCE

Заблокировать пакеты IPv4 мультивещания с указанным исходным адресом.

IP_DEFAULT_MULTICAST_LOOP

Стандартная петля обратной связи мультивещания.

IP_DEFAULT_MULTICAST_TTL

Стандартный TTL мультивещания.

IP_DONTFRAG

Не фрагментировать пакеты.

IP_DROP_MEMBERSHIP

Удалить членство в группе мультивещания.

IP_DROP_SOURCE_MEMBERSHIP

Удалить членство в группе мультивещания.

IP_FREEBIND

Разрешить привязку к несуществующим IP-адресам.

IP_HDRINCL

Заголовок включен в данные.

IP_IPSEC_POLICY

Политика безопасности IPsec.

IP_MAX_MEMBERSHIPS

Максимальное количество групп мультивещания, к которым может присоединиться сокет.

IP_MINTTL

Минимальное значение TTL, разрешенное для полученных пакетов.

IP_MSFILTER

Фильтр источников мультивещания.

IP_MTU

Максимальный размер транспортного блока сокета.

IP_MTU_DISCOVER

Обнаружение пути MTU.

IP_MULTICAST_IF

Интерфейс IP мультивещания.

IP_MULTICAST_LOOP

Петля обратной связи IP мультивещания.

IP_MULTICAST_TTL

TTL IP мультивещания.

IP_ONESBCAST

Принудительно задать адрес необращённой широковещательной передачи для исходящих широковещательных датаграмм.

IP_OPTIONS

Опции IP, которые должны быть включены в пакеты.

IP_PASSSEC

Получение контекста безопасности с датаграммой.

IP_PKTINFO

Получение информации о пакете с датаграммами.

IP_PKTOPTIONS

Получение опций пакета с датаграммами.

IP_PMTUDISC_DO

Всегда отправлять кадр DF.

IP_PMTUDISC_DONT

Никогда не отправлять кадр DF.

IP_PMTUDISC_WANT

Использовать подсказки по каждому маршруту.

IP_PORTRANGE

Set диапазон портов для сокетов с неуказанными номерами портов.

IP_RECVDSTADDR

Получение IP-адреса назначения с датаграммой.

IP_RECVERR

Включить передачу расширенных сообщений об ошибках надёжной связи.

IP_RECVIF

Получение информации об интерфейсе с датаграммами.

IP_RECVOPTS

Получение всех опций IP с датаграммой.

IP_RECVRETOPTS

Получение всех опций IP для ответа.

IP_RECVSLLA

Получение адреса канального уровня с датаграммами.

IP_RECVTOS

Получить TOS со входящими пакетами.

IP_RECVTTL

Получить IP TTL с датаграммами.

IP_RETOPTS

Опции IP, которые должны быть включены в датаграммы.

IP_ROUTER_ALERT

Уведомить маршрутизаторы транзита о более тщательном изучении содержимого пакета IP.

IP_SENDSRCADDR

Адрес источника для исходящих UDP-датаграмм.

IP_TOS

Тип обслуживания IP.

IP_TRANSPARENT

Прозрачный прокси.

IP_TTL

Время жизни IP.

IP_UNBLOCK_SOURCE

Разблокировать пакеты IPv4 мультивещания с данным исходным адресом.

IP_XFRM_POLICY
LOCAL_CONNWAIT

Подключение блокируется до его принятия.

LOCAL_CREDS

Передача учётных данных получателю.

LOCAL_PEERCRED

Получение учётных данных партнёра.

MCAST_BLOCK_SOURCE

Заблокировать пакеты мультивещания от данного источника.

MCAST_EXCLUDE

Исключительный фильтр источников мультивещания.

MCAST_INCLUDE

Включительно-исключительный фильтр источников мультивещания.

MCAST_JOIN_GROUP

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

MCAST_JOIN_SOURCE_GROUP

Присоединиться к группе источников мультивещания.

MCAST_LEAVE_GROUP

Выйти из группы мультивещания.

MCAST_LEAVE_SOURCE_GROUP

Выйти из группы источников мультивещания.

MCAST_MSFILTER

Фильтр источников мультивещания.

MCAST_UNBLOCK_SOURCE

Разблокировать пакеты мультивещания от данного источника.

MSG_COMPAT

Конец записи.

MSG_CONFIRM

Подтвердить правильность пути.

MSG_CTRUNC

Утеряны управляющие данные перед доставкой.

MSG_DONTROUTE

Отправить, не используя таблицы маршрутизации.

MSG_DONTWAIT

Данное сообщение должно быть без блокировки.

MSG_EOF

Data завершает подключение.

MSG_EOR

Data завершает запись.

MSG_ERRQUEUE

Получить сообщение из очереди ошибок.

MSG_FASTOPEN

Уменьшение шага процесса рукопожатия

MSG_FIN
MSG_FLUSH

Начало последовательности удержания. Выгружается в so_temp

MSG_HAVEMORE

Data готов к чтению

MSG_HOLD

Удержание фрагмента в so_temp

MSG_MORE

Отправитель отправит больше данных

MSG_NOSIGNAL

Не генерировать SIGPIPE

MSG_OOB

Process данные вне очереди

MSG_PEEK

Предварительный просмотр входящего сообщения

MSG_PROXY

Ожидание полного запроса

MSG_RCVMORE

Data остаётся в текущем пакете

MSG_RST
MSG_SEND

Отправка пакета в so_temp

MSG_SYN
MSG_TRUNC

Data отброшено перед доставкой

MSG_WAITALL

Ожидание полного запроса или ошибки

NI_DGRAM

Указанная служба — это служба дейтаграмм (поиск портов UDP)

NI_MAXHOST

Максимальная длина имени хоста

NI_MAXSERV

Максимальная длина имени службы

NI_NAMEREQD

Требуется имя

NI_NOFQDN

FQDN не требуется для локальных хостов, возвращается только локальная часть

NI_NUMERICHOST

Возвращение числового адреса

NI_NUMERICSERV

Возвращение имени службы в виде числовой строки

PF_ALG

Интерфейс к ядру API криптографии

PF_APPLETALK

Протокол AppleTalk

PF_ATM

Режим асинхронной передачи

PF_AX25

Протокол AX.25

PF_BLUETOOTH

Протокол низкого уровня сокетов Bluetooth

PF_CAN

Протокол шины CAN автомобильной сети

PF_CCITT

Протоколы CCITT (сейчас ITU-T)

PF_CHAOS

Протоколы MIT CHAOS

PF_CNT

Технология компьютерной сети

PF_COIP

Ориентированный на соединение IP

PF_DATAKIT

Протокол Datakit

PF_DEC

Протокол DECnet

PF_DECnet

Протокол DECnet

PF_DLI

Протокол DEC Direct Data интерфейса канала

PF_ECMA

Протоколы Европейских производителей компьютеров

PF_HYLINK

Протокол NSC Hyperchannel

PF_IB

Родная адресация InfiniBand

PF_IMPLINK

Протокол ARPANET IMP

PF_INET

Протокол IPv4

PF_INET6

Протокол IPv6

PF_IPX

Протокол IPX

PF_ISDN

Интегрированная цифровая сеть с услугами

PF_ISO

Протоколы ISO Открытой системы взаимосвязи

PF_KCM

Интерфейс KCM (ядерный множитель подключений)

PF_KEY

Протокол управления ключами, первоначально разработанный для использования с IPsec

PF_LAT

Протокол локальной транспортной сети

PF_LINK

Интерфейс уровня канала

PF_LLC

Протокол логического управления каналом (IEEE 802.2 LLC)

PF_LOCAL

Внутрисистемные протоколы

PF_MAX

Максимальная семейство адресов для этой платформы

PF_MPLS

Многопротокольная коммутация меток

PF_NATM

Родной доступ ATM

PF_NDRV

Прямой доступ к драйверу сети

PF_NETBIOS

NetBIOS

PF_NETGRAPH

Сокеты Netgraph

PF_NETLINK

Kernel интерфейс устройства пользователя

PF_NS

Протоколы XEROX NS

PF_OSI

Протоколы ISO Открытой системы взаимосвязи

PF_PACKET

Прямой доступ к каналу связи

PF_PIP
PF_PPP

Протокол точка-точка

PF_PPPOX

Обобщённый транспортный уровень PPP для настройки туннелей L2 (L2TP и PPPoE)

PF_PUP

Протокол PARC Universal Packet

PF_RDS

Протокол надёжных сокетов дейтаграмм (RDS)

PF_ROUTE

Внутренний протокол маршрутизации

PF_RTIP
PF_SIP

Простой интернет-протокол

PF_SNA

Протокол IBM SNA

PF_SYSTEM
PF_TIPC

TIPC, протокол «кластерных доменных сокетов»

PF_UNIX

Сокеты UNIX

PF_UNSPEC

Неуказанный протокол, любое поддерживаемое семейство адресов

PF_VSOCK

Протокол VSOCK (первоначально «VMWare VSockets») для межгипервизорно-гостевого взаимодействия

PF_XDP

Интерфейс XDP (быстрый путь данных)

PF_XTP

Протокол экспресс-передачи

SCM_BINTIME

Отметка времени (bintime)

SCM_CREDENTIALS

Удостоверение отправителя

SCM_CREDS

Process удостоверения

SCM_RIGHTS

Права доступа

SCM_TIMESTAMP

Отметка времени (timeval)

SCM_TIMESTAMPING

Отметка времени (список timespec) (Linux 2.6.30)

SCM_TIMESTAMPNS

Timespec (timespec)

SCM_UCRED

Удостоверения пользователя

SCM_WIFI_STATUS

Состояние Wi-Fi (Linux 3.3)

SHUT_RD

Закрытие стороны чтения сокета

SHUT_RDWR

Закрытие обеих сторон сокета

SHUT_WR

Закрытие стороны записи сокета

SOCK_CLOEXEC

Set флаг close-on-exec (FD_CLOEXEC) для нового дескриптора файла.

SOCK_DGRAM

Сокет дейтаграмм обеспечивает обмен сообщениями без установления соединения и без гарантии доставки

SOCK_NONBLOCK

Set флаг состояния файла O_NONBLOCK для открытого дескриптора файла (см. open(2)), на который ссылается новый дескриптор файла.

SOCK_PACKET

Доступ к пакету на уровне устройства

SOCK_RAW

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

SOCK_RDM

Надёжный сокет дейтаграмм обеспечивает надёжную доставку сообщений

SOCK_SEQPACKET

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

SOCK_STREAM

Потоковый сокет обеспечивает упорядоченную, надёжную двустороннюю связь для потока байтов

SOL_ATALK

Параметры сокета AppleTalk

SOL_AX25

Параметры сокета AX.25

SOL_IP

Параметры сокета IP

SOL_IPX

Параметры сокета IPX

SOL_SOCKET

Параметры уровня сокета

SOL_TCP

Параметры сокета TCP

SOL_UDP

Параметры сокета UDP

SOMAXCONN

Максимальное количество запросов на соединение, которые могут быть поставлены в очередь для сокета

SOPRI_BACKGROUND

Приоритет сокета в фоновом режиме

SOPRI_INTERACTIVE

Приоритет интерактивного сокета

SOPRI_NORMAL

Нормальный приоритет сокета

SO_ACCEPTCONN

Socket на нём был вызван listen()

SO_ACCEPTFILTER

Существует фильтр принятия

SO_ALLZONES

Обход границ зон

SO_ATTACH_FILTER

Присоединение фильтра принятия

SO_BINDTODEVICE

Отправка пакетов только с указанного интерфейса

SO_BINTIME

Получение отметки времени с дейтаграммами (bintime)

SO_BPF_EXTENSIONS

Запрос поддерживаемых расширений BPF (Linux 3.14)

SO_BROADCAST

Разрешение отправки широковещательных сообщений

SO_BUSY_POLL

Set порог в микросекундах для опроса с низкой задержкой (Linux 3.11)

SO_DEBUG

Запись отладочной информации

SO_DETACH_FILTER

Отсоединение фильтра принятия

SO_DOMAIN

Указанный домен для socket() (Linux 2.6.32)

SO_DONTROUTE

Использовать адреса интерфейса

SO_DONTTRUNC

Сохранить непрочитанные данные

SO_ERROR

Получение и очистка состояния ошибки

SO_GET_FILTER

Получение набора фильтров, установленного с помощью SO_ATTACH_FILTER (Linux 3.8)

SO_INCOMING_CPU

Получение процессора, подключённого к сокету (Linux 3.19)

SO_INCOMING_NAPI_ID

Получение идентификатора napi, присоединённого к очереди RX (Linux 4.12)

SO_KEEPALIVE

Поддерживать соединения живыми

SO_LINGER

Ожидать при закрытии, если присутствуют данные

SO_LOCK_FILTER

Заблокировать фильтр, присоединённый к сокету (Linux 3.9)

SO_MAC_EXEMPT

Исключение обязательного управления доступом для незамеченных партнёров

SO_MARK

Set метку для маршрутизации на основе меток (Linux 2.6.25)

SO_MAX_PACING_RATE
END_OF_DOCUMENT_MARKER

Ограничить скорость, вычисленную транспортным уровнем. [байты в секунду] (Linux 3.13)

SO_NKE

Установить расширение сокетного уровня Сети Kernel

SO_NOFCS

Set netns сокета (Linux 3.4)

SO_NOSIGPIPE

Не генерировать SIGPIPE при EPIPE

SO_NO_CHECK

Отключить контрольные суммы

SO_NREAD

Получить количество байтов первого пакета

SO_OOBINLINE

Оставить полученные данные вне очереди в строке

SO_PASSCRED

Получать сообщения SCM_CREDENTIALS

SO_PASSSEC

Переключить передачу контекста безопасности (Linux 2.6.18)

SO_PEEK_OFF

Set смещение peek (Linux 3.4)

SO_PEERCRED

Удостоверения удалённого процесса, подключённого к этому сокету

SO_PEERNAME

Имя пользователя, подключившегося к сокету

SO_PEERSEC

Получить учетные данные безопасности (Linux 2.6.2)

SO_PRIORITY

Определённый протоколом приоритет для всех пакетов по этому сокету

SO_PROTOCOL

Протокол, заданный для socket() (Linux 2.6.32)

SO_RCVBUF

Размер буфера приема

SO_RCVBUFFORCE

Размер буфера приема без ограничения rmem_max (Linux 2.6.14)

SO_RCVLOWAT

Минимальное значение для получения данных

SO_RCVTIMEO

Таймаут приема

SO_RECVUCRED

Получение учетных данных пользователя с дейтаграммой

SO_REUSEADDR

Разрешить повторное использование локального адреса

SO_REUSEPORT

Разрешить повторное использование локального адреса и порта

SO_RTABLE

Set таблицу маршрутизации для этого сокета (OpenBSD)

SO_RXQ_OVFL

Переключить cmsg для количества потерянных пакетов (Linux 2.6.33)

SO_SECURITY_AUTHENTICATION
SO_SECURITY_ENCRYPTION_NETWORK
SO_SECURITY_ENCRYPTION_TRANSPORT
SO_SELECT_ERR_QUEUE

Заставить select() обнаруживать очередь ошибок сокета с ошибочными дескрипторами (Linux 3.10)

SO_SETFIB

Set связанную таблицу маршрутизации для сокета (FreeBSD)

SO_SNDBUF

Размер буфера отправки

SO_SNDBUFFORCE

Размер буфера отправки без ограничения wmem_max (Linux 2.6.14)

SO_SNDLOWAT

Минимальное значение для отправки данных

SO_SNDTIMEO

Таймаут отправки

SO_TIMESTAMP

Получение временной метки с дейтаграммами (timeval)

SO_TIMESTAMPING

Time временных меток входящих и исходящих пакетов (Linux 2.6.30)

SO_TIMESTAMPNS

Получение временной метки в наносекундах с дейтаграммами (timespec)

SO_TYPE

Получить тип сокета

SO_USELOOPBACK

Игнорировать оборудование, когда это возможно

SO_USER_COOKIE

Установка идентификатора, в основном для ipfw

SO_WANTMORE

Указание, когда доступны дополнительные данные

SO_WANTOOBFLAG

Данные вне очереди требуются в MSG_FLAG при приеме

SO_WIFI_STATUS

Переключить cmsg для состояния Wi-Fi (Linux 3.3)

TCP_CONGESTION

Алгоритм управления трафиком TCP (Linux 2.6.13, glibc 2.6)

TCP_CONNECTION_INFO

Получение информации об этом сокете (macOS)

TCP_COOKIE_TRANSACTIONS

TCP Cookie Transactions (Linux 2.6.33, glibc 2.18)

TCP_CORK

Не отправлять фрагменты (Linux 2.2, glibc 2.2)

TCP_DEFER_ACCEPT

Не уведомлять сокет, пока данные не готовы (Linux 2.4, glibc 2.2)

TCP_FASTOPEN

Уменьшение шагов процесса рукопожатия (Linux 3.7, glibc 2.18)

TCP_INFO

Получение информации об этом сокете (Linux 2.4, glibc 2.2)

TCP_KEEPALIVE

Время простоя перед отправкой зондов keepalive (macOS)

TCP_KEEPCNT

Максимальное количество зондов keepalive, разрешенных перед разрывом соединения (Linux 2.4, glibc 2.2)

TCP_KEEPIDLE

Время простоя перед отправкой зондов keepalive (Linux 2.4, glibc 2.2)

TCP_KEEPINTVL

Time между зондами keepalive (Linux 2.4, glibc 2.2)

TCP_LINGER2

Срок службы незавершенных сокетов FIN_WAIT2 (Linux 2.4, glibc 2.2)

TCP_MAXSEG

Set максимальный размер сегмента

TCP_MD5SIG

Использование хэш-сумм MD5 (RFC2385, Linux 2.6.20, glibc 2.7)

TCP_NODELAY

Не задерживать отправку для объединения пакетов

TCP_NOOPT

Не использовать параметры TCP

TCP_NOPUSH

Не выполнять push для последнего блока записи

TCP_QUEUE_SEQ

Последовательность очереди для режима ремонта (Linux 3.5, glibc 2.18)

TCP_QUICKACK

Включить режим quickack (Linux 2.4.4, glibc 2.3)

TCP_REPAIR

Режим ремонта (Linux 3.5, glibc 2.18)

TCP_REPAIR_OPTIONS

Параметры для режима ремонта (Linux 3.5, glibc 2.18)

TCP_REPAIR_QUEUE

Очередь для режима ремонта (Linux 3.5, glibc 2.18)

TCP_SYNCNT

Количество повторных передач SYN перед разрывом соединения (Linux 2.4, glibc 2.2)

TCP_THIN_DUPACK

Обработка дублированных подтверждений для тонких потоков (Linux 2.6.34, glibc 2.18)

TCP_THIN_LINEAR_TIMEOUTS

Линейные таймауты для тонких потоков (Linux 2.6.34, glibc 2.18)

TCP_TIMESTAMP

TCP временная метка (Linux 3.9, glibc 2.18)

TCP_USER_TIMEOUT

Максимальный таймаут перед прерыванием TCP-соединения (Linux 2.6.37, glibc 2.18)

TCP_WINDOW_CLAMP

Ограничение размера объявленного окна (Linux 2.4, glibc 2.2)

UDP_CORK

Не отправлять фрагменты (Linux 2.5.44, glibc 2.11)

Методы открытого класса

accept_loop(*sockets) { |socket, client_addrinfo| ... } Показать исходный код
# File ext/socket/lib/socket.rb, line 803
def self.accept_loop(*sockets) # :yield: socket, client_addrinfo
  sockets.flatten!(1)
  if sockets.empty?
    raise ArgumentError, "no sockets"
  end
  loop {
    readable, _, _ = IO.select(sockets)
    readable.each {|r|
      sock, addr = r.accept_nonblock(exception: false)
      next if sock == :wait_readable
      yield sock, addr
    }
  }
end

Возвращает сокет и адрес клиента для каждого принятого соединения через указанные сокеты.

Аргументами является список сокетов. Каждый аргумент должен быть сокетом или массивом сокетов.

Этот метод выполняет блок последовательно. Это означает, что следующее соединение не принимается, пока блок не вернёт значение. Поэтому для обслуживания нескольких клиентов одновременно необходимо использовать механизмы параллельности, например, потоки.

getaddrinfo(nodename, servname[, family[, socktype[, protocol[, flags[, reverse_lookup]]]]]) → array Показать исходный код
static VALUE
sock_s_getaddrinfo(int argc, VALUE *argv, VALUE _)
{
    VALUE host, port, family, socktype, protocol, flags, ret, revlookup;
    struct addrinfo hints;
    struct rb_addrinfo *res;
    int norevlookup;

    rb_scan_args(argc, argv, "25", &host, &port, &family, &socktype, &protocol, &flags, &revlookup);

    MEMZERO(&hints, struct addrinfo, 1);
    hints.ai_family = NIL_P(family) ? PF_UNSPEC : rsock_family_arg(family);

    if (!NIL_P(socktype)) {
        hints.ai_socktype = rsock_socktype_arg(socktype);
    }
    if (!NIL_P(protocol)) {
        hints.ai_protocol = NUM2INT(protocol);
    }
    if (!NIL_P(flags)) {
        hints.ai_flags = NUM2INT(flags);
    }
    if (NIL_P(revlookup) || !rsock_revlookup_flag(revlookup, &norevlookup)) {
        norevlookup = rsock_do_not_reverse_lookup;
    }

    res = rsock_getaddrinfo(host, port, &hints, 0);

    ret = make_addrinfo(res, norevlookup);
    rb_freeaddrinfo(res);
    return ret;
}

Получает информацию об адресе для nodename:servname.

Обратите внимание, что Addrinfo.getaddrinfo обеспечивает ту же функциональность в объектно-ориентированном стиле.

family должен быть семейством адресов, например: :INET, :INET6 и т.д.

socktype должен быть типом сокета, например: :STREAM, :DGRAM, :RAW и т.д.

protocol должен быть протоколом, определённым в семействе, и по умолчанию равен 0 для семейства.

flags должны быть побитовым ИЛИ констант Socket::AI_*.

Socket.getaddrinfo("www.ruby-lang.org", "http", nil, :STREAM)
#=> [["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68", 2, 1, 6]] # PF_INET/SOCK_STREAM/IPPROTO_TCP

Socket.getaddrinfo("localhost", nil)
#=> [["AF_INET", 0, "localhost", "127.0.0.1", 2, 1, 6],  # PF_INET/SOCK_STREAM/IPPROTO_TCP
#    ["AF_INET", 0, "localhost", "127.0.0.1", 2, 2, 17], # PF_INET/SOCK_DGRAM/IPPROTO_UDP
#    ["AF_INET", 0, "localhost", "127.0.0.1", 2, 3, 0]]  # PF_INET/SOCK_RAW/IPPROTO_IP

reverse_lookup определяет вид третьего элемента и должен быть одним из следующих. Если reverse_lookup опущен, используется значение по умолчанию nil.

+true+, +:hostname+:  hostname is obtained from numeric address using reverse lookup, which may take a time.
+false+, +:numeric+:  hostname is the same as numeric address.
+nil+:              obey to the current +do_not_reverse_lookup+ flag.

Если предпочтительнее объект Addrinfo, используйте Addrinfo.getaddrinfo.

gethostbyaddr(address_string [, address_family]) → hostent Показать исходный код
static VALUE
sock_s_gethostbyaddr(int argc, VALUE *argv, VALUE _)
{
    VALUE addr, family;
    struct hostent *h;
    char **pch;
    VALUE ary, names;
    int t = AF_INET;

    rb_warn("Socket.gethostbyaddr is deprecated; use Addrinfo#getnameinfo instead.");

    rb_scan_args(argc, argv, "11", &addr, &family);
    StringValue(addr);
    if (!NIL_P(family)) {
        t = rsock_family_arg(family);
    }
#ifdef AF_INET6
    else if (RSTRING_LEN(addr) == 16) {
        t = AF_INET6;
    }
#endif
    h = gethostbyaddr(RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), t);
    if (h == NULL) {
#ifdef HAVE_HSTRERROR
        extern int h_errno;
        rb_raise(rb_eSocket, "%s", (char*)hstrerror(h_errno));
#else
        rb_raise(rb_eSocket, "host not found");
#endif
    }
    ary = rb_ary_new();
    rb_ary_push(ary, rb_str_new2(h->h_name));
    names = rb_ary_new();
    rb_ary_push(ary, names);
    if (h->h_aliases != NULL) {
        for (pch = h->h_aliases; *pch; pch++) {
            rb_ary_push(names, rb_str_new2(*pch));
        }
    }
    rb_ary_push(ary, INT2NUM(h->h_addrtype));
#ifdef h_addr
    for (pch = h->h_addr_list; *pch; pch++) {
        rb_ary_push(ary, rb_str_new(*pch, h->h_length));
    }
#else
    rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length));
#endif

    return ary;
}

Используйте Addrinfo#getnameinfo вместо этого. Этот метод устарел по следующим причинам:

  • Нестандартное представление адреса: двоичная строка из 4/16 байт для представления адресов IPv4/IPv6.

  • gethostbyaddr() может занимать много времени и блокировать другие потоки. (GVL не может быть освобождён, так как gethostbyname() не потокобезопасен.)

  • Этот метод использует функцию gethostbyname(), уже удалённую из POSIX.

Этот метод получает информацию о хосте для address.

p Socket.gethostbyaddr([221,186,184,68].pack("CCCC"))
#=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"]

p Socket.gethostbyaddr([127,0,0,1].pack("CCCC"))
["localhost", [], 2, "\x7F\x00\x00\x01"]
p Socket.gethostbyaddr(([0]*15+[1]).pack("C"*16))
#=> ["localhost", ["ip6-localhost", "ip6-loopback"], 10,
     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"]
gethostbyname(hostname) → [official_hostname, alias_hostnames, address_family, *address_list] Показать исходный код
static VALUE
sock_s_gethostbyname(VALUE obj, VALUE host)
{
    rb_warn("Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
    struct rb_addrinfo *res =
        rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
    return rsock_make_hostent(host, res, sock_sockaddr);
}

Используйте Addrinfo.getaddrinfo вместо этого. Этот метод устарел по следующим причинам:

  • Третий элемент результата — семейство адресов первого адреса. Семейства адресов остальных адресов не возвращаются.

  • Нестандартное представление адреса: двоичная строка из 4/16 байт для представления адресов IPv4/IPv6.

  • gethostbyname() может занимать много времени и блокировать другие потоки. (GVL не может быть освобождён, так как gethostbyname() не потокобезопасен.)

  • Этот метод использует функцию gethostbyname(), уже удалённую из POSIX.

Этот метод получает информацию о хосте для hostname.

p Socket.gethostbyname("hal") #=> ["localhost", ["hal"], 2, "\x7F\x00\x00\x01"]
gethostname → hostname Показать исходный код
static VALUE
sock_gethostname(VALUE obj)
{
#if defined(NI_MAXHOST)
#  define RUBY_MAX_HOST_NAME_LEN NI_MAXHOST
#elif defined(HOST_NAME_MAX)
#  define RUBY_MAX_HOST_NAME_LEN HOST_NAME_MAX
#else
#  define RUBY_MAX_HOST_NAME_LEN 1024
#endif

    long len = RUBY_MAX_HOST_NAME_LEN;
    VALUE name;

    name = rb_str_new(0, len);
    while (gethostname(RSTRING_PTR(name), len) < 0) {
        int e = errno;
        switch (e) {
          case ENAMETOOLONG:
#ifdef __linux__
          case EINVAL:
            /* glibc before version 2.1 uses EINVAL instead of ENAMETOOLONG */
#endif
            break;
          default:
            rb_syserr_fail(e, "gethostname(3)");
        }
        rb_str_modify_expand(name, len);
        len += len;
    }
    rb_str_resize(name, strlen(RSTRING_PTR(name)));
    return name;
}

Возвращает имя хоста.

p Socket.gethostname #=> "hal"

Обратите внимание, что нет гарантии возможности преобразования в IP-адрес с помощью gethostbyname, getaddrinfo и т.п. Если вам нужен локальный IP-адрес, используйте Socket.ip_address_list.

getifaddrs → [ifaddr1, ...] Показать исходный код
static VALUE
socket_s_getifaddrs(VALUE self)
{
    return rsock_getifaddrs();
}

Возвращает массив адресов интерфейсов. Элемент массива — экземпляр Socket::Ifaddr.

Этот метод можно использовать для поиска интерфейсов с поддержкой мультикаста:

pp Socket.getifaddrs.reject {|ifaddr|
  !ifaddr.addr.ip? || (ifaddr.flags & Socket::IFF_MULTICAST == 0)
}.map {|ifaddr| [ifaddr.name, ifaddr.ifindex, ifaddr.addr] }
#=> [["eth0", 2, #<Addrinfo: 221.186.184.67>],
#    ["eth0", 2, #<Addrinfo: fe80::216:3eff:fe95:88bb%eth0>]]

Пример результата на GNU/Linux:

pp Socket.getifaddrs
#=> [#<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 PACKET[protocol=0 lo hatype=772 HOST hwaddr=00:00:00:00:00:00]>,
#    #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=00:16:3e:95:88:bb] broadcast=PACKET[protocol=0 eth0 hatype=1 HOST hwaddr=ff:ff:ff:ff:ff:ff]>,
#    #<Socket::Ifaddr sit0 NOARP PACKET[protocol=0 sit0 hatype=776 HOST hwaddr=00:00:00:00]>,
#    #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 127.0.0.1 netmask=255.0.0.0>,
#    #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 221.186.184.67 netmask=255.255.255.240 broadcast=221.186.184.79>,
#    #<Socket::Ifaddr lo UP,LOOPBACK,RUNNING,0x10000 ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
#    #<Socket::Ifaddr eth0 UP,BROADCAST,RUNNING,MULTICAST,0x10000 fe80::216:3eff:fe95:88bb%eth0 netmask=ffff:ffff:ffff:ffff::>]

Пример результата на FreeBSD:

pp Socket.getifaddrs
#=> [#<Socket::Ifaddr usbus0 UP,0x10000 LINK[usbus0]>,
#    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 LINK[re0 3a:d0:40:9a:fe:e8]>,
#    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 10.250.10.18 netmask=255.255.255.? (7 bytes for 16 bytes sockaddr_in) broadcast=10.250.10.255>,
#    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 fe80:2::38d0:40ff:fe9a:fee8 netmask=ffff:ffff:ffff:ffff::>,
#    #<Socket::Ifaddr re0 UP,BROADCAST,RUNNING,MULTICAST,0x800 2001:2e8:408:10::12 netmask=UNSPEC>,
#    #<Socket::Ifaddr plip0 POINTOPOINT,MULTICAST,0x800 LINK[plip0]>,
#    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>,
#    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST ::1 netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>,
#    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST fe80:4::1 netmask=ffff:ffff:ffff:ffff::>,
#    #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST 127.0.0.1 netmask=255.?.?.? (5 bytes for 16 bytes sockaddr_in)>]
getnameinfo(sockaddr [, flags]) → [hostname, servicename] Показать исходный код
static VALUE
sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
{
    VALUE sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp;
    char hbuf[1024], pbuf[1024];
    int fl;
    struct rb_addrinfo *res = NULL;
    struct addrinfo hints, *r;
    int error, saved_errno;
    union_sockaddr ss;
    struct sockaddr *sap;
    socklen_t salen;

    sa = flags = Qnil;
    rb_scan_args(argc, argv, "11", &sa, &flags);

    fl = 0;
    if (!NIL_P(flags)) {
        fl = NUM2INT(flags);
    }
    tmp = rb_check_sockaddr_string_type(sa);
    if (!NIL_P(tmp)) {
        sa = tmp;
        if (sizeof(ss) < (size_t)RSTRING_LEN(sa)) {
            rb_raise(rb_eTypeError, "sockaddr length too big");
        }
        memcpy(&ss, RSTRING_PTR(sa), RSTRING_LEN(sa));
        if (!VALIDATE_SOCKLEN(&ss.addr, RSTRING_LEN(sa))) {
            rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
        }
        sap = &ss.addr;
        salen = RSTRING_SOCKLEN(sa);
        goto call_nameinfo;
    }
    tmp = rb_check_array_type(sa);
    if (!NIL_P(tmp)) {
        sa = tmp;
        MEMZERO(&hints, struct addrinfo, 1);
        if (RARRAY_LEN(sa) == 3) {
            af = RARRAY_AREF(sa, 0);
            port = RARRAY_AREF(sa, 1);
            host = RARRAY_AREF(sa, 2);
        }
        else if (RARRAY_LEN(sa) >= 4) {
            af = RARRAY_AREF(sa, 0);
            port = RARRAY_AREF(sa, 1);
            host = RARRAY_AREF(sa, 3);
            if (NIL_P(host)) {
                host = RARRAY_AREF(sa, 2);
            }
            else {
                /*
                 * 4th element holds numeric form, don't resolve.
                 * see rsock_ipaddr().
                 */
#ifdef AI_NUMERICHOST /* AIX 4.3.3 doesn't have AI_NUMERICHOST. */
                hints.ai_flags |= AI_NUMERICHOST;
#endif
            }
        }
        else {
            rb_raise(rb_eArgError, "array size should be 3 or 4, %ld given",
                     RARRAY_LEN(sa));
        }
        hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
        /* af */
        hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
        res = rsock_getaddrinfo(host, port, &hints, 0);
        sap = res->ai->ai_addr;
        salen = res->ai->ai_addrlen;
    }
    else {
        rb_raise(rb_eTypeError, "expecting String or Array");
    }

  call_nameinfo:
    error = rb_getnameinfo(sap, salen, hbuf, sizeof(hbuf),
                           pbuf, sizeof(pbuf), fl);
    if (error) goto error_exit_name;
    if (res) {
        for (r = res->ai->ai_next; r; r = r->ai_next) {
            char hbuf2[1024], pbuf2[1024];

            sap = r->ai_addr;
            salen = r->ai_addrlen;
            error = rb_getnameinfo(sap, salen, hbuf2, sizeof(hbuf2),
                                   pbuf2, sizeof(pbuf2), fl);
            if (error) goto error_exit_name;
            if (strcmp(hbuf, hbuf2) != 0|| strcmp(pbuf, pbuf2) != 0) {
                rb_freeaddrinfo(res);
                rb_raise(rb_eSocket, "sockaddr resolved to multiple nodename");
            }
        }
        rb_freeaddrinfo(res);
    }
    return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));

  error_exit_name:
    saved_errno = errno;
    if (res) rb_freeaddrinfo(res);
    errno = saved_errno;
    rsock_raise_socket_error("getnameinfo", error);

    UNREACHABLE_RETURN(Qnil);
}

Получает информацию о имени для sockaddr.

sockaddr должен быть одним из следующих.

  • Упакованная строка sockaddr, например Socket.sockaddr_in(80, “127.0.0.1”)

  • Массив из 3 элементов, например [“AF_INET”, 80, “127.0.0.1”]

  • Массив из 4 элементов, например [“AF_INET”, 80, пропуск, “127.0.0.1”]

flags должны быть побитовым ИЛИ констант Socket::NI_*.

Примечание: Последняя форма совместима с IPSocket#addr и IPSocket#peeraddr.

Socket.getnameinfo(Socket.sockaddr_in(80, "127.0.0.1"))       #=> ["localhost", "www"]
Socket.getnameinfo(["AF_INET", 80, "127.0.0.1"])              #=> ["localhost", "www"]
Socket.getnameinfo(["AF_INET", 80, "localhost", "127.0.0.1"]) #=> ["localhost", "www"]

Если предпочтительнее объект Addrinfo, используйте Addrinfo#getnameinfo.

getservbyname(service_name) → port_number Показать исходный код
getservbyname(service_name, protocol_name) → port_number
static VALUE
sock_s_getservbyname(int argc, VALUE *argv, VALUE _)
{
    VALUE service, proto;
    struct servent *sp;
    long port;
    const char *servicename, *protoname = "tcp";

    rb_scan_args(argc, argv, "11", &service, &proto);
    StringValue(service);
    if (!NIL_P(proto)) StringValue(proto);
    servicename = StringValueCStr(service);
    if (!NIL_P(proto)) protoname = StringValueCStr(proto);
    sp = getservbyname(servicename, protoname);
    if (sp) {
        port = ntohs(sp->s_port);
    }
    else {
        char *end;

        port = STRTOUL(servicename, &end, 0);
        if (*end != '\0') {
            rb_raise(rb_eSocket, "no such service %s/%s", servicename, protoname);
        }
    }
    return INT2FIX(port);
}

Получает номер порта для service_name.

Если protocol_name не указан, предполагается «tcp».

Socket.getservbyname("smtp")          #=> 25
Socket.getservbyname("shell")         #=> 514
Socket.getservbyname("syslog", "udp") #=> 514
getservbyport(port [, protocol_name]) → service Показать исходный код
static VALUE
sock_s_getservbyport(int argc, VALUE *argv, VALUE _)
{
    VALUE port, proto;
    struct servent *sp;
    long portnum;
    const char *protoname = "tcp";

    rb_scan_args(argc, argv, "11", &port, &proto);
    portnum = NUM2LONG(port);
    if (portnum != (uint16_t)portnum) {
        const char *s = portnum > 0 ? "big" : "small";
        rb_raise(rb_eRangeError, "integer %ld too %s to convert into `int16_t'", portnum, s);
    }
    if (!NIL_P(proto)) protoname = StringValueCStr(proto);

    sp = getservbyport((int)htons((uint16_t)portnum), protoname);
    if (!sp) {
        rb_raise(rb_eSocket, "no such service for port %d/%s", (int)portnum, protoname);
    }
    return rb_str_new2(sp->s_name);
}

Получает номер порта для port.

Если protocol_name не указан, предполагается «tcp».

Socket.getservbyport(80)         #=> "www"
Socket.getservbyport(514, "tcp") #=> "shell"
Socket.getservbyport(514, "udp") #=> "syslog"
ip_address_list → array Показать исходный код
static VALUE
socket_s_ip_address_list(VALUE self)
{
#if defined(HAVE_GETIFADDRS)
    struct ifaddrs *ifp = NULL;
    struct ifaddrs *p;
    int ret;
    VALUE list;

    ret = getifaddrs(&ifp);
    if (ret == -1) {
        rb_sys_fail("getifaddrs");
    }

    list = rb_ary_new();
    for (p = ifp; p; p = p->ifa_next) {
        if (p->ifa_addr != NULL && IS_IP_FAMILY(p->ifa_addr->sa_family)) {
            struct sockaddr *addr = p->ifa_addr;
#if defined(AF_INET6) && defined(__sun)
            /*
             * OpenIndiana SunOS 5.11 getifaddrs() returns IPv6 link local
             * address with sin6_scope_id == 0.
             * So fill it from the interface name (ifa_name).
             */
            struct sockaddr_in6 addr6;
            if (addr->sa_family == AF_INET6) {
                socklen_t len = (socklen_t)sizeof(struct sockaddr_in6);
                memcpy(&addr6, addr, len);
                addr = (struct sockaddr *)&addr6;
                if (IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) &&
                    addr6.sin6_scope_id == 0) {
                    unsigned int ifindex = if_nametoindex(p->ifa_name);
                    if (ifindex != 0) {
                        addr6.sin6_scope_id = ifindex;
                    }
                }
            }
#endif
            rb_ary_push(list, sockaddr_obj(addr, sockaddr_len(addr)));
        }
    }

    freeifaddrs(ifp);

    return list;
#elif defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM)
    /* Solaris if_tcp(7P) */
    int fd = -1;
    int ret;
    struct lifnum ln;
    struct lifconf lc;
    const char *reason = NULL;
    int save_errno;
    int i;
    VALUE list = Qnil;

    lc.lifc_buf = NULL;

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd == -1)
        rb_sys_fail("socket(2)");

    memset(&ln, 0, sizeof(ln));
    ln.lifn_family = AF_UNSPEC;

    ret = ioctl(fd, SIOCGLIFNUM, &ln);
    if (ret == -1) {
        reason = "SIOCGLIFNUM";
        goto finish;
    }

    memset(&lc, 0, sizeof(lc));
    lc.lifc_family = AF_UNSPEC;
    lc.lifc_flags = 0;
    lc.lifc_len = sizeof(struct lifreq) * ln.lifn_count;
    lc.lifc_req = xmalloc(lc.lifc_len);

    ret = ioctl(fd, SIOCGLIFCONF, &lc);
    if (ret == -1) {
        reason = "SIOCGLIFCONF";
        goto finish;
    }

    list = rb_ary_new();
    for (i = 0; i < ln.lifn_count; i++) {
        struct lifreq *req = &lc.lifc_req[i];
        if (IS_IP_FAMILY(req->lifr_addr.ss_family)) {
            if (req->lifr_addr.ss_family == AF_INET6 &&
                IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_addr) &&
                ((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id == 0) {
                struct lifreq req2;
                memcpy(req2.lifr_name, req->lifr_name, LIFNAMSIZ);
                ret = ioctl(fd, SIOCGLIFINDEX, &req2);
                if (ret == -1) {
                    reason = "SIOCGLIFINDEX";
                    goto finish;
                }
                ((struct sockaddr_in6 *)(&req->lifr_addr))->sin6_scope_id = req2.lifr_index;
            }
            rb_ary_push(list, sockaddr_obj((struct sockaddr *)&req->lifr_addr, req->lifr_addrlen));
        }
    }

  finish:
    save_errno = errno;
    if (lc.lifc_buf != NULL)
        xfree(lc.lifc_req);
    if (fd != -1)
        close(fd);
    errno = save_errno;

    if (reason)
        rb_syserr_fail(save_errno, reason);
    return list;

#elif defined(SIOCGIFCONF)
    int fd = -1;
    int ret;
#define EXTRA_SPACE ((int)(sizeof(struct ifconf) + sizeof(union_sockaddr)))
    char initbuf[4096+EXTRA_SPACE];
    char *buf = initbuf;
    int bufsize;
    struct ifconf conf;
    struct ifreq *req;
    VALUE list = Qnil;
    const char *reason = NULL;
    int save_errno;

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd == -1)
        rb_sys_fail("socket(2)");

    bufsize = sizeof(initbuf);
    buf = initbuf;

  retry:
    conf.ifc_len = bufsize;
    conf.ifc_req = (struct ifreq *)buf;

    /* fprintf(stderr, "bufsize: %d\n", bufsize); */

    ret = ioctl(fd, SIOCGIFCONF, &conf);
    if (ret == -1) {
        reason = "SIOCGIFCONF";
        goto finish;
    }

    /* fprintf(stderr, "conf.ifc_len: %d\n", conf.ifc_len); */

    if (bufsize - EXTRA_SPACE < conf.ifc_len) {
        if (bufsize < conf.ifc_len) {
            /* NetBSD returns required size for all interfaces. */
            bufsize = conf.ifc_len + EXTRA_SPACE;
        }
        else {
            bufsize = bufsize << 1;
        }
        if (buf == initbuf)
            buf = NULL;
        buf = xrealloc(buf, bufsize);
        goto retry;
    }

    close(fd);
    fd = -1;

    list = rb_ary_new();
    req = conf.ifc_req;
    while ((char*)req < (char*)conf.ifc_req + conf.ifc_len) {
        struct sockaddr *addr = &req->ifr_addr;
        if (IS_IP_FAMILY(addr->sa_family)) {
            rb_ary_push(list, sockaddr_obj(addr, sockaddr_len(addr)));
        }
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
# ifndef _SIZEOF_ADDR_IFREQ
#  define _SIZEOF_ADDR_IFREQ(r) \
          (sizeof(struct ifreq) + \
           (sizeof(struct sockaddr) < (r).ifr_addr.sa_len ? \
            (r).ifr_addr.sa_len - sizeof(struct sockaddr) : \
            0))
# endif
        req = (struct ifreq *)((char*)req + _SIZEOF_ADDR_IFREQ(*req));
#else
        req = (struct ifreq *)((char*)req + sizeof(struct ifreq));
#endif
    }

  finish:

    save_errno = errno;
    if (buf != initbuf)
        xfree(buf);
    if (fd != -1)
        close(fd);
    errno = save_errno;

    if (reason)
        rb_syserr_fail(save_errno, reason);
    return list;

#undef EXTRA_SPACE
#elif defined(_WIN32)
    typedef struct ip_adapter_unicast_address_st {
        unsigned LONG_LONG dummy0;
        struct ip_adapter_unicast_address_st *Next;
        struct {
            struct sockaddr *lpSockaddr;
            int iSockaddrLength;
        } Address;
        int dummy1;
        int dummy2;
        int dummy3;
        long dummy4;
        long dummy5;
        long dummy6;
    } ip_adapter_unicast_address_t;
    typedef struct ip_adapter_anycast_address_st {
        unsigned LONG_LONG dummy0;
        struct ip_adapter_anycast_address_st *Next;
        struct {
            struct sockaddr *lpSockaddr;
            int iSockaddrLength;
        } Address;
    } ip_adapter_anycast_address_t;
    typedef struct ip_adapter_addresses_st {
        unsigned LONG_LONG dummy0;
        struct ip_adapter_addresses_st *Next;
        void *dummy1;
        ip_adapter_unicast_address_t *FirstUnicastAddress;
        ip_adapter_anycast_address_t *FirstAnycastAddress;
        void *dummy2;
        void *dummy3;
        void *dummy4;
        void *dummy5;
        void *dummy6;
        BYTE dummy7[8];
        DWORD dummy8;
        DWORD dummy9;
        DWORD dummy10;
        DWORD IfType;
        int OperStatus;
        DWORD dummy12;
        DWORD dummy13[16];
        void *dummy14;
    } ip_adapter_addresses_t;
    typedef ULONG (WINAPI *GetAdaptersAddresses_t)(ULONG, ULONG, PVOID, ip_adapter_addresses_t *, PULONG);
    HMODULE h;
    GetAdaptersAddresses_t pGetAdaptersAddresses;
    ULONG len;
    DWORD ret;
    ip_adapter_addresses_t *adapters;
    VALUE list;

    h = LoadLibrary("iphlpapi.dll");
    if (!h)
        rb_notimplement();
    pGetAdaptersAddresses = (GetAdaptersAddresses_t)GetProcAddress(h, "GetAdaptersAddresses");
    if (!pGetAdaptersAddresses) {
        FreeLibrary(h);
        rb_notimplement();
    }

    ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &len);
    if (ret != ERROR_SUCCESS && ret != ERROR_BUFFER_OVERFLOW) {
        errno = rb_w32_map_errno(ret);
        FreeLibrary(h);
        rb_sys_fail("GetAdaptersAddresses");
    }
    adapters = (ip_adapter_addresses_t *)ALLOCA_N(BYTE, len);
    ret = pGetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapters, &len);
    if (ret != ERROR_SUCCESS) {
        errno = rb_w32_map_errno(ret);
        FreeLibrary(h);
        rb_sys_fail("GetAdaptersAddresses");
    }

    list = rb_ary_new();
    for (; adapters; adapters = adapters->Next) {
        ip_adapter_unicast_address_t *uni;
        ip_adapter_anycast_address_t *any;
        if (adapters->OperStatus != 1)  /* 1 means IfOperStatusUp */
            continue;
        for (uni = adapters->FirstUnicastAddress; uni; uni = uni->Next) {
#ifndef INET6
            if (uni->Address.lpSockaddr->sa_family == AF_INET)
#else
            if (IS_IP_FAMILY(uni->Address.lpSockaddr->sa_family))
#endif
                rb_ary_push(list, sockaddr_obj(uni->Address.lpSockaddr, uni->Address.iSockaddrLength));
        }
        for (any = adapters->FirstAnycastAddress; any; any = any->Next) {
#ifndef INET6
            if (any->Address.lpSockaddr->sa_family == AF_INET)
#else
            if (IS_IP_FAMILY(any->Address.lpSockaddr->sa_family))
#endif
                rb_ary_push(list, sockaddr_obj(any->Address.lpSockaddr, any->Address.iSockaddrLength));
        }
    }

    FreeLibrary(h);
    return list;
#endif
}

Возвращает локальные IP-адреса в виде массива.

Массив содержит объекты Addrinfo.

pp Socket.ip_address_list
#=> [#<Addrinfo: 127.0.0.1>,
     #<Addrinfo: 192.168.0.128>,
     #<Addrinfo: ::1>,
     ...]
new(domain, socktype [, protocol]) → socket Показать исходный код
static VALUE
sock_initialize(int argc, VALUE *argv, VALUE sock)
{
    VALUE domain, type, protocol;
    int fd;
    int d, t;

    rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
    if (NIL_P(protocol))
        protocol = INT2FIX(0);

    setup_domain_and_type(domain, &d, type, &t);
    fd = rsock_socket(d, t, NUM2INT(protocol));
    if (fd < 0) rb_sys_fail("socket(2)");

    return rsock_init_sock(sock, fd);
}

Создаёт новый объект сокета.

domain должно быть областью связи, например: :INET, :INET6, :UNIX и т.д.

socktype должен быть типом сокета, например: :STREAM, :DGRAM, :RAW и т.д.

protocol необязателен и должен быть протоколом, определённым в области. Если protocol не задан, внутри используется 0.

Socket.new(:INET, :STREAM) # TCP socket
Socket.new(:INET, :DGRAM)  # UDP socket
Socket.new(:UNIX, :STREAM) # UNIX stream socket
Socket.new(:UNIX, :DGRAM)  # UNIX datagram socket
sockaddr_in(port, host) → sockaddr Показать исходный код
pack_sockaddr_in(port, host) → sockaddr
static VALUE
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
{
    struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0);
    VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);

    rb_freeaddrinfo(res);

    return addr;
}

Упаковывает port и host в строку sockaddr AF_INET/AF_INET6.

Socket.sockaddr_in(80, "127.0.0.1")
#=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"

Socket.sockaddr_in(80, "::1")
#=> "\n\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
sockaddr_un(path) → sockaddr Показать исходный код
pack_sockaddr_un(path) → sockaddr
static VALUE
sock_s_pack_sockaddr_un(VALUE self, VALUE path)
{
    struct sockaddr_un sockaddr;
    VALUE addr;

    StringValue(path);
    INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
    if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
        rb_raise(rb_eArgError, "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
            (size_t)RSTRING_LEN(path), sizeof(sockaddr.sun_path));
    }
    memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
    addr = rb_str_new((char*)&sockaddr, rsock_unix_sockaddr_len(path));

    return addr;
}

Упаковывает path в строку sockaddr AF_UNIX.

Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
pair(domain, type, protocol) → [socket1, socket2] Показать исходный код
socketpair(domain, type, protocol) → [socket1, socket2]
VALUE
rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
{
    VALUE domain, type, protocol;
    int d, t, p, sp[2];
    int ret;
    VALUE s1, s2, r;

    rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
    if (NIL_P(protocol))
        protocol = INT2FIX(0);

    setup_domain_and_type(domain, &d, type, &t);
    p = NUM2INT(protocol);
    ret = rsock_socketpair(d, t, p, sp);
    if (ret < 0) {
        rb_sys_fail("socketpair(2)");
    }

    s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
    s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
    r = rb_assoc_new(s1, s2);
    if (rb_block_given_p()) {
        return rb_ensure(pair_yield, r, io_close, s1);
    }
    return r;
}

Создаёт пару сокетов, соединённых друг с другом.

domain должно быть областью связи, например: :INET, :INET6, :UNIX и т.д.

socktype должен быть типом сокета, например: :STREAM, :DGRAM, :RAW и т.д.

protocol должен быть протоколом, определённым в области, по умолчанию равен 0 для области.

s1, s2 = Socket.pair(:UNIX, :STREAM, 0)
s1.send "a", 0
s1.send "b", 0
s1.close
p s2.recv(10) #=> "ab"
p s2.recv(10) #=> ""
p s2.recv(10) #=> ""

s1, s2 = Socket.pair(:UNIX, :DGRAM, 0)
s1.send "a", 0
s1.send "b", 0
p s2.recv(10) #=> "a"
p s2.recv(10) #=> "b"
END_OF_DOCUMENT_MARKER
sockaddr_in(port, host) → sockaddr Показать исходный код
pack_sockaddr_in(port, host) → sockaddr
static VALUE
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
{
    struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0);
    VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);

    rb_freeaddrinfo(res);

    return addr;
}

Упаковывает port и host в строку sockaddr AF_INET/AF_INET6.

Socket.sockaddr_in(80, "127.0.0.1")
#=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"

Socket.sockaddr_in(80, "::1")
#=> "\n\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
sockaddr_un(path) → sockaddr Показать исходный код
pack_sockaddr_un(path) → sockaddr
static VALUE
sock_s_pack_sockaddr_un(VALUE self, VALUE path)
{
    struct sockaddr_un sockaddr;
    VALUE addr;

    StringValue(path);
    INIT_SOCKADDR_UN(&sockaddr, sizeof(struct sockaddr_un));
    if (sizeof(sockaddr.sun_path) < (size_t)RSTRING_LEN(path)) {
        rb_raise(rb_eArgError, "too long unix socket path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)",
            (size_t)RSTRING_LEN(path), sizeof(sockaddr.sun_path));
    }
    memcpy(sockaddr.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
    addr = rb_str_new((char*)&sockaddr, rsock_unix_sockaddr_len(path));

    return addr;
}

Упаковывает path в строку sockaddr AF_UNIX.

Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
pair(domain, type, protocol) → [socket1, socket2] Показать исходный код
socketpair(domain, type, protocol) → [socket1, socket2]
VALUE
rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
{
    VALUE domain, type, protocol;
    int d, t, p, sp[2];
    int ret;
    VALUE s1, s2, r;

    rb_scan_args(argc, argv, "21", &domain, &type, &protocol);
    if (NIL_P(protocol))
        protocol = INT2FIX(0);

    setup_domain_and_type(domain, &d, type, &t);
    p = NUM2INT(protocol);
    ret = rsock_socketpair(d, t, p, sp);
    if (ret < 0) {
        rb_sys_fail("socketpair(2)");
    }

    s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
    s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
    r = rb_assoc_new(s1, s2);
    if (rb_block_given_p()) {
        return rb_ensure(pair_yield, r, io_close, s1);
    }
    return r;
}

Создаёт пару сокетов, соединённых друг с другом.

domain должен быть домен связи, такой как: :INET, :INET6, :UNIX и т.д.

socktype должен быть типом сокета, таким как: :STREAM, :DGRAM, :RAW и т.д.

protocol должен быть протоколом, определённым в домене, по умолчанию равен 0 для домена.

s1, s2 = Socket.pair(:UNIX, :STREAM, 0)
s1.send "a", 0
s1.send "b", 0
s1.close
p s2.recv(10) #=> "ab"
p s2.recv(10) #=> ""
p s2.recv(10) #=> ""

s1, s2 = Socket.pair(:UNIX, :DGRAM, 0)
s1.send "a", 0
s1.send "b", 0
p s2.recv(10) #=> "a"
p s2.recv(10) #=> "b"
tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... } Показать исходный код
tcp(host, port, local_host=nil, local_port=nil, [opts])
# File ext/socket/lib/socket.rb, line 626
def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil) # :yield: socket
  last_error = nil
  ret = nil

  local_addr_list = nil
  if local_host != nil || local_port != nil
    local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
  end

  Addrinfo.foreach(host, port, nil, :STREAM, timeout: resolv_timeout) {|ai|
    if local_addr_list
      local_addr = local_addr_list.find {|local_ai| local_ai.afamily == ai.afamily }
      next unless local_addr
    else
      local_addr = nil
    end
    begin
      sock = local_addr ?
        ai.connect_from(local_addr, timeout: connect_timeout) :
        ai.connect(timeout: connect_timeout)
    rescue SystemCallError
      last_error = $!
      next
    end
    ret = sock
    break
  }
  unless ret
    if last_error
      raise last_error
    else
      raise SocketError, "no appropriate local address"
    end
  end
  if block_given?
    begin
      yield ret
    ensure
      ret.close
    end
  else
    ret
  end
end

создаёт новый объект сокета, подключённый к host:port с использованием TCP/IP.

Если заданы local_host:local_port, сокет привязывается к ним.

Дополнительный последний аргумент opts представляет собой опции, представленные в виде хэша. opts может иметь следующие опции:

:connect_timeout

указывает таймаут в секундах.

Если задан блок, блок вызывается с сокетом. Возвращаемое значение блока возвращается. Сокет закрывается при возвращении этого метода.

Если блок не задан, сокет возвращается.

Socket.tcp("www.ruby-lang.org", 80) {|sock|
  sock.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n"
  sock.close_write
  puts sock.read
}
tcp_server_loop(host=nil, port) { |socket, client_addrinfo| ... } Показать исходный код
# File ext/socket/lib/socket.rb, line 859
def self.tcp_server_loop(host=nil, port, &b) # :yield: socket, client_addrinfo
  tcp_server_sockets(host, port) {|sockets|
    accept_loop(sockets, &b)
  }
end

создаёт TCP/IP сервер на port и вызывает блок для каждого принятого подключения. Блок вызывается с сокетом и адресом клиента как объектом Addrinfo.

Если задан host, он используется с port для определения адресов сервера.

Сокет не закрывается при возвращении блока. Поэтому приложение должно закрыть его явно.

Этот метод вызывает блок последовательно. Это означает, что следующее подключение не принимается, пока блок не вернётся. Таким образом, для одновременного обслуживания нескольких клиентов необходимо использовать механизм конкурентности, например, потоки.

Обратите внимание, что используется Addrinfo.getaddrinfo для определения адресов сокета сервера. Когда Addrinfo.getaddrinfo возвращает два или более адреса, например, IPv4 и IPv6 адрес, все они используются. Socket.tcp_server_loop успешно выполняется, если хотя бы один сокет может быть использован.

# Sequential echo server.
# It services only one client at a time.
Socket.tcp_server_loop(16807) {|sock, client_addrinfo|
  begin
    IO.copy_stream(sock, sock)
  ensure
    sock.close
  end
}

# Threaded echo server
# It services multiple clients at a time.
# Note that it may accept connections too much.
Socket.tcp_server_loop(16807) {|sock, client_addrinfo|
  Thread.new {
    begin
      IO.copy_stream(sock, sock)
    ensure
      sock.close
    end
  }
}
tcp_server_sockets(host=nil, port) { |sockets| ... } Показать исходный код
# File ext/socket/lib/socket.rb, line 759
def self.tcp_server_sockets(host=nil, port)
  if port == 0
    sockets = tcp_server_sockets_port0(host)
  else
    last_error = nil
    sockets = []
    begin
      Addrinfo.foreach(host, port, nil, :STREAM, nil, Socket::AI_PASSIVE) {|ai|
        begin
          s = ai.listen
        rescue SystemCallError
          last_error = $!
          next
        end
        sockets << s
      }
      if sockets.empty?
        raise last_error
      end
    rescue Exception
      sockets.each(&:close)
      raise
    end
  end
  if block_given?
    begin
      yield sockets
    ensure
      sockets.each(&:close)
    end
  else
    sockets
  end
end

создаёт сокеты TCP/IP сервера для host и port. host необязателен.

Если блок не задан, возвращает массив прослушивающих сокетов.

Если задан блок, блок вызывается с сокетами. Возвращаемое значение блока возвращается. Сокет закрывается при возвращении этого метода.

Если port равен 0, выбирается фактический номер порта динамически. Однако у всех сокетов в результате будет одинаковый номер порта.

# tcp_server_sockets returns two sockets.
sockets = Socket.tcp_server_sockets(1296)
p sockets #=> [#<Socket:fd 3>, #<Socket:fd 4>]

# The sockets contains IPv6 and IPv4 sockets.
sockets.each {|s| p s.local_address }
#=> #<Addrinfo: [::]:1296 TCP>
#   #<Addrinfo: 0.0.0.0:1296 TCP>

# IPv6 and IPv4 socket has same port number, 53114, even if it is chosen dynamically.
sockets = Socket.tcp_server_sockets(0)
sockets.each {|s| p s.local_address }
#=> #<Addrinfo: [::]:53114 TCP>
#   #<Addrinfo: 0.0.0.0:53114 TCP>

# The block is called with the sockets.
Socket.tcp_server_sockets(0) {|sockets|
  p sockets #=> [#<Socket:fd 3>, #<Socket:fd 4>]
}
udp_server_loop(port) {|msg, msg_src| ... } Показать исходный код
udp_server_loop(host, port) {|msg, msg_src| ... }
# File ext/socket/lib/socket.rb, line 1029
def self.udp_server_loop(host=nil, port, &b) # :yield: message, message_source
  udp_server_sockets(host, port) {|sockets|
    udp_server_loop_on(sockets, &b)
  }
end

создаёт UDP/IP сервер на port и вызывает блок для каждого принятого сообщения. Блок вызывается с сообщением и информацией об источнике.

Этот метод выделяет сокеты внутри, используя port. Если задан host, он используется совместно с port для определения адресов сервера.

msg — это строка.

msg_src — объект Socket::UDPSource. Он используется для ответа.

# UDP/IP echo server.
Socket.udp_server_loop(9261) {|msg, msg_src|
  msg_src.reply msg
}
udp_server_loop_on(sockets) {|msg, msg_src| ... } Показать исходный код
# File ext/socket/lib/socket.rb, line 1002
def self.udp_server_loop_on(sockets, &b) # :yield: msg, msg_src
  loop {
    readable, _, _ = IO.select(sockets)
    udp_server_recv(readable, &b)
  }
end

Запустить цикл UDP/IP сервера на заданных сокетах.

Возвращаемое значение Socket.udp_server_sockets подходит в качестве аргумента.

Вызывает блок для каждого полученного сообщения.

udp_server_recv(sockets) {|msg, msg_src| ... } Показать исходный код
# File ext/socket/lib/socket.rb, line 975
def self.udp_server_recv(sockets)
  sockets.each {|r|
    msg, sender_addrinfo, _, *controls = r.recvmsg_nonblock(exception: false)
    next if msg == :wait_readable
    ai = r.local_address
    if ai.ipv6? and pktinfo = controls.find {|c| c.cmsg_is?(:IPV6, :PKTINFO) }
      ai = Addrinfo.udp(pktinfo.ipv6_pktinfo_addr.ip_address, ai.ip_port)
      yield msg, UDPSource.new(sender_addrinfo, ai) {|reply_msg|
        r.sendmsg reply_msg, 0, sender_addrinfo, pktinfo
      }
    else
      yield msg, UDPSource.new(sender_addrinfo, ai) {|reply_msg|
        r.send reply_msg, 0, sender_addrinfo
      }
    end
  }
end

Принимать UDP/IP пакеты от заданных sockets. Для каждого полученного пакета вызывается блок.

Блок получает msg и msg_src. msg — это строка, которая является полезной нагрузкой полученного пакета. msg_src — объект Socket::UDPSource, который используется для ответа.

Socket.udp_server_loop может быть реализована с помощью этого метода следующим образом.

udp_server_sockets(host, port) {|sockets|
  loop {
    readable, _, _ = IO.select(sockets)
    udp_server_recv(readable) {|msg, msg_src| ... }
  }
}
udp_server_sockets([host, ] port) Показать исходный код
# File ext/socket/lib/socket.rb, line 887
def self.udp_server_sockets(host=nil, port)
  last_error = nil
  sockets = []

  ipv6_recvpktinfo = nil
  if defined? Socket::AncillaryData
    if defined? Socket::IPV6_RECVPKTINFO # RFC 3542
      ipv6_recvpktinfo = Socket::IPV6_RECVPKTINFO
    elsif defined? Socket::IPV6_PKTINFO # RFC 2292
      ipv6_recvpktinfo = Socket::IPV6_PKTINFO
    end
  end

  local_addrs = Socket.ip_address_list

  ip_list = []
  Addrinfo.foreach(host, port, nil, :DGRAM, nil, Socket::AI_PASSIVE) {|ai|
    if ai.ipv4? && ai.ip_address == "0.0.0.0"
      local_addrs.each {|a|
        next unless a.ipv4?
        ip_list << Addrinfo.new(a.to_sockaddr, :INET, :DGRAM, 0);
      }
    elsif ai.ipv6? && ai.ip_address == "::" && !ipv6_recvpktinfo
      local_addrs.each {|a|
        next unless a.ipv6?
        ip_list << Addrinfo.new(a.to_sockaddr, :INET6, :DGRAM, 0);
      }
    else
      ip_list << ai
    end
  }
  ip_list.uniq!(&:to_sockaddr)

  if port == 0
    sockets = ip_sockets_port0(ip_list, false)
  else
    ip_list.each {|ip|
      ai = Addrinfo.udp(ip.ip_address, port)
      begin
        s = ai.bind
      rescue SystemCallError
        last_error = $!
        next
      end
      sockets << s
    }
    if sockets.empty?
      raise last_error
    end
  end

  sockets.each {|s|
    ai = s.local_address
    if ipv6_recvpktinfo && ai.ipv6? && ai.ip_address == "::"
      s.setsockopt(:IPV6, ipv6_recvpktinfo, 1)
    end
  }

  if block_given?
    begin
      yield sockets
    ensure
      sockets.each(&:close) if sockets
    end
  else
    sockets
  end
end

Создаёт UDP/IP сокеты для UDP сервера.

Если блок не задан, возвращает массив сокетов.

Если задан блок, блок вызывается с сокетами. Возвращаемое значение блока возвращается. Сокеты закрываются по возвращении этого метода.

Если port равен нулю, выбирается какой-то порт. Но выбранный порт используется для всех сокетов.

# UDP/IP echo server
Socket.udp_server_sockets(0) {|sockets|
  p sockets.first.local_address.ip_port     #=> 32963
  Socket.udp_server_loop_on(sockets) {|msg, msg_src|
    msg_src.reply msg
  }
}
unix(path) { |socket| ... } Показать исходный код
# File ext/socket/lib/socket.rb, line 1079
def self.unix(path) # :yield: socket
  addr = Addrinfo.unix(path)
  sock = addr.connect
  if block_given?
    begin
      yield sock
    ensure
      sock.close
    end
  else
    sock
  end
end

создаёт новый сокет, подключённый к пути с помощью сокета UNIX.

Если задан блок, блок вызывается с сокетом. Возвращаемое значение блока возвращается. Сокет закрывается при возвращении этого метода.

Если блок не задан, сокет возвращается.

# talk to /tmp/sock socket.
Socket.unix("/tmp/sock") {|sock|
  t = Thread.new { IO.copy_stream(sock, STDOUT) }
  IO.copy_stream(STDIN, sock)
  t.join
}
unix_server_loop(path) { |socket, client_addrinfo| ... } Показать исходный код
# File ext/socket/lib/socket.rb, line 1166
def self.unix_server_loop(path, &b) # :yield: socket, client_addrinfo
  unix_server_socket(path) {|serv|
    accept_loop(serv, &b)
  }
end

создаёт UNIX сокет-сервер по path. Вызывает блок для каждого принятого сокета.

Если задан host, он используется с port для определения портов сервера.

Сокет не закрывается при возвращении блока. Приложение должно закрыть его.

Этот метод удаляет файл сокета, указанный по path, если это файл сокета и он принадлежит пользователю приложения. Это безопасно только в том случае, если каталог path не меняется злонамеренным пользователем. Не используйте /tmp/malicious-users-directory/socket. Обратите внимание, что /tmp/socket и /tmp/your-private-directory/socket являются безопасными, предполагая, что /tmp имеет бит "sticky".

# Sequential echo server.
# It services only one client at a time.
Socket.unix_server_loop("/tmp/sock") {|sock, client_addrinfo|
  begin
    IO.copy_stream(sock, sock)
  ensure
    sock.close
  end
}
unix_server_socket(path) { |s| ... } Показать исходный код
# File ext/socket/lib/socket.rb, line 1109
def self.unix_server_socket(path)
  unless unix_socket_abstract_name?(path)
    begin
      st = File.lstat(path)
    rescue Errno::ENOENT
    end
    if st&.socket? && st.owned?
      File.unlink path
    end
  end
  s = Addrinfo.unix(path).listen
  if block_given?
    begin
      yield s
    ensure
      s.close
      unless unix_socket_abstract_name?(path)
        File.unlink path
      end
    end
  else
    s
  end
end

создаёт UNIX сокет-сервер по path

Если блок не задан, возвращает прослушивающий сокет.

Если задан блок, он вызывается с сокетом, и значение блока возвращается. Когда блок завершается, сокет закрывается, а файл сокета удаляется.

socket = Socket.unix_server_socket("/tmp/s")
p socket                  #=> #<Socket:fd 3>
p socket.local_address    #=> #<Addrinfo: /tmp/s SOCK_STREAM>

Socket.unix_server_socket("/tmp/sock") {|s|
  p s                     #=> #<Socket:fd 3>
  p s.local_address       #=> # #<Addrinfo: /tmp/sock SOCK_STREAM>
}
END_OF_DOCUMENT_MARKER
unpack_sockaddr_in(sockaddr) → [port, ip_address] Show source
static VALUE
sock_s_unpack_sockaddr_in(VALUE self, VALUE addr)
{
    struct sockaddr_in * sockaddr;
    VALUE host;

    sockaddr = (struct sockaddr_in*)SockAddrStringValuePtr(addr);
    if (RSTRING_LEN(addr) <
        (char*)&((struct sockaddr *)sockaddr)->sa_family +
        sizeof(((struct sockaddr *)sockaddr)->sa_family) -
        (char*)sockaddr)
        rb_raise(rb_eArgError, "too short sockaddr");
    if (((struct sockaddr *)sockaddr)->sa_family != AF_INET
#ifdef INET6
        && ((struct sockaddr *)sockaddr)->sa_family != AF_INET6
#endif
        ) {
#ifdef INET6
        rb_raise(rb_eArgError, "not an AF_INET/AF_INET6 sockaddr");
#else
        rb_raise(rb_eArgError, "not an AF_INET sockaddr");
#endif
    }
    host = rsock_make_ipaddr((struct sockaddr*)sockaddr, RSTRING_SOCKLEN(addr));
    return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
}

Распаковывает sockaddr в порт и ip_address.

sockaddr должен быть строкой или addrinfo для AF_INET/AF_INET6.

sockaddr = Socket.sockaddr_in(80, "127.0.0.1")
p sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
p Socket.unpack_sockaddr_in(sockaddr) #=> [80, "127.0.0.1"]
unpack_sockaddr_un(sockaddr) → path Show source
static VALUE
sock_s_unpack_sockaddr_un(VALUE self, VALUE addr)
{
    struct sockaddr_un * sockaddr;
    VALUE path;

    sockaddr = (struct sockaddr_un*)SockAddrStringValuePtr(addr);
    if (RSTRING_LEN(addr) <
        (char*)&((struct sockaddr *)sockaddr)->sa_family +
        sizeof(((struct sockaddr *)sockaddr)->sa_family) -
        (char*)sockaddr)
        rb_raise(rb_eArgError, "too short sockaddr");
    if (((struct sockaddr *)sockaddr)->sa_family != AF_UNIX) {
        rb_raise(rb_eArgError, "not an AF_UNIX sockaddr");
    }
    if (sizeof(struct sockaddr_un) < (size_t)RSTRING_LEN(addr)) {
        rb_raise(rb_eTypeError, "too long sockaddr_un - %ld longer than %d",
                 RSTRING_LEN(addr), (int)sizeof(struct sockaddr_un));
    }
    path = rsock_unixpath_str(sockaddr, RSTRING_SOCKLEN(addr));
    return path;
}

Распаковывает sockaddr в путь.

sockaddr должен быть строкой или addrinfo для AF_UNIX.

sockaddr = Socket.sockaddr_un("/tmp/sock")
p Socket.unpack_sockaddr_un(sockaddr) #=> "/tmp/sock"

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

unix_socket_abstract_name?(path) Show source
# File ext/socket/lib/socket.rb, line 1137
def unix_socket_abstract_name?(path)
  /linux/ =~ RUBY_PLATFORM && /\A(\0|\z)/ =~ path
end

Публичные методы экземпляра

accept → [client_socket, client_addrinfo] Show source
static VALUE
sock_accept(VALUE server)
{
    union_sockaddr buffer;
    socklen_t length = (socklen_t)sizeof(buffer);

    VALUE peer = rsock_s_accept(rb_cSocket, server, &buffer.addr, &length);

    return rb_assoc_new(peer, rsock_io_socket_addrinfo(peer, &buffer.addr, length));
}

Принимает следующее соединение. Возвращает новый объект Socket и объект Addrinfo.

serv = Socket.new(:INET, :STREAM, 0)
serv.listen(5)
c = Socket.new(:INET, :STREAM, 0)
c.connect(serv.connect_address)
p serv.accept #=> [#<Socket:fd 6>, #<Addrinfo: 127.0.0.1:48555 TCP>]
accept_nonblock([options]) → [client_socket, client_addrinfo] Show source
# File ext/socket/lib/socket.rb, line 596
def accept_nonblock(exception: true)
  __accept_nonblock(exception)
end

Принимает входящее соединение, используя accept(2) после установки O_NONBLOCK для базового файлового дескриптора. Возвращает массив, содержащий принятый сокет для входящего соединения, client_socket, и Addrinfo, client_addrinfo.

Пример

# In one script, start this first
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(2200, 'localhost')
socket.bind(sockaddr)
socket.listen(5)
begin # emulate blocking accept
  client_socket, client_addrinfo = socket.accept_nonblock
rescue IO::WaitReadable, Errno::EINTR
  IO.select([socket])
  retry
end
puts "The client said, '#{client_socket.readline.chomp}'"
client_socket.puts "Hello from script one!"
socket.close

# In another script, start this second
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(2200, 'localhost')
socket.connect(sockaddr)
socket.puts "Hello from script 2."
puts "The server said, '#{socket.readline.chomp}'"
socket.close

Обратитесь к Socket#accept для получения информации об исключениях, которые могут быть выброшены, если вызов accept_nonblock завершится неудачей.

Socket#accept_nonblock может вызывать любые ошибки, соответствующие ошибке accept(2), включая Errno::EWOULDBLOCK.

Если исключение — Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED или Errno::EPROTO, оно расширяется с помощью IO::WaitReadable. Таким образом, IO::WaitReadable можно использовать для обработки исключений при повторной попытке accept_nonblock.

Указав именованный аргумент exception для false, можно указать, что accept_nonblock не должен вызывать исключение IO::WaitReadable, а вместо этого возвращать символ :wait_readable.

См. также

  • Socket#accept

bind(local_sockaddr) → 0 Show source
static VALUE
sock_bind(VALUE sock, VALUE addr)
{
    VALUE rai;
    rb_io_t *fptr;

    SockAddrStringValueWithAddrinfo(addr, rai);
    GetOpenFile(sock, fptr);
    if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr)) < 0)
        rsock_sys_fail_raddrinfo_or_sockaddr("bind(2)", addr, rai);

    return INT2FIX(0);
}

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

Параметр

  • local_sockaddr - struct sockaddr, содержащийся в строке или объекте Addrinfo

Пример

require 'socket'

# use Addrinfo
socket = Socket.new(:INET, :STREAM, 0)
socket.bind(Addrinfo.tcp("127.0.0.1", 2222))
p socket.local_address #=> #<Addrinfo: 127.0.0.1:2222 TCP>

# use struct sockaddr
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.bind( sockaddr )

Исключения в Unix-подобных системах

В Unix-подобных системах могут возникнуть следующие системные исключения, если вызов bind завершится неудачей:

  • Errno::EACCES - указанный sockaddr защищен, и текущий пользователь не имеет разрешения на привязку к нему

  • Errno::EADDRINUSE - указанный sockaddr уже используется

  • Errno::EADDRNOTAVAIL - указанный sockaddr недоступен с локальной машины

  • Errno::EAFNOSUPPORT - указанный sockaddr не является допустимым адресом для семейства вызывающего socket

  • Errno::EBADF - указанный sockaddr не является допустимым файловым дескриптором

  • Errno::EFAULT - к аргументу sockaddr невозможно получить доступ

  • Errno::EINVAL - socket уже привязан к адресу, и протокол не поддерживает привязку к новому sockaddr или socket был закрыт.

  • Errno::EINVAL - длина адреса не является допустимой длиной для семейства адресов

  • Errno::ENAMETOOLONG - длина разрешенного пути превысила PATH_MAX

  • Errno::ENOBUFS - нет доступного буферного пространства

  • Errno::ENOSR - не было достаточно ресурсов STREAMS для выполнения операции

  • Errno::ENOTSOCK - socket не ссылается на сокет

  • Errno::EOPNOTSUPP - тип сокета socket не поддерживает привязку к адресу

В Unix-подобных системах, если семейство адресов вызывающего socket является Socket::AF_UNIX, могут возникнуть следующие исключения, если вызов bind завершится неудачей:

  • Errno::EACCES - запрещен доступ на чтение для компонента префиксного пути или запрещен доступ на запись к socket

  • Errno::EDESTADDRREQ - аргумент sockaddr является нулевым указателем

  • Errno::EISDIR - то же, что и Errno::EDESTADDRREQ

  • Errno::EIO - произошла ошибка ввода-вывода

  • Errno::ELOOP - при преобразовании имени пути в sockaddr было обнаружено слишком много символических ссылок

  • Errno::ENAMETOOLLONG - компонент имени пути превысил NAME_MAX символов, или весь путь превысил PATH_MAX символов

  • Errno::ENOENT - компонент имени пути не обозначает существующий файл, или имя пути является пустой строкой

  • Errno::ENOTDIR - компонент префиксного пути в имени пути в sockaddr не является каталогом

  • Errno::EROFS - имя будет находиться в файловой системе только для чтения

Исключения в Windows

В системах Windows могут возникнуть следующие системные исключения, если вызов bind завершится неудачей:

  • Errno::ENETDOWN– сеть не работает

  • Errno::EACCES - попытка подключения сокета дейтаграммы к широковещательному адресу не удалась

  • Errno::EADDRINUSE - локальный адрес сокета уже используется

  • Errno::EADDRNOTAVAIL - указанный адрес не является допустимым адресом для этого компьютера

  • Errno::EFAULT - внутренний адрес сокета или параметр длины адреса слишком мал или не является допустимой частью адресуемого пространства пользователя

  • Errno::EINVAL - socket уже привязан к адресу

  • Errno::ENOBUFS - нет доступного буферного пространства

  • Errno::ENOTSOCK - аргумент socket не ссылается на сокет

См. также

  • Страницы руководства bind в Unix-подобных системах

  • Функция bind в справочнике функций Winsock от Microsoft

connect(remote_sockaddr) → 0 Показать исходный код
static VALUE
sock_connect(VALUE sock, VALUE addr)
{
    VALUE rai;
    rb_io_t *fptr;
    int fd, n;

    SockAddrStringValueWithAddrinfo(addr, rai);
    addr = rb_str_new4(addr);
    GetOpenFile(sock, fptr);
    fd = fptr->fd;
    n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), 0, NULL);
    if (n < 0) {
        rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
    }

    return INT2FIX(n);
}

Запрашивает установление соединения с заданным remote_sockaddr. Возвращает 0, если успешно, иначе генерирует исключение.

Параметр

  • remote_sockaddr - адрес struct sockaddr, содержащийся в строке или Addrinfo объекте

Пример:

# Pull down Google's web page
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 80, 'www.google.com' )
socket.connect( sockaddr )
socket.write( "GET / HTTP/1.0\r\n\r\n" )
results = socket.read

Исключения на системах Unix

На системах Unix при неудачном выполнении вызова connect могут быть сгенерированы следующие системные исключения:

  • Errno::EACCES - запрещён доступ к компоненту префиксного пути или запрещён доступ на запись к socket

  • Errno::EADDRINUSE - struct sockaddr уже используется

  • Errno::EADDRNOTAVAIL - указанный struct sockaddr недоступен с локального компьютера

  • Errno::EAFNOSUPPORT - указанный struct sockaddr не является допустимым адресом для семейства адресов указанного socket

  • Errno::EALREADY - для указанного сокета уже идёт процесс подключения

  • Errno::EBADF - socket не является допустимым дескриптором файла

  • Errno::ECONNREFUSED - целевой struct sockaddr не принимает подключения, отклонено запрошенный запрос соединения

  • Errno::ECONNRESET - удалённый хост прервал запрос подключения

  • Errno::EFAULT - к struct sockaddr невозможно получить доступ

  • Errno::EHOSTUNREACH - целевой хост недоступен (вероятно, потому что хост отключён или удалённый маршрутизатор не может его достичь)

  • Errno::EINPROGRESS - для socket установлено O_NONBLOCK, и соединение не может быть установлено немедленно; подключение будет установлено асинхронно

  • Errno::EINTR - попытка установить соединение была прервана доставкой сигнала, который был перехвачен; соединение будет установлено асинхронно

  • Errno::EISCONN - указанный socket уже подключен

  • Errno::EINVAL - длина адреса, используемая для struct sockaddr, не является допустимой длиной для семейства адресов, или в struct sockaddr указано недопустимое семейство

  • Errno::ENAMETOOLONG - длина разрешённого пути превысила PATH_MAX

  • Errno::ENETDOWN - локальный интерфейс, используемый для достижения назначения, отключён

  • Errno::ENETUNREACH - маршрут к сети отсутствует

  • Errno::ENOBUFS - нет доступного буферного пространства

  • Errno::ENOSR - не хватает ресурсов STREAMS для завершения операции

  • Errno::ENOTSOCK - аргумент socket не относится к сокету

  • Errno::EOPNOTSUPP - вызывающий socket прослушивает и не может быть подключён

  • Errno::EPROTOTYPE - struct sockaddr имеет другой тип, чем сокет, привязанный к указанному адресу удалённого узла

  • Errno::ETIMEDOUT - попытка подключения закончилась по истечении времени ожидания до установления соединения.

На системах Unix, если семейство адресов вызывающего socket является AF_UNIX, при неудачном вызове connect могут быть сгенерированы следующие исключения:

  • Errno::EIO - произошла ошибка ввода-вывода при чтении или записи в файловую систему

  • Errno::ELOOP - при преобразовании пути в struct sockaddr было встречено слишком много символьных ссылок

  • Errno::ENAMETOOLLONG - компонент пути превысил NAME_MAX символов или весь путь превысил PATH_MAX символов

  • Errno::ENOENT - компонент пути не указывает на существующий файл или путь пустой

  • Errno::ENOTDIR - компонент префиксного пути пути в struct sockaddr не является каталогом

Исключения Windows

На системах Windows при неудачном вызове connect могут быть сгенерированы следующие системные исключения:

  • Errno::ENETDOWN - сеть отключена

  • Errno::EADDRINUSE - локальный адрес сокета уже используется

  • Errno::EINTR - сокет был отменён

  • Errno::EINPROGRESS - происходит блокирующий сокет или поставщик сервиса ещё обрабатывает функцию обратного вызова. Или происходит блокирующий вызов connect для socket.

  • Errno::EALREADY - см. Errno::EINVAL

  • Errno::EADDRNOTAVAIL - удалённый адрес не является допустимым, например, ADDR_ANY TODO проверить ADDRANY TO INADDR_ANY

  • Errno::EAFNOSUPPORT - адреса в указанном семействе не могут использоваться с этим socket

  • Errno::ECONNREFUSED - целевой struct sockaddr не принимает подключения, отклонено запрошенный запрос соединения

  • Errno::EFAULT - внутренний адрес сокета или параметр длины адреса слишком короткий или не является валидной частью адресного пространства пользователя

  • Errno::EINVAL - socket является сокетом прослушивания

  • Errno::EISCONN - socket уже подключён

  • Errno::ENETUNREACH - сеть не может быть достигнута с этого хоста в данный момент

  • Errno::EHOSTUNREACH - маршрут к сети отсутствует

  • Errno::ENOBUFS - нет доступного буферного пространства

  • Errno::ENOTSOCK - аргумент socket не относится к сокету

  • Errno::ETIMEDOUT - попытка подключения закончилась по истечении времени ожидания до установления соединения.

  • Errno::EWOULDBLOCK - сокет помечен как неблокирующий, и подключение не может быть выполнено немедленно

  • Errno::EACCES - попытка подключить сокет датаграмм к широковещательному адресу не удалась

См. также

  • Справочные страницы connect на системах Unix

  • Функция connect в справочнике функций Winsock от Microsoft

connect_nonblock(remote_sockaddr, [options]) → 0 Показать исходный код
# File ext/socket/lib/socket.rb, line 1216
def connect_nonblock(addr, exception: true)
  __connect_nonblock(addr, exception)
end

Запрашивает установление соединения с заданным remote_sockaddr после установки O_NONBLOCK для базового дескриптора файла. Возвращает 0, если успешно, иначе генерирует исключение.

Параметр

# +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object

Пример:

# Pull down Google's web page
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(80, 'www.google.com')
begin # emulate blocking connect
  socket.connect_nonblock(sockaddr)
rescue IO::WaitWritable
  IO.select(nil, [socket]) # wait 3-way handshake completion
  begin
    socket.connect_nonblock(sockaddr) # check connection failure
  rescue Errno::EISCONN
  end
end
socket.write("GET / HTTP/1.0\r\n\r\n")
results = socket.read

См. Socket#connect для исключений, которые могут быть сгенерированы при неудачном вызове connect_nonblock.

Socket#connect_nonblock может генерировать любую ошибку, соответствующую ошибке connect(2), включая Errno::EINPROGRESS.

Если исключение Errno::EINPROGRESS, оно дополняется IO::WaitWritable. Поэтому IO::WaitWritable можно использовать для перехвата исключений для повторной попытки connect_nonblock.

Указав ключевой аргумент exception для false, можно указать, что connect_nonblock не должен генерировать исключение IO::WaitWritable, а вместо этого возвращает символ :wait_writable.

См. также

# Socket#connect
ipv6only!() Показать исходный код
# File ext/socket/lib/socket.rb, line 467
def ipv6only!
  if defined? Socket::IPV6_V6ONLY
    self.setsockopt(:IPV6, :V6ONLY, 1)
  end
end

Включает опцию сокета IPV6_V6ONLY, если IPV6_V6ONLY доступна.

listen( int ) → 0 Показать исходный код
VALUE
rsock_sock_listen(VALUE sock, VALUE log)
{
    rb_io_t *fptr;
    int backlog;

    backlog = NUM2INT(log);
    GetOpenFile(sock, fptr);
    if (listen(fptr->fd, backlog) < 0)
        rb_sys_fail("listen(2)");

    return INT2FIX(0);
}

Прослушивает подключения, используя указанный int в качестве очереди ожидающих подключений. Вызов listen применяется только если socket имеет тип SOCK_STREAM или SOCK_SEQPACKET.

Параметр

  • backlog - максимальная длина очереди ожидающих подключений.

Пример 1

require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.bind( sockaddr )
socket.listen( 5 )

Пример 2 (прослушивание на произвольном порту, только для систем на основе Unix):

require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
socket.listen( 1 )

Исключения для систем на основе Unix

В системах на основе Unix вышеуказанный код будет работать, так как создается новый sockaddr-структура по адресу ADDR_ANY для произвольного номера порта, переданного ядром. Это не сработает в Windows, так как Windows требует, чтобы socket был привязан с помощью вызова bind перед использованием listen.

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

В системах на основе Unix при неудачном выполнении вызова listen могут быть подняты следующие системные исключения:

  • Errno::EBADF - аргумент socket не является допустимым дескриптором файла

  • Errno::EDESTADDRREQ - socket не привязан к локальному адресу, а протокол не поддерживает прослушивание на не привязанном сокете

  • Errno::EINVAL - socket уже подключен

  • Errno::ENOTSOCK - аргумент socket не относится к сокету

  • Errno::EOPNOTSUPP - протокол socket не поддерживает прослушивание

  • Errno::EACCES - у вызывающего процесса нет соответствующих привилегий

  • Errno::EINVAL - socket закрыт

  • Errno::ENOBUFS - недостаточно ресурсов в системе для выполнения вызова

Исключения для систем Windows

В системах Windows при неудачном выполнении вызова listen могут быть подняты следующие системные исключения:

  • Errno::ENETDOWN - сеть не активна

  • Errno::EADDRINUSE - локальный адрес сокета уже используется. Это обычно происходит во время выполнения bind, но может быть отложено, если вызов bind был к частично подставленному адресу (включающему ADDR_ANY), и если конкретный адрес должен быть определен в момент вызова listen

  • Errno::EINPROGRESS - выполняется вызов Windows Sockets 1.1 или поставщик сервисов ещё обрабатывает функцию обратного вызова

  • Errno::EINVAL - socket не был привязан с помощью вызова bind.

  • Errno::EISCONN - socket уже подключен

  • Errno::EMFILE - больше нет доступных дескрипторов сокета

  • Errno::ENOBUFS - нет доступного буферного пространства

  • Errno::ENOTSOC - socket не является сокетом

  • Errno::EOPNOTSUPP - ссылка на socket не является типом, который поддерживает метод listen

См. также

  • Страницы руководства listen в системах на основе Unix

  • Функция listen в справочнике функций Microsoft Winsock

recvfrom(maxlen) → [mesg, sender_addrinfo] Показать исходный код
recvfrom(maxlen, flags) → [mesg, sender_addrinfo]
static VALUE
sock_recvfrom(int argc, VALUE *argv, VALUE sock)
{
    return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
}

Получает до maxlen байтов из socket. flags — ноль или более опций MSG_. Первый элемент результата, mesg, — полученные данные. Второй элемент, sender_addrinfo, содержит адресно-специфическую информацию отправителя.

Параметры

  • maxlen - максимальное количество байтов для получения от сокета

  • flags - ноль или более опций MSG_

Пример

# In one file, start this first
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.bind( sockaddr )
socket.listen( 5 )
client, client_addrinfo = socket.accept
data = client.recvfrom( 20 )[0].chomp
puts "I only received 20 bytes '#{data}'"
sleep 1
socket.close

# In another file, start this second
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.connect( sockaddr )
socket.puts "Watch this get cut short!"
socket.close

Исключения для систем на базе Unix

В системах на базе Unix при неудачном выполнении вызова recvfrom могут быть подняты следующие системные исключения:

  • Errno::EAGAIN - дескриптор файла socket отмечен как O_NONBLOCK и данные для получения не ожидаются; или флаг MSG_OOB установлен, но внеочередных данных нет, и либо дескриптор файла socket отмечен как O_NONBLOCK, либо дескриптор socket не поддерживает блокирование для ожидания внеочередных данных

  • Errno::EWOULDBLOCK - см. Errno::EAGAIN

  • Errno::EBADF - socket не является допустимым дескриптором файла

  • Errno::ECONNRESET - соединение было принудительно закрыто удалённой стороной

  • Errno::EFAULT - доступ к внутреннему буферу, адресу или длине адреса сокета или запись в них невозможны

  • Errno::EINTR - сигнал прервал recvfrom, прежде чем данные стали доступны

  • Errno::EINVAL - флаг MSG_OOB установлен, но внеочередных данных нет

  • Errno::EIO - произошла ошибка ввода-вывода при чтении или записи в файловую систему

  • Errno::ENOBUFS - недостаточно ресурсов в системе для выполнения операции

  • Errno::ENOMEM - недостаточно памяти для выполнения запроса

  • Errno::ENOSR - недостаточно ресурсов STREAMS для завершения операции

  • Errno::ENOTCONN - попытка приема на сокете режима соединения, который не подключен

  • Errno::ENOTSOCK - socket не ссылается на сокет

  • Errno::EOPNOTSUPP - указанные флаги не поддерживаются для этого типа сокета

  • Errno::ETIMEDOUT - соединение истекло во время установления соединения или из-за таймаута передачи на активном соединении

Исключения для систем Windows

В системах Windows при неудачном выполнении вызова recvfrom могут быть подняты следующие системные исключения:

  • Errno::ENETDOWN - сеть не активна

  • Errno::EFAULT - внутренний буфер и параметры from в socket не находятся в адресном пространстве пользователя или внутренний параметр fromlen слишком мал, чтобы вместить адрес удалённой стороны

  • Errno::EINTR - (блокирующий) вызов был отменён внутренним вызовом функции WinSock WSACancelBlockingCall

  • Errno::EINPROGRESS - в процессе блокирующий вызов Windows Sockets 1.1 или поставщик сервисов всё ещё обрабатывает функцию обратного вызова

  • Errno::EINVAL - socket не был привязан вызовом bind, или был указан неизвестный флаг, или MSG_OOB был указан для сокета с SO_OOBINLINE включённым, или (только для сокетов типа потоков байтов) внутренний параметр len в socket был нулевым или отрицательным

  • Errno::EISCONN - socket уже подключен. Вызов recvfrom не разрешён для подключенного сокета в сокете, который ориентирован на соединение или нет.

  • Errno::ENETRESET - соединение было прервано из-за активности keep-alive, обнаружившей сбой во время выполнения операции.

  • Errno::EOPNOTSUPP - MSG_OOB был указан, но socket не является потоковым, например, типа SOCK_STREAM. Данные OOB не поддерживаются в области связи, связанной с socket, или socket однонаправленный и поддерживает только операции отправки

  • Errno::ESHUTDOWN - socket закрыт. Невозможно вызвать recvfrom на сокете после вызова shutdown.

  • Errno::EWOULDBLOCK - socket помечен как неблокирующий, и вызов recvfrom заблокирует выполнение.

  • Errno::EMSGSIZE - сообщение было слишком большим для указанного буфера и было усечено.

  • Errno::ETIMEDOUT - соединение было разорвано из-за сбоя сети или из-за того, что система на другом конце отключилась без предупреждения

  • Errno::ECONNRESET - виртуальный канал был сброшен удаленной стороной при выполнении жёсткого или аварийного закрытия. Приложение должно закрыть сокет; он больше не пригоден для использования. В сокете UDP-датаграммы эта ошибка указывает, что предыдущая операция отправки привела к сообщению ICMP Port Unreachable.

recvfrom_nonblock(maxlen[, flags[, outbuf[, opts]]]) → [mesg, sender_addrinfo] Показать исходный код
# File ext/socket/lib/socket.rb, line 539
def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
  __recvfrom_nonblock(len, flag, str, exception)
end

Принимает до maxlen байтов данных от socket с помощью recvfrom(2) после установки O_NONBLOCK для базового дескриптора файла. flags равно нулю или большему числу MSG_ опций. Первый элемент результата, mesg, — это полученные данные. Второй элемент, sender_addrinfo, содержит информацию о протокольном адресе отправителя.

Когда recvfrom(2) возвращает 0, Socket#recvfrom_nonblock возвращает пустую строку в качестве данных. Значение зависит от сокета: EOF для TCP, пустой пакет для UDP и т. д.

Параметры

  • maxlen - максимальное количество байтов для приема с сокета

  • flags - ноль или более MSG_ опций

  • outbuf - буфер назначения String

  • opts - словарь ключевых слов, поддерживающий ‘exception: false`

Пример

# In one file, start this first
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(2200, 'localhost')
socket.bind(sockaddr)
socket.listen(5)
client, client_addrinfo = socket.accept
begin # emulate blocking recvfrom
  pair = client.recvfrom_nonblock(20)
rescue IO::WaitReadable
  IO.select([client])
  retry
end
data = pair[0].chomp
puts "I only received 20 bytes '#{data}'"
sleep 1
socket.close

# In another file, start this second
require 'socket'
include Socket::Constants
socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(2200, 'localhost')
socket.connect(sockaddr)
socket.puts "Watch this get cut short!"
socket.close

Обратитесь к Socket#recvfrom для получения исключений, которые могут быть выброшены, если вызов recvfrom_nonblock завершился неудачно.

Socket#recvfrom_nonblock может вызывать любые ошибки, соответствующие ошибкам recvfrom(2), включая Errno::EWOULDBLOCK.

Если исключение Errno::EWOULDBLOCK или Errno::EAGAIN, оно дополняется IO::WaitReadable. Поэтому IO::WaitReadable можно использовать для обработки исключений для повторного вызова recvfrom_nonblock.

Указав ключевое слово exception в false, можно указать, что recvfrom_nonblock не должен вызывать исключение IO::WaitReadable, а вместо этого вернуть символ :wait_readable.

См. также

  • Socket#recvfrom

sysaccept → [client_socket_fd, client_addrinfo] Показать исходный код
static VALUE
sock_sysaccept(VALUE server)
{
    union_sockaddr buffer;
    socklen_t length = (socklen_t)sizeof(buffer);

    VALUE peer = rsock_s_accept(0, server, &buffer.addr, &length);

    return rb_assoc_new(peer, rsock_io_socket_addrinfo(peer, &buffer.addr, length));
}

Принимает входящее подключение, возвращая массив, содержащий (целый) дескриптор файла входящего подключения, client_socket_fd, и Addrinfo, client_addrinfo.

Пример

# In one script, start this first
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.bind( sockaddr )
socket.listen( 5 )
client_fd, client_addrinfo = socket.sysaccept
client_socket = Socket.for_fd( client_fd )
puts "The client said, '#{client_socket.readline.chomp}'"
client_socket.puts "Hello from script one!"
socket.close

# In another script, start this second
require 'socket'
include Socket::Constants
socket = Socket.new( AF_INET, SOCK_STREAM, 0 )
sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' )
socket.connect( sockaddr )
socket.puts "Hello from script 2."
puts "The server said, '#{socket.readline.chomp}'"
socket.close

Обратитесь к Socket#accept для получения исключений, которые могут быть выброшены, если вызов sysaccept завершился неудачно.

См. также

  • Socket#accept

Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API