класс 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, 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 1739 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. Поэтому IO::WaitReadable можно использовать для обработки этих исключений и повторного вызова accept_nonblock.
Указав именованный аргумент 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-подобных системах приведённый выше пример работает, потому что на адресе ADDR_ANY создаётся новая структура sockaddr с произвольным номером порта, назначенным ядром. В Windows это не сработает, поскольку там требуется привязать socket с помощью вызова bind, прежде чем вызывать listen.
Если значение 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.