Версия:

Модуль socket

Модуль socket

Общие сведения

Модуль socket позволяет обмениваться данными с локальным или удаленным хостом по BSD-сокетам в режиме с установлением соединений (TCP) или на основе датаграмм (UDP). Семантика вызовов в API модуля socket точно соответствует семантике соответствующих вызовов в POSIX. Имена и сигнатуры функций по большей части совместимы с luasocket.

Функции для настройки и подключения: socket, sysconnect, tcp_connect. Функции для отправки данных: send, sendto, write, syswrite. Функции для получения данных: recv, recvfrom, read. Функции для ожидания отправки/получения данных: wait, readable, writable. Функции для установки флагов: nonblock, setsockopt. Функции для остановки и отключения: shutdown, close. Функции для проверки ошибок: errno, error.

Индекс

Ниже приведен перечень всех функций модуля socket.

Имя Использование
socket() Создание сокета
socket.tcp_connect() Подключение к удаленному хосту с помощью сокета
socket.getaddrinfo() Получение информации об удаленном узле
socket.tcp_server() Использование Tarantool’а в качестве TCP-сервера
socket_object:sysconnect() Подключение к удаленному хосту с помощью сокета
socket_object:send()
socket_object:write()
Отправка данных по подключенному сокету
socket_object:syswrite() Запись данных в буфер сокета без блокировки
socket_object:recv() Чтение с подключенного сокета
socket_object:sysread() Чтение данных из буфера сокета без блокировки
socket_object:bind() Привязка сокета к данному хосту/порту
socket_object:listen() Начало прослушивания входящих соединений
socket_object:accept() Принятие запроса клиента на соединение + создание подключенного сокета
socket_object:sendto() Отправка сообщения по UDP-сокету на указанный хост
socket_object:recvfrom() Получение сообщения по UDP-сокету
socket_object:shutdown() Отключение передачи данных на чтение, на запись или в обоих направлениях
socket_object:close() Закрытие сокета
socket_object:error()
socket_object:errno()
Получение информации о последней ошибке на сокете
socket_object:setsockopt() Определение флагов сокета
socket_object:getsockopt() Получение флагов сокета
socket_object:linger() Установить/убрать флаг SO_LINGER
socket_object:nonblock() Определить/получить значение флага
socket_object:readable() Ожидание доступности чего-либо для чтения
socket_object:writable() Ожидание доступности чего-либо для записи
socket_object:wait() Ожидание доступности чего-либо для чтения или записи
socket_object:name() Получение информации о ближней стороне соединения
socket_object:peer() Получение информации о дальней стороне соединения
socket.iowait() Ожидание активности чтения/записи

Как правило, сессия сокета начинается с функций настройки, определяет один или более флагов, запустит цикл с функциями отправки и получения и закончится функциями завершения – как в примере в конце данного раздела. В течение сессии может быть проверка на ошибки и ожидание синхронизации функции. Чтобы файбер с сокетом не блокировал другие файберы, правила неявной передачи управления заставят его передать управление другим процессам в рамках кооперативной многозадачности.

Для всех примеров в данном разделе имя сокета будет sock, а вызов функции будет выглядеть как sock:имя_функции(...).

socket.__call(domain, type, protocol)

Создание нового TCP-сокета или UDP-сокета. Значения аргумента остаются теми же, что и на странице socket(2) руководства по Linux.

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

Пример:

socket('AF_INET', 'SOCK_STREAM', 'tcp')
socket.tcp_connect(host[, port[, timeout]])

Подключение к удаленному хосту с помощью сокета.

Параметры:
  • host (string) – URL или IP-адрес
  • port (number) – номер порта
  • timeout (number) – время ожидания
возвращается:

подключенный сокет, если нет ошибки.

тип возвращаемого значения:
 

пользовательские данные

Пример:

socket.tcp_connect('127.0.0.1', 3301)
socket.getaddrinfo(host, type[, {option-list}])

Функция socket.getaddrinfo() используется для поиска информации об удаленном узле, чтобы можно было передать правильные аргументы для sock:sysconnect(). Эта функция может использовать конфигурационный параметр worker_pool_threads.

возвращается:Таблица со следующими полями: «host», «family», «type», «protocol», «port».
тип возвращаемого значения:
 таблица

Пример:

tarantool> socket.getaddrinfo('tarantool.org', 'http')
 ---
 - - host: 188.93.56.70
     family: AF_INET
     type: SOCK_STREAM
     protocol: tcp
     port: 80
   - host: 188.93.56.70
     family: AF_INET
     type: SOCK_DGRAM
     protocol: udp
     port: 80
 ...
socket.tcp_server(host, port, handler-function[, timeout])

Функция socket.tcp_server() заставляет Tarantool выступать в качестве сервера для принятия подключений. Обычно для этой же цели используется box.cfg{listen=…}.

Параметры:
  • host (string) – имя или IP хоста
  • port (number) – порт хоста, может быть 0
  • handler (function/table) – что выполнить после подключения
  • timeout (number) – количество секунд ожидания

Параметр handler-function может представлять собой имя функции (например, function_55), объявление функции (например, function () print('!') end) или таблицу с handler = функция (например, {handler=function_55, name='A'}).

Пример:

socket.tcp_server('localhost', 3302, function () end)

object socket_object
socket_object:sysconnect(host, port)

Подключение к удаленному хосту с помощью существующего сокета. Значения аргументов будут такие же, как в tcp_connect(). Хост должен представлять собой IP-адрес.

Параметры:
  • Либо:
    • host – строковое представление IPv4 адреса или IPv6 адреса;
    • port – число.
  • Либо:
    • host – строка, которая содержит «unix/»;
    • port – строка, которая содержит путь к Unix-сокету.
  • Либо:
    • host – число, 0 (ноль), что означает «все локальные интерфейсы»;
    • port – число. Если номер порта – 0 (ноль), сокет будет привязан к случайному локальному порту.
возвращается:значение объекта сокета может изменяться, если будет выполнена функция sysconnect().
тип возвращаемого значения:
 boolean (логический)

Пример:

socket = require('socket')
 sock = socket('AF_INET', 'SOCK_STREAM', 'tcp')
 sock:sysconnect(0, 3301)
socket_object:send(data)
socket_object:write(data)

Отправка данных по подключенному сокету.

Параметры:
  • data (string) – что отправляется
возвращается:

количество отправляемых байтов.

тип возвращаемого значения:
 

число

Возможные ошибки: nil в случае ошибки.

socket_object:syswrite(size)

Запись максимально возможного количества данных в буфер сокета без блокировки. Используется редко. Для получения подробной информации см. описание по ссылке this description.

socket_object:recv(size)

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

Параметры:
возвращается:

строка запрошенной длины, если выполнено.

тип возвращаемого значения:
 

string (строка)

Возможные ошибки: В случае ошибки возвращается пустая строка, после чего статус, errno, errstr. Если передача данных на запись закрыта с другой стороны, возвращаются оставшиеся для чтения данные из сокета (возможно, пустая строка), после чего идет статус «eof» (конец файла).

socket_object:read(limit[, timeout])
socket_object:read(delimiter[, timeout])
socket_object:read({limit=limit}[, timeout])
socket_object:read({delimiter=delimiter}[, timeout])
socket_object:read({limit=limit, delimiter=delimiter}[, timeout])

Чтение данных из подключенного сокета до выполнения какого-либо условия и возврат прочтенных байтов. Чтение данных производится в таком количестве, которое указано в параметре limit, либо до символа-разделителя, либо до истечения времени ожидания.

Параметры:
  • limit (integer) – максимальное количество байтов для чтения, например, 50 означает «остановиться на 50 байтах»
  • delimiter (string) – разделитель, например, „?“ означает «остановиться после знака вопроса»
  • timeout (number) – максимальное количество секунд ожидания, например, 50 означает «остановиться через 50 секунд».
возвращается:

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

тип возвращаемого значения:
 

string (строка)

socket_object:sysread(size)

Возврат данных из буфера сокета без блокировки.Если сокет с блокировкой, sysread() может блокировать процесс вызова. Используется редко. Для получения подробной информации, см. описание.

Параметры:
  • size (integer) – максимальное количество байтов для чтения, например, 50 означает «остановиться на 50 байтах»
возвращается:

пустая строка, если нет данных для чтения, либо нулевое значение nil в случае ошибки, либо строка, ограниченная количеством байтов в size.

тип возвращаемого значения:
 

string (строка)

socket_object:bind(host[, port])

Привязка сокета к данному хосту/порту. UDP-сокет после привязки может использоваться для получения данных (см. socket_object.recvfrom). TCP-сокет может использоваться для принятия новых соединений после перевода в режим прослушивания.

Параметры:
  • host (string) – URL или IP-адрес
  • port (number) – номер порта
возвращается:

true for success, false for error. If return is false, use socket_object:errno() or socket_object:error() to see details.

тип возвращаемого значения:
 

boolean (логический)

socket_object:listen(backlog)

Начало прослушивания входящих соединений.

Параметры:
  • backlog – on Linux the listen backlog backlog may be from /proc/sys/net/core/somaxconn, on BSD the backlog may be SOMAXCONN.
возвращается:

true (правда), если выполнено, false (ложь) в случае ошибки.

тип возвращаемого значения:
 

boolean (логический).

socket_object:accept()

Принятие нового клиентского соединения и создание нового подключенного сокета. Установка блокирующего режима на сокете явным образом после принятия соединения приведет к эффективной работе.

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

Возможные ошибки: nil.

socket_object:sendto(host, port, data)

Отправка сообщения по UDP-сокету на указанный хост.

Параметры:
  • host (string) – URL или IP-адрес
  • port (number) – номер порта
  • data (string) – что отправляется
возвращается:

количество отправляемых байтов.

тип возвращаемого значения:
 

число

Возможные ошибки: в случае ошибки возвращает nil, а также может вернуть статус, errno, errstr.

socket_object:recvfrom(size)

Получение сообщения по UDP-сокету.

Параметры:
возвращается:

сообщение, таблица с полями «host», «family» и «port».

тип возвращаемого значения:
 

строка, таблица

Возможные ошибки: в случае ошибки возвращает nil, статус, errno, errstr.

Пример:

После message_content, message_sender = recvfrom(1) значением message_content может быть строка, которая содержит „X“, а значением message_sender может быть таблица, которая содержит

message_sender.host = '18.44.0.1'
 message_sender.family = 'AF_INET'
 message_sender.port = 43065
socket_object:shutdown(how)

Отключение передачи данных на чтение, на запись или в обоих направлениях.

Параметры:
  • how – socket.SHUT_RD, socket.SHUT_WR, or socket.SHUT_RDWR.
возвращается:

true (правда) или false (ложь).

тип возвращаемого значения:
 

boolean (логический)

socket_object:close()

Close (destroy) a socket. A closed socket should not be used any more. A socket is closed automatically when the Lua garbage collector removes its user data.

возвращается:true (правда), если выполнено, false (ложь) в случае ошибки. Например, если сокет sock уже закрыт, sock:close() вернет false.
тип возвращаемого значения:
 boolean (логический)
socket_object:error()
socket_object:errno()

Получение информации о последней ошибке на сокете, если таковая была. Ошибки не выдают исключения, поэтому данные функции необходимы.

возвращается:результат sock:errno(), результат sock:error(). Если ошибки нет, то sock:errno() вернет 0 и sock:error().
тип возвращаемого значения:
 число, строка
socket_object:setsockopt(level, name, value)

Определение флагов сокета. Значения аргумента будут такими же, что и на странице getsockopt(2) руководства по Linux. Tarantool принимает следующие:

  • SO_ACCEPTCONN
  • SO_BINDTODEVICE
  • SO_BROADCAST
  • SO_DEBUG
  • SO_DOMAIN
  • SO_ERROR
  • SO_DONTROUTE
  • SO_KEEPALIVE
  • SO_MARK
  • SO_OOBINLINE
  • SO_PASSCRED
  • SO_PEERCRED
  • SO_PRIORITY
  • SO_PROTOCOL
  • SO_RCVBUF
  • SO_RCVBUFFORCE
  • SO_RCVLOWAT
  • SO_SNDLOWAT
  • SO_RCVTIMEO
  • SO_SNDTIMEO
  • SO_REUSEADDR
  • SO_SNDBUF
  • SO_SNDBUFFORCE
  • SO_TIMESTAMP
  • SO_TYPE

Установка флага SO_LINGER осуществляется с помощью sock:linger(active).

socket_object:getsockopt(level, name)

Получение флагов сокета. Список возможных флагов см. с помощью sock:setsockopt().

socket_object:linger([active])

Установить или убрать флаг SO_LINGER. Описание флага см. в руководстве по Linux.

Параметры:
  • active (boolean) –
возвращается:

новые значения active и timeout.

socket_object:nonblock([flag])
  • sock:nonblock() возвращает текущее значение флага.
  • sock:nonblock(false) устанавливает флаг на false и возвращает false.
  • sock:nonblock(true) устанавливает флаг на true и возвращает true.

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

socket_object:readable([timeout])

Ожидание доступности чего-либо для чтения или до истечения времени ожидания.

возвращается:true, если сокет доступен для чтения, false, если истекло время ожидания;
socket_object:writable([timeout])

Ожидание доступности чего-либо для записи или до истечения времени ожидания.

возвращается:true, если сокет доступен для записи, false, если истекло время ожидания;
socket_object:wait([timeout])

Ожидание доступности чего-либо для чтения или записи, или до истечения времени ожидания.

возвращается:„R“, если сокет доступен для чтения, „W“, если сокет доступен для записи, „RW“, если сокет доступен и для чтения, и для записи, „“ (пустая строка), если истекло время ожидания;
socket_object:name()

Функция sock:name() используется для получения информации о ближней стороне соединения. Если сокет привязан к xyz.com:45, то sock:name вернет информацию о [host:xyz.com, port:45]. Аналогичная функция в POSIX – getsockname().

возвращается:Таблица со следующими полями: «host», «family», «type», «protocol», «port».
тип возвращаемого значения:
 таблица
socket_object:peer()

Функция sock:peer() используется для получения информации о дальней стороне соединения. Если TCP-соединение установлено с удаленным хостом tarantool.org:80, то sock:peer() вернет информацию о [host:tarantool.org, port:80]. Аналогичная функция в POSIX – getpeername().

возвращается:Таблица со следующими полями: «host», «family», «type», «protocol», «port».
тип возвращаемого значения:
 таблица
socket.iowait(fd, read-or-write-flags[, timeout])

Функция socket.iowait() используется для ожидания, пока дескриптор файла не будет активен для чтения или записи.

Параметры:
  • fd – дескриптор файла
  • read-or-write-flags – „R“ или 1 = чтение, „W“ или 2 = запись, „RW“ или 3 = чтение|запись.
  • timeout – количество секунд ожидания

Если значение параметра fd – nil, то будет режим ожидания до истечения времени, указанного в параметре timeout. Если timeout – nil или не указан, время ожидания считается бесконечным.

Как правило, возвращается значение совершенного действия („R“ или „W“, или „RW“, или 1, или 2, или 3). Если время ожидания в timeout проходит без действий чтения или записи, возвращается ошибка = ETIMEDOUT.

Пример: socket.iowait(sock:fd(), 'r', 1.11)

Примеры

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

В данном примере устанавливается соединение по интернету между экземпляром Tarantool’а и tarantool.org, затем отправляется HTTP-сообщение заголовка «head» и возвращается ответ: «HTTP/1.1 200 OK» или что-то другое, если сайт перемещен. Так не слишком удобно взаимодействовать с определенным сайтом, но пример показывает работу системы.

tarantool> socket = require('socket')
 ---
 ...
 tarantool> sock = socket.tcp_connect('tarantool.org', 80)
 ---
 ...
 tarantool> type(sock)
 ---
 - table
 ...
 tarantool> sock:error()
 ---
 - null
 ...
 tarantool> sock:send("HEAD / HTTP/1.0\r\nHost: tarantool.org\r\n\r\n")
 ---
 - 40
 ...
 tarantool> sock:read(17)
 ---
 - HTTP/1.1 302 Move
 ...
 tarantool> sock:close()
 ---
 - true
 ...

Использование UDP-сокета на localhost

Ниже приведен пример с датаграммами. Устанавливается два соединения с 127.0.0.1 (localhost): sock_1 и sock_2. С помощью sock_2 отправляется сообщение на sock_1. С помощью sock_1 получается сообщение. Отображается полученное сообщение. Оба соединения закрываются.
Компьютеру так не слишком удобно взаимодействовать с самим собой, но пример показывает работу системы.

tarantool> socket = require('socket')
---
...
tarantool> sock_1 = socket('AF_INET', 'SOCK_DGRAM', 'udp')
---
...
tarantool> sock_1:bind('127.0.0.1')
---
- true
...
tarantool> sock_2 = socket('AF_INET', 'SOCK_DGRAM', 'udp')
---
...
tarantool> sock_2:sendto('127.0.0.1', sock_1:name().port,'X')
---
- 1
...
tarantool> message = sock_1:recvfrom(512)
---
...
tarantool> message
---
- X
...
tarantool> sock_1:close()
---
- true
...
tarantool> sock_2:close()
---
- true
...

Использование tcp_server для получения содержимого файла, отправленного по socat

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

Запустите две оболочки. Первая оболочка будет экземпляром сервера. Вторая оболочка будет клиентом.

В первой оболочке запустите Tarantool и выполните:

box.cfg{}
 socket = require('socket')
 socket.tcp_server('0.0.0.0', 3302, function(s)
     while true do
       local request
       request = s:read("\n");
       if request == "" or request == nil then
         break
       end
       print(request)
     end
   end)

Вышеуказанный код означает: использовать tcp_server() для ожидания подключения с любого хоста по порту 3302. Когда это произойдет, ввести цикл, который читает по сокету и выводит результат чтения. Разделителем для функции чтения будет «\n», поэтому каждое выполнение read() выполнит чтение строки до перевода строки, включая перевод строки.

Во второй оболочке создайте файл, который содержит несколько строк. Содержимое не имеет значения. Предположим, что первая строка содержит A, вторая строка содержит B, третья строка содержит C. Вызвать этот файл «tmp.txt».

Во второй оболочке используйте утилиту socat для отправки файла tmp.txt на экземпляр сервера по хосту и порту:

$ socat TCP:localhost:3302 ./tmp.txt

Теперь смотрите, что происходит в первой оболочке. Выводятся строки «A», «B», «C».