класс 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);
} Создаёт новый сокет сервера, привязанный к порту 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 sock)
{
rb_io_t *fptr;
union_sockaddr from;
socklen_t fromlen;
GetOpenFile(sock, fptr);
fromlen = (socklen_t)sizeof(from);
return rsock_s_accept(rb_cTCPSocket, fptr->fd, &from.addr, &fromlen);
} Принимает входящее соединение. Возвращает новый объект 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 1313 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.
Обратитесь к Socket#accept для исключений, которые могут быть выброшены, если вызов TCPServer#accept_nonblock завершится неудачно.
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 это будет работать, потому что новый sockaddr создаётся по адресу ADDR_ANY, для произвольного номера порта, переданного ядром. Это не будет работать в Windows, так как Windows требует, чтобы socket был привязан с помощью вызова bind, прежде чем он может listen.
Если значение backlog превышает максимальную длину очереди, зависящую от реализации, будет использоваться максимальная длина очереди реализации.
В системах на основе Unix могут быть выброшены следующие системные исключения, если вызов listen завершится неудачно:
-
Errno::EBADF - аргумент socket не является допустимым дескриптором файла
-
Errno::EDESTADDRREQ - socket не привязан к локальному адресу, и протокол не поддерживает прослушивание на несвязанном сокете
-
Errno::EINVAL - socket уже подключён
-
Errno::ENOTSOCK - аргумент socket не ссылается на сокет
-
Errno::EOPNOTSUPP - протокол socket не поддерживает 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
static VALUE
tcp_sysaccept(VALUE sock)
{
rb_io_t *fptr;
union_sockaddr from;
socklen_t fromlen;
GetOpenFile(sock, fptr);
fromlen = (socklen_t)sizeof(from);
return rsock_s_accept(0, fptr->fd, &from.addr, &fromlen);
} Возвращает дескриптор файла принятого соединения.
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–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.