класс TCPServer
TCPServer представляет серверный сокет TCP/IP.
Простой TCP-сервер может выглядеть так:
require 'socket'
server = TCPServer.new 2000 # Server bind 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'
server = TCPServer.new 2000
loop do
Thread.start(server.accept) do |client|
client.puts "Hello !"
client.puts "Time is #{Time.now}"
client.close
end
end
Публичные методы класса
static VALUE
tcp_svr_init(int argc, VALUE *argv, VALUE sock)
{
VALUE hostname, port;
rb_scan_args(argc, argv, "011", &hostname, &port);
return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil, Qnil, Qnil, Qfalse, Qnil);
} Создаёт новый серверный сокет, привязанный к port.
Если указан hostname, сокет привязывается к нему.
serv = TCPServer.new("127.0.0.1", 28561)
s = serv.accept
s.puts Time.now
s.close
Внутри TCPServer.new вызывает функцию getaddrinfo() для получения адресов. Если getaddrinfo() возвращает несколько адресов, TCPServer.new пытается создать серверный сокет для каждого адреса и возвращает первый успешно созданный.
Публичные методы экземпляра
static VALUE
tcp_accept(VALUE server)
{
union_sockaddr buffer;
socklen_t length = sizeof(buffer);
return rsock_s_accept(rb_cTCPSocket, server, &buffer.addr, &length);
} Принимает входящее соединение. Возвращает новый объект TCPSocket.
TCPServer.open("127.0.0.1", 14641) {|serv|
s = serv.accept
s.puts Time.now
s.close
}
# File ext/socket/lib/socket.rb, line 1777 def accept_nonblock(exception: true) __accept_nonblock(exception) end
Принимает входящее соединение с помощью accept(2) после установки O_NONBLOCK для базового файлового дескриптора. Возвращает принятый TCPSocket для входящего соединения.
Пример
require 'socket' serv = TCPServer.new(2202) begin # emulate blocking accept sock = serv.accept_nonblock rescue IO::WaitReadable, Errno::EINTR IO.select([serv]) retry end # sock is an accepted socket.
Сведения об исключениях, которые могут быть вызваны при неудачном вызове TCPServer#accept_nonblock, см. в разделе Socket#accept.
TCPServer#accept_nonblock может вызвать любую ошибку, соответствующую сбою accept(2), включая Errno::EWOULDBLOCK.
Если исключение имеет тип Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNABORTED или Errno::EPROTO, к нему добавляется IO::WaitReadable. Поэтому для перехвата исключений и повторной попытки вызова accept_nonblock можно использовать IO::WaitReadable.
Указав ключевой аргумент exception для false, можно указать, что accept_nonblock не должен вызывать исключение IO::WaitReadable, а должен возвращать вместо него символ :wait_readable.
См. также
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 это не сработает, поскольку перед вызовом listen Windows требует привязать socket вызовом bind.
Если значение backlog превышает максимальную длину очереди, зависящую от реализации, будет использована максимальная длина очереди, поддерживаемая реализацией.
В Unix-подобных системах при неудачном вызове listen могут быть вызваны следующие системные исключения:
-
Errno::EBADF — аргумент socket не является допустимым файловым дескриптором
-
Errno::EDESTADDRREQ — сокет socket не привязан к локальному адресу, а протокол не поддерживает прослушивание непривязанного сокета
-
Errno::EINVAL — сокет socket уже подключён
-
Errno::ENOTSOCK — аргумент socket не является сокетом
-
Errno::EOPNOTSUPP — протокол сокета socket не поддерживает listen
-
Errno::EACCES — вызывающий процесс не имеет необходимых прав
-
Errno::EINVAL — сокет socket был отключён
-
Errno::ENOBUFS — в системе недостаточно ресурсов для выполнения вызова
Исключения в Windows
В системах Windows при неудачном вызове listen могут быть вызваны следующие системные исключения:
-
Errno::ENETDOWN — сеть не работает
-
Errno::EADDRINUSE — локальный адрес сокета уже используется. Обычно это происходит во время выполнения bind, но может произойти и позже, если вызов bind был выполнен для частично подстановочного адреса (с использованием ADDR_ANY) и конкретный адрес необходимо зафиксировать во время вызова listen
-
Errno::EINPROGRESS — выполняется вызов Windows Sockets 1.1 или поставщик служб всё ещё обрабатывает функцию обратного вызова
-
Errno::EINVAL —
socketне был привязан вызовом bind. -
Errno::EISCONN —
socketуже подключён -
Errno::EMFILE — больше нет доступных дескрипторов сокетов
-
Errno::ENOBUFS — недостаточно места в буфере
-
Errno::ENOTSOC —
socketне является сокетом -
Errno::EOPNOTSUPP — тип объекта
socketне поддерживает метод listen
См. также
-
справочные страницы listen в Unix-подобных системах
-
функция listen в справочнике функций Winsock от Microsoft
static VALUE
tcp_sysaccept(VALUE server)
{
union_sockaddr buffer;
socklen_t length = sizeof(buffer);
return rsock_s_accept(0, server, &buffer.addr, &length);
} Возвращает файловый дескриптор принятого соединения.
TCPServer.open("127.0.0.1", 28561) {|serv|
fd = serv.sysaccept
s = IO.for_fd(fd)
s.puts Time.now
s.close
}
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.