Spec-Zone.ru › Ruby 2.2

класс Socket

Родитель:
BasicSocket

Класс 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:

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

Обработка исключений

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

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

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

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

::tcp, IO.open

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

::tcp_server_loop, IO.open

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

::unix, IO.open

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

::unix_server_loop, IO.open

Документация составлена

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

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

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

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

Константы

AF_APPLETALK

Протокол AppleTalk

AF_ATM

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

AF_AX25

Протокол AX.25

AF_CCITT

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

AF_CHAOS

Протоколы MIT CHAOS

AF_CNT

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

AF_COIP

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

AF_DATAKIT

Протокол Datakit

AF_DEC

Протокол DECnet

AF_DLI

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

AF_E164

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

AF_ECMA

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

AF_HYLINK

Протокол NSC Hyperchannel

AF_IMPLINK

Протокол ARPANET IMP

AF_INET

Протокол IPv4

AF_INET6

Протокол IPv6

AF_IPX

Протокол IPX

AF_ISDN

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

AF_ISO

Протоколы ISO Модель взаимодействия открытых систем

AF_LAT

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

AF_LINK

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

AF_LOCAL

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

AF_MAX

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

AF_NATM

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

AF_NDRV

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

AF_NETBIOS

NetBIOS

AF_NETGRAPH

Сокеты Netgraph

AF_NS

Протоколы XEROX NS

AF_OSI

Протоколы ISO Модель взаимодействия открытых систем

AF_PACKET

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

AF_PPP

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

AF_PUP

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

AF_ROUTE

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

AF_SIP

Простой протокол Интернет

AF_SNA

Протокол IBM SNA

AF_SYSTEM
AF_UNIX

Сокеты UNIX

AF_UNSPEC

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

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

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

EAI_SYSTEM

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

IFF_802_1Q_VLAN

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

IFF_ALLMULTI

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

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

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

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

Поддерживает multicast

IFF_NOARP

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

IFF_NOTRAILERS

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

IFF_OACTIVE

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

IFF_OVS_DATAPATH

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

IFF_POINTOPOINT

Точечно-точечное соединение

IFF_PORTSEL

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

IFF_PPROMISC

Запрошенный пользователем режим promisc

IFF_PROMISC

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

IFF_RENAMING

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

IFF_ROUTE

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

IFF_RUNNING

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

IFF_SIMPLEX

Не слышит собственные передачи

IFF_SLAVE

Раб балансировки нагрузки

IFF_SLAVE_INACTIVE

Раб консолидации не является текущим активным

IFF_SLAVE_NEEDARP

Необходимы ARPs для проверки

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

END_OF_DOCUMENT_MARKER
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

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

IPPROTO_UDP

UDP

IPPROTO_XTP

Протокол транспортной связи Xpress

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

Максимальный размер блока (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

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

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

Данные завершают соединение

MSG_EOR

Данные завершают запись

MSG_ERRQUEUE

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

MSG_FASTOPEN

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

MSG_FIN
MSG_FLUSH

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

MSG_HAVEMORE

Данные готовы к чтению

MSG_HOLD

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

MSG_MORE

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

MSG_NOSIGNAL

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

MSG_OOB

Обработать данные вне полосы

MSG_PEEK

Просмотреть входящее сообщение

MSG_PROXY

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

MSG_RCVMORE

Данные остаются в текущем пакете

MSG_RST
MSG_SEND

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

MSG_SYN
MSG_TRUNC

Данные отброшены до доставки

MSG_WAITALL

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

NI_DGRAM

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

NI_MAXHOST

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

NI_MAXSERV

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

END_OF_DOCUMENT_MARKER
NI_NAMEREQD

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

NI_NOFQDN

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

NI_NUMERICHOST

Возвратить числовой адрес

NI_NUMERICSERV

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

PF_APPLETALK

Протокол AppleTalk

PF_ATM

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

PF_AX25

Протокол AX.25

PF_CCITT

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

PF_CHAOS

Протоколы MIT CHAOS

PF_CNT

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

PF_COIP

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

PF_DATAKIT

Протокол Datakit

PF_DEC

Протокол DECnet

PF_DLI

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

PF_ECMA

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

PF_HYLINK

Протокол NSC Hyperchannel

PF_IMPLINK

Протокол ARPANET IMP

PF_INET

Протокол IPv4

PF_INET6

Протокол IPv6

PF_IPX

Протокол IPX

PF_ISDN

Цифровая сеть с интеграцией служб

PF_ISO

Протоколы ISO OSI

PF_KEY
PF_LAT

Протокол локального транспорта

PF_LINK

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

PF_LOCAL

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

PF_MAX

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

PF_NATM

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

PF_NDRV

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

PF_NETBIOS

NetBIOS

PF_NETGRAPH

Сокеты Netgraph

PF_NS

Протоколы XEROX NS

PF_OSI

Протоколы ISO OSI

PF_PACKET

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

PF_PIP
PF_PPP

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

PF_PUP

Протокол PARC Universal Packet

PF_ROUTE

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

PF_RTIP
PF_SIP

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

PF_SNA

Протокол IBM SNA

PF_SYSTEM
PF_UNIX

Сокеты UNIX

PF_UNSPEC

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

PF_XTP

Протокол быстрой передачи данных

SCM_BINTIME

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

SCM_CREDENTIALS

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

SCM_CREDS

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

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_DGRAM

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

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

Для сокета был вызван 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

Установить порог в микросекундах для опроса с низкой задержкой (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_KEEPALIVE

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

SO_LINGER

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

SO_LOCK_FILTER

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

SO_MAC_EXEMPT

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

SO_MARK

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

SO_MAX_PACING_RATE

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

SO_NKE

Установить расширение ядра сети на уровне сокета

SO_NOFCS

Установить 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

Установить смещение для 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_RXQ_OVFL

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

SO_SECURITY_AUTHENTICATION
SO_SECURITY_ENCRYPTION_NETWORK
SO_SECURITY_ENCRYPTION_TRANSPORT
SO_SELECT_ERR_QUEUE

Разрешить select() обнаруживать очередь ошибок сокета с errorfds (Linux 3.10)

SO_SNDBUF

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

SO_SNDBUFFORCE

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

SO_SNDLOWAT

Пороговое значение буфера отправки

SO_SNDTIMEO

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

SO_TIMESTAMP

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

SO_TIMESTAMPING

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

SO_TIMESTAMPNS

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

SO_TYPE

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

SO_USELOOPBACK

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

SO_WANTMORE

Указать, что больше данных готово

SO_WANTOOBFLAG

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

SO_WIFI_STATUS

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

TCP_CONGESTION

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

TCP_COOKIE_TRANSACTIONS

Транзакции TCP Cookie (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_KEEPCNT

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

TCP_KEEPIDLE

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

TCP_KEEPINTVL

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

TCP_LINGER2

Срок жизни осиротевших сокетов FIN_WAIT2 (Linux 2.4, glibc 2.2)

TCP_MAXSEG

Установить максимальный размер сегмента

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

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

TCP_THIN_LINEAR_TIMEOUTS

Линейные таймауты для thin-потоков (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 496
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|
      begin
        sock, addr = r.accept_nonblock
      rescue IO::WaitReadable
        next
      end
      yield sock, addr
    }
  }
end

Выполняет итерацию по принятым соединениям через заданные сокеты, передавая сокет и адрес клиента в блок.

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

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

getaddrinfo(nodename, servname[, family[, socktype[, protocol[, flags[, reverse_lookup]]]]]) → массив Показать исходный код
static VALUE
sock_s_getaddrinfo(int argc, VALUE *argv)
{
    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.

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

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 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 addr, family;
    struct hostent *h;
    char **pch;
    VALUE ary, names;
    int t = AF_INET;

    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;
}

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

p Socket.gethostbyaddr([221,186,184,68].pack("CCCC"))
#=> ["carbon.ruby-lang.org", [], 2, "\xDD\xBA\xB8D"]
gethostbyname(hostname) → [official_hostname, alias_hostnames, address_family, *address_list] Показать исходный код
static VALUE
sock_s_gethostbyname(VALUE obj, VALUE host)
{
    rb_secure(3);
    return rsock_make_hostent(host, rsock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr);
}

Получает информацию о хосте для 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;

    rb_secure(3);
    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-адрес, используйте ::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 sa, af = Qnil, host = Qnil, port = Qnil, flags, tmp;
    char *hptr, *pptr;
    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_PTR(sa)[0];
            port = RARRAY_PTR(sa)[1];
            host = RARRAY_PTR(sa)[2];
        }
        else if (RARRAY_LEN(sa) >= 4) {
            af = RARRAY_PTR(sa)[0];
            port = RARRAY_PTR(sa)[1];
            host = RARRAY_PTR(sa)[3];
            if (NIL_P(host)) {
                host = RARRAY_PTR(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));
        }
        /* host */
        if (NIL_P(host)) {
            hptr = NULL;
        }
        else {
            strncpy(hbuf, StringValuePtr(host), sizeof(hbuf));
            hbuf[sizeof(hbuf) - 1] = '\0';
            hptr = hbuf;
        }
        /* port */
        if (NIL_P(port)) {
            strcpy(pbuf, "0");
            pptr = NULL;
        }
        else if (FIXNUM_P(port)) {
            snprintf(pbuf, sizeof(pbuf), "%ld", NUM2LONG(port));
            pptr = pbuf;
        }
        else {
            strncpy(pbuf, StringValuePtr(port), sizeof(pbuf));
            pbuf[sizeof(pbuf) - 1] = '\0';
            pptr = pbuf;
        }
        hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
        /* af */
        hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
        error = rb_getaddrinfo(hptr, pptr, &hints, &res);
        if (error) goto error_exit_addr;
        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_addr:
    saved_errno = errno;
    if (res) rb_freeaddrinfo(res);
    errno = saved_errno;
    rsock_raise_socket_error("getaddrinfo", error);

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

    UNREACHABLE;
}

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

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

  • Строка sockaddr в упакованном формате, например ::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) → номер_порта Показать исходный код
getservbyname(service_name, protocol_name) → номер_порта
static VALUE
sock_s_getservbyname(int argc, VALUE *argv)
{
    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 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_tainted_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 → массив Показать исходный код
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) && !defined(__hpux)
    /* Solaris if_tcp(7P) */
    /* HP-UX has SIOCGLIFCONF too.  But it uses different struct */
    int fd = -1;
    int ret;
    struct lifnum ln;
    struct lifconf lc;
    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_sys_fail(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_sys_fail(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]) → сокет Показать исходный код
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);

    rb_secure(3);
    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
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, 0, 0);
    VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);

    rb_freeaddrinfo(res);
    OBJ_INFECT(addr, port);
    OBJ_INFECT(addr, host);

    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"
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));
    OBJ_INFECT(addr, path);

    return addr;
}

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

Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
pair(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"
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, 0, 0);
    VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);

    rb_freeaddrinfo(res);
    OBJ_INFECT(addr, port);
    OBJ_INFECT(addr, host);

    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 Показать исходный код
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));
    OBJ_INFECT(addr, path);

    return addr;
}

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

Socket.sockaddr_un("/tmp/sock") #=> "\x01\x00/tmp/sock\x00\x00..."
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| ... } Show source
tcp(host, port, local_host=nil, local_port=nil, [opts])
# File ext/socket/lib/socket.rb, line 314
def self.tcp(host, port, *rest) # :yield: socket
  opts = Hash === rest.last ? rest.pop : {}
  raise ArgumentError, "wrong number of arguments (#{rest.length} for 2)" if 2 < rest.length
  local_host, local_port = rest
  last_error = nil
  ret = nil

  connect_timeout = opts[:connect_timeout]

  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) {|ai|
    if local_addr_list
      local_addr = local_addr_list.find {|local_ai| local_ai.afamily == ai.afamily }
      next if !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
  }
  if !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 if !ret.closed?
    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| ... } Show source
# File ext/socket/lib/socket.rb, line 555
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 и вызывает блок для каждого принятого соединения. Блок вызывается с сокетом и client_address в виде объекта Addrinfo.

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

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

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

Обратите внимание, что Addrinfo.getaddrinfo используется для определения адресов сокета сервера. Когда Addrinfo.getaddrinfo возвращает два или более адреса, например, IPv4 и IPv6, используются все они. ::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| ... } Show source
# File ext/socket/lib/socket.rb, line 452
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 {|s| s.close }
      raise
    end
  end
  if block_given?
    begin
      yield sockets
    ensure
      sockets.each {|s| s.close if !s.closed? }
    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| ... } Show source
udp_server_loop(host, port) {|msg, msg_src| ... }
# File ext/socket/lib/socket.rb, line 727
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| ... } Show source
# File ext/socket/lib/socket.rb, line 700
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-сервера на указанных сокетах.

Возвращаемое значение ::udp_server_sockets подходит для аргумента.

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

udp_server_recv(sockets) {|msg, msg_src| ... } Show source
# File ext/socket/lib/socket.rb, line 670
def self.udp_server_recv(sockets)
  sockets.each {|r|
    begin
      msg, sender_addrinfo, _, *controls = r.recvmsg_nonblock
    rescue IO::WaitReadable
      next
    end
    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, который используется для ответа.

::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) Show source
# File ext/socket/lib/socket.rb, line 583
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 if !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 if !a.ipv6?
        ip_list << Addrinfo.new(a.to_sockaddr, :INET6, :DGRAM, 0);
      }
    else
      ip_list << ai
    end
  }

  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 {|s| s.close if !s.closed? } 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| ... } Show source
# File ext/socket/lib/socket.rb, line 777
def self.unix(path) # :yield: socket
  addr = Addrinfo.unix(path)
  sock = addr.connect
  if block_given?
    begin
      yield sock
    ensure
      sock.close if !sock.closed?
    end
  else
    sock
  end
end

создает новый сокет, подключенный к path, используя сокет 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| ... } Show source
# File ext/socket/lib/socket.rb, line 864
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 имеет липкий бит.

# 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| ... } Show source
# File ext/socket/lib/socket.rb, line 807
def self.unix_server_socket(path)
  if !unix_socket_abstract_name?(path)
    begin
      st = File.lstat(path)
    rescue Errno::ENOENT
    end
    if st && st.socket? && st.owned?
      File.unlink path
    end
  end
  s = Addrinfo.unix(path).listen
  if block_given?
    begin
      yield s
    ensure
      s.close if !s.closed?
      if !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>
}
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));
    OBJ_INFECT(host, addr);
    return rb_assoc_new(INT2NUM(ntohs(sockaddr->sin_port)), host);
}

Распаковывает sockaddr в port и 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));
    OBJ_INFECT(path, addr);
    return path;
}

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

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 835
def unix_socket_abstract_name?(path)
  /linux/ =~ RUBY_PLATFORM && /\A(\0|\z)/ =~ path
end

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

accept → [client_socket, client_addrinfo] Показать исходный код
static VALUE
sock_accept(VALUE sock)
{
    rb_io_t *fptr;
    VALUE sock2;
    union_sockaddr buf;
    socklen_t len = (socklen_t)sizeof buf;

    GetOpenFile(sock, fptr);
    sock2 = rsock_s_accept(rb_cSocket,fptr->fd,&buf.addr,&len);

    return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
}

Принимает следующее подключение. Возвращает новый объект 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 → [client_socket, client_addrinfo] Показать исходный код
static VALUE
sock_accept_nonblock(VALUE sock)
{
    rb_io_t *fptr;
    VALUE sock2;
    union_sockaddr buf;
    socklen_t len = (socklen_t)sizeof buf;

    GetOpenFile(sock, fptr);
    sock2 = rsock_s_accept_nonblock(rb_cSocket, fptr, &buf.addr, &len);
    return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
}

Принимает входящее подключение с помощью 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

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

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

Если исключение равно Errno::EWOULDBLOCK, Errno::AGAIN, Errno::ECONNABORTED или Errno::EPROTO, оно дополняется IO::WaitReadable. Поэтому IO::WaitReadable можно использовать для перехвата исключений для повторной попытки accept_nonblock.

См. также

  • #accept

bind(local_sockaddr) → 0 Показать исходный код
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 - the 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 - сокет уже привязан к адресу, и протокол не поддерживает привязку к новому sockaddr или сокет был закрыт.

  • 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 имеет значение null

  • 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 - сокет уже привязан к адресу

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

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

См. также

  • Справочные страницы bind для систем на основе Unix

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

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);
    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 — sockaddr уже используется

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Errno::ENETUNREACH — нет маршрута к сети

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Errno::ECONNREFUSED — целевой 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 Майкрософт

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

    SockAddrStringValueWithAddrinfo(addr, rai);
    addr = rb_str_new4(addr);
    GetOpenFile(sock, fptr);
    rb_io_set_nonblock(fptr);
    n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr));
    if (n < 0) {
        if (errno == EINPROGRESS)
            rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "connect(2) would block");
        rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
    }

    return INT2FIX(n);
}

Запрашивает подключение к указанному remote_sockaddr после установки флага O_NONBLOCK для базового дескриптора файла. Возвращает 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.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

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

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

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

См. также

  • #connect

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

Включает опцию сокета 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 — сокет не привязан к локальному адресу, и протокол не поддерживает прослушивание на несвязанном сокете

  • Errno::EINVAL — сокет уже подключен

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

  • Errno::EOPNOTSUPP — протокол socket не поддерживает listen

  • Errno::EACCES — вызывающий процесс не имеет соответствующих привилегий

  • Errno::EINVAL — сокет был закрыт

  • 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 в справке по функциям Winsock от Microsoft

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) → [mesg, sender_addrinfo] Показать исходный код
recvfrom_nonblock(maxlen, flags) → [mesg, sender_addrinfo]
static VALUE
sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
{
    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
}

Принимает до maxlen байт данных от socket с помощью recvfrom(2) после установки O_NONBLOCK для базового дескриптора файла. flags принимает ноль или более MSG_ опций. Первый элемент результата, mesg, содержит полученные данные. Второй элемент, sender_addrinfo, содержит адресную информацию отправителя, специфичную для протокола.

Когда recvfrom(2) возвращает 0, #recvfrom_nonblock возвращает пустую строку в качестве данных. Значение зависит от сокета: EOF для TCP, пустой пакет для UDP и т.д.

Параметры

  • maxlen - максимальное количество байт для получения от сокета

  • flags - ноль или более MSG_ опций

Пример

# 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

Обратитесь к #recvfrom для исключений, которые могут быть выброшены, если вызов recvfrom_nonblock завершится ошибкой.

#recvfrom_nonblock может генерировать любые ошибки, соответствующие ошибкам вызова recvfrom(2), включая Errno::EWOULDBLOCK.

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

См. также

  • #recvfrom

sysaccept → [client_socket_fd, client_addrinfo] Показать исходный код
static VALUE
sock_sysaccept(VALUE sock)
{
    rb_io_t *fptr;
    VALUE sock2;
    union_sockaddr buf;
    socklen_t len = (socklen_t)sizeof buf;

    GetOpenFile(sock, fptr);
    sock2 = rsock_s_accept(0,fptr->fd,&buf.addr,&len);

    return rb_assoc_new(sock2, rsock_io_socket_addrinfo(sock2, &buf.addr, len));
}

Принимает входящее подключение, возвращая массив, содержащий дескриптор файла (целое число) входящего подключения, 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

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

См. также

  • #accept

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API