Spec-Zone.ru › Ruby 2.2

класс BasicSocket

Родитель:
IO

BasicSocket — это суперкласс для всех классов Socket.

Методы класса

do_not_reverse_lookup → true или false Показать исходный код
static VALUE
bsock_do_not_rev_lookup(void)
{
    return rsock_do_not_reverse_lookup?Qtrue:Qfalse;
}

Возвращает глобальный флаг ::do_not_reverse_lookup.

BasicSocket.do_not_reverse_lookup  #=> false
do_not_reverse_lookup = bool Показать исходный код
static VALUE
bsock_do_not_rev_lookup_set(VALUE self, VALUE val)
{
    rsock_do_not_reverse_lookup = RTEST(val);
    return val;
}

Устанавливает глобальный флаг ::do_not_reverse_lookup.

Флаг используется для начального значения ::do_not_reverse_lookup для каждого сокета.

s1 = TCPSocket.new("localhost", 80)
p s1.do_not_reverse_lookup                 #=> true
BasicSocket.do_not_reverse_lookup = false
s2 = TCPSocket.new("localhost", 80)
p s2.do_not_reverse_lookup                 #=> false
p s1.do_not_reverse_lookup                 #=> true
for_fd(fd) → basicsocket Показать исходный код
static VALUE
bsock_s_for_fd(VALUE klass, VALUE fd)
{
    rb_io_t *fptr;
    VALUE sock = rsock_init_sock(rb_obj_alloc(klass), NUM2INT(fd));

    GetOpenFile(sock, fptr);

    return sock;
}

Возвращает объект сокета, содержащий дескриптор файла, fd.

# If invoked by inetd, STDIN/STDOUT/STDERR is a socket.
STDIN_SOCK = Socket.for_fd(STDIN.fileno)
p STDIN_SOCK.remote_address

Методы экземпляра

close_read → nil Показать исходный код
static VALUE
bsock_close_read(VALUE sock)
{
    rb_io_t *fptr;

    GetOpenFile(sock, fptr);
    shutdown(fptr->fd, 0);
    if (!(fptr->mode & FMODE_WRITABLE)) {
        return rb_io_close(sock);
    }
    fptr->mode &= ~FMODE_READABLE;

    return Qnil;
}

Запрещает дальнейшее чтение с помощью системного вызова shutdown.

s1, s2 = UNIXSocket.pair
s1.close_read
s2.puts #=> Broken pipe (Errno::EPIPE)
close_write → nil Показать исходный код
static VALUE
bsock_close_write(VALUE sock)
{
    rb_io_t *fptr;

    GetOpenFile(sock, fptr);
    if (!(fptr->mode & FMODE_READABLE)) {
        return rb_io_close(sock);
    }
    shutdown(fptr->fd, 1);
    fptr->mode &= ~FMODE_WRITABLE;

    return Qnil;
}

Запрещает дальнейшую запись с помощью системного вызова shutdown.

UNIXSocket.pair {|s1, s2|
  s1.print "ping"
  s1.close_write
  p s2.read        #=> "ping"
  s2.print "pong"
  s2.close
  p s1.read        #=> "pong"
}
connect_address() Показать исходный код
# File ext/socket/lib/socket.rb, line 256
def connect_address
  addr = local_address
  afamily = addr.afamily
  if afamily == Socket::AF_INET
    raise SocketError, "unbound IPv4 socket" if addr.ip_port == 0
    if addr.ip_address == "0.0.0.0"
      addr = Addrinfo.new(["AF_INET", addr.ip_port, nil, "127.0.0.1"], addr.pfamily, addr.socktype, addr.protocol)
    end
  elsif defined?(Socket::AF_INET6) && afamily == Socket::AF_INET6
    raise SocketError, "unbound IPv6 socket" if addr.ip_port == 0
    if addr.ip_address == "::"
      addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
    elsif addr.ip_address == "0.0.0.0" # MacOS X 10.4 returns "a.b.c.d" for IPv4-mapped IPv6 address.
      addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
    elsif addr.ip_address == "::ffff:0.0.0.0" # MacOS X 10.6 returns "::ffff:a.b.c.d" for IPv4-mapped IPv6 address.
      addr = Addrinfo.new(["AF_INET6", addr.ip_port, nil, "::1"], addr.pfamily, addr.socktype, addr.protocol)
    end
  elsif defined?(Socket::AF_UNIX) && afamily == Socket::AF_UNIX
    raise SocketError, "unbound Unix socket" if addr.unix_path == ""
  end
  addr
end

Возвращает адрес сокета, подходящий для подключения в локальной машине.

Этот метод возвращает self.local_address, за исключением следующих условий.

  • Неуказанный IPv4-адрес (0.0.0.0) заменяется IPv4-адресом обратной связи (127.0.0.1).

  • Неуказанный IPv6-адрес (::) заменяется IPv6-адресом обратной связи (::1).

Если локальный адрес не подходит для подключения, генерируется исключение SocketError. IPv4 и IPv6-адреса с портом 0 не подходят для подключения. Сокет доменной Unix без пути не подходит для подключения.

Addrinfo.tcp("0.0.0.0", 0).listen {|serv|
  p serv.connect_address #=> #<Addrinfo: 127.0.0.1:53660 TCP>
  serv.connect_address.connect {|c|
    s, _ = serv.accept
    p [c, s] #=> [#<Socket:fd 4>, #<Socket:fd 6>]
  }
}
do_not_reverse_lookup → true или false Показать исходный код
static VALUE
bsock_do_not_reverse_lookup(VALUE sock)
{
    rb_io_t *fptr;

    GetOpenFile(sock, fptr);
    return (fptr->mode & FMODE_NOREVLOOKUP) ? Qtrue : Qfalse;
}

Возвращает флаг ::do_not_reverse_lookup для basicsocket.

TCPSocket.open("www.ruby-lang.org", 80) {|sock|
  p sock.do_not_reverse_lookup      #=> false
  p sock.peeraddr                   #=> ["AF_INET", 80, "carbon.ruby-lang.org", "221.186.184.68"]
  sock.do_not_reverse_lookup = true
  p sock.peeraddr                   #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
}
do_not_reverse_lookup = bool Показать исходный код
static VALUE
bsock_do_not_reverse_lookup_set(VALUE sock, VALUE state)
{
    rb_io_t *fptr;

    GetOpenFile(sock, fptr);
    if (RTEST(state)) {
        fptr->mode |= FMODE_NOREVLOOKUP;
    }
    else {
        fptr->mode &= ~FMODE_NOREVLOOKUP;
    }
    return sock;
}

Устанавливает флаг ::do_not_reverse_lookup для basicsocket.

BasicSocket.do_not_reverse_lookup = false
p TCPSocket.new("127.0.0.1", 80).do_not_reverse_lookup #=> false
BasicSocket.do_not_reverse_lookup = true
p TCPSocket.new("127.0.0.1", 80).do_not_reverse_lookup #=> true
getpeereid → [euid, egid] Показать исходный код
static VALUE
bsock_getpeereid(VALUE self)
{
#if defined(HAVE_GETPEEREID)
    rb_io_t *fptr;
    uid_t euid;
    gid_t egid;
    GetOpenFile(self, fptr);
    if (getpeereid(fptr->fd, &euid, &egid) == -1)
        rb_sys_fail("getpeereid(3)");
    return rb_assoc_new(UIDT2NUM(euid), GIDT2NUM(egid));
#elif defined(SO_PEERCRED) /* GNU/Linux */
    rb_io_t *fptr;
    struct ucred cred;
    socklen_t len = sizeof(cred);
    GetOpenFile(self, fptr);
    if (getsockopt(fptr->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == -1)
        rb_sys_fail("getsockopt(SO_PEERCRED)");
    return rb_assoc_new(UIDT2NUM(cred.uid), GIDT2NUM(cred.gid));
#elif defined(HAVE_GETPEERUCRED) /* Solaris */
    rb_io_t *fptr;
    ucred_t *uc = NULL;
    VALUE ret;
    GetOpenFile(self, fptr);
    if (getpeerucred(fptr->fd, &uc) == -1)
        rb_sys_fail("getpeerucred(3C)");
    ret = rb_assoc_new(UIDT2NUM(ucred_geteuid(uc)), GIDT2NUM(ucred_getegid(uc)));
    ucred_free(uc);
    return ret;
#endif
}

Возвращает пользователя и группу на стороне сокета Unix. Результатом является массив из двух элементов, содержащий эффективный идентификатор пользователя (euid) и эффективный идентификатор группы (egid).

Socket.unix_server_loop("/tmp/sock") {|s|
  begin
    euid, egid = s.getpeereid

    # Check the connected client is myself or not.
    next if euid != Process.uid

    # do something about my resource.

  ensure
    s.close
  end
}
getpeername → sockaddr Показать исходный код
static VALUE
bsock_getpeername(VALUE sock)
{
    union_sockaddr buf;
    socklen_t len = (socklen_t)sizeof buf;
    socklen_t len0 = len;
    rb_io_t *fptr;

    GetOpenFile(sock, fptr);
    if (getpeername(fptr->fd, &buf.addr, &len) < 0)
        rb_sys_fail("getpeername(2)");
    if (len0 < len) len = len0;
    return rb_str_new((char*)&buf, len);
}

Возвращает удалённый адрес сокета в виде строки sockaddr.

TCPServer.open("127.0.0.1", 1440) {|serv|
  c = TCPSocket.new("127.0.0.1", 1440)
  s = serv.accept
  p s.getpeername #=> "\x02\x00\x82u\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
}

Если предпочтительнее объект Addrinfo, а не двоичная строка, используйте #remote_address.

getsockname → sockaddr Показать исходный код
static VALUE
bsock_getsockname(VALUE sock)
{
    union_sockaddr buf;
    socklen_t len = (socklen_t)sizeof buf;
    socklen_t len0 = len;
    rb_io_t *fptr;

    GetOpenFile(sock, fptr);
    if (getsockname(fptr->fd, &buf.addr, &len) < 0)
        rb_sys_fail("getsockname(2)");
    if (len0 < len) len = len0;
    return rb_str_new((char*)&buf, len);
}

Возвращает локальный адрес сокета в виде строки sockaddr.

TCPServer.open("127.0.0.1", 15120) {|serv|
  p serv.getsockname #=> "\x02\x00;\x10\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
}

Если предпочтительнее объект Addrinfo, а не двоичная строка, используйте #local_address.

getsockopt(level, optname) → socketoption Показать исходный код
static VALUE
bsock_getsockopt(VALUE sock, VALUE lev, VALUE optname)
{
    int level, option;
    socklen_t len;
    char *buf;
    rb_io_t *fptr;
    int family;

    GetOpenFile(sock, fptr);
    family = rsock_getfamily(fptr->fd);
    level = rsock_level_arg(family, lev);
    option = rsock_optname_arg(family, level, optname);
    len = 256;
    buf = ALLOCA_N(char,len);

    rb_io_check_closed(fptr);

    if (getsockopt(fptr->fd, level, option, buf, &len) < 0)
        rsock_sys_fail_path("getsockopt(2)", fptr->pathv);

    return rsock_sockopt_new(family, level, option, rb_str_new(buf, len));
}

Получает опцию сокета. Эти опции зависят от протокола и системы, смотрите документацию вашей системы для подробностей. Опция возвращается в виде объекта Socket::Option.

Параметры

  • level — целое число, обычно одно из констант SOL_, например Socket::SOL_SOCKET, или уровень протокола. Также принимаются строка или символ имени, возможно без префикса.

  • optname — целое число, обычно одно из констант SO_, например Socket::SO_REUSEADDR. Также принимаются строка или символ имени, возможно без префикса.

Примеры

Некоторые опции сокета — целые числа с булевыми значениями, в этом случае getsockopt может вызываться так:

reuseaddr = sock.getsockopt(:SOCKET, :REUSEADDR).bool

optval = sock.getsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR)
optval = optval.unpack "i"
reuseaddr = optval[0] == 0 ? false : true

Некоторые опции сокета — целые числа с числовыми значениями, в этом случае getsockopt может вызываться так:

ipttl = sock.getsockopt(:IP, :TTL).int

optval = sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
ipttl = optval.unpack("i")[0]

Значения опций могут быть структурами. Их декодирование может быть сложным, так как оно включает в себя изучение заголовков вашей системы для определения правильного определения. Примером является +struct linger+, которая может быть определена в заголовках вашей системы как:

struct linger {
  int l_onoff;
  int l_linger;
};

В этом случае getsockopt может вызываться так:

# Socket::Option knows linger structure.
onoff, linger = sock.getsockopt(:SOCKET, :LINGER).linger

optval =  sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER)
onoff, linger = optval.unpack "ii"
onoff = onoff == 0 ? false : true
local_address → addrinfo Показать исходный код
static VALUE
bsock_local_address(VALUE sock)
{
    union_sockaddr buf;
    socklen_t len = (socklen_t)sizeof buf;
    socklen_t len0 = len;
    rb_io_t *fptr;

    GetOpenFile(sock, fptr);
    if (getsockname(fptr->fd, &buf.addr, &len) < 0)
        rb_sys_fail("getsockname(2)");
    if (len0 < len) len = len0;
    return rsock_fd_socket_addrinfo(fptr->fd, &buf.addr, len);
}

Возвращает объект Addrinfo для локального адреса, полученного с помощью getsockname.

Обратите внимание, что addrinfo.protocol заполнен 0.

TCPSocket.open("www.ruby-lang.org", 80) {|s|
  p s.local_address #=> #<Addrinfo: 192.168.0.129:36873 TCP>
}

TCPServer.open("127.0.0.1", 1512) {|serv|
  p serv.local_address #=> #<Addrinfo: 127.0.0.1:1512 TCP>
}
recv(maxlen) → mesg Показать исходный код
recv(maxlen, flags) → mesg
static VALUE
bsock_recv(int argc, VALUE *argv, VALUE sock)
{
    return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
}

Принимает сообщение.

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

flags должно быть побитовым ИЛИ констант Socket::MSG_*.

UNIXSocket.pair {|s1, s2|
  s1.puts "Hello World"
  p s2.recv(4)                     #=> "Hell"
  p s2.recv(4, Socket::MSG_PEEK)   #=> "o Wo"
  p s2.recv(4)                     #=> "o Wo"
  p s2.recv(10)                    #=> "rld\n"
}
recv_nonblock(maxlen) → mesg Показать исходный код
recv_nonblock(maxlen, flags) → mesg
static VALUE
bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
{
    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_RECV);
}

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

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

Параметры

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

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

Пример

serv = TCPServer.new("127.0.0.1", 0)
af, port, host, addr = serv.addr
c = TCPSocket.new(addr, port)
s = serv.accept
c.send "aaa", 0
begin # emulate blocking recv.
  p s.recv_nonblock(10) #=> "aaa"
rescue IO::WaitReadable
  IO.select([s])
  retry
end

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

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

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

См. также

  • Socket#recvfrom

recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) → [mesg, sender_addrinfo, rflags, *controls] Показать исходный код
VALUE
rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
{
    return bsock_recvmsg_internal(argc, argv, sock, 0);
}

recvmsg получает сообщение с помощью системного вызова recvmsg(2) в блокирующем режиме.

maxmesglen — максимальная длина принимаемого сообщения.

flags — битовое ИЛИ констант MSG_*, таких как Socket::MSG_PEEK.

maxcontrollen — максимальная длина управляющих данных (дополнительных данных).

opts — опции в виде хеша. В настоящее время единственной опцией является :scm_rights=>bool.

Опция :scm_rights указывает, что приложение ожидает управляющее сообщение SCM_RIGHTS. Если значение равно nil или false, приложение не ожидает управляющее сообщение SCM_RIGHTS. В этом случае recvmsg закрывает переданные дескрипторы файлов немедленно. Это поведение по умолчанию.

Если значение :scm_rights не равно nil и не равно false, приложение ожидает управляющее сообщение SCM_RIGHTS. В этом случае recvmsg создаёт объекты IO для каждого дескриптора файла для метода Socket::AncillaryData#unix_rights.

Возвращаемое значение — массив из 4 элементов.

mesg — строка полученного сообщения.

sender_addrinfo — адрес отправителя сокета для сокета без соединения. Это объект Addrinfo. Для ориентированного на соединение сокета, такого как TCP, sender_addrinfo зависит от платформы.

rflags — флаги полученного сообщения, которые являются битовым ИЛИ констант MSG_*, таких как Socket::MSG_TRUNC. Будет nil, если система использует старый системный вызов recvmsg в стиле 4.3BSD.

controls — дополнительные данные, являющиеся массивом объектов Socket::AncillaryData, таких как:

#<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>

maxmesglen и maxcontrollen могут быть nil. В этом случае буфер будет увеличиваться до тех пор, пока сообщение не будет усечено. Внутренне используется MSG_PEEK и проверяются MSG_TRUNC/MSG_CTRUNC.

recvmsg можно использовать для реализации recv_io следующим образом:

mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
controls.each {|ancdata|
  if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
    return ancdata.unix_rights[0]
  end
}
recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) → [data, sender_addrinfo, rflags, *controls] Показать исходный код
VALUE
rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
{
    return bsock_recvmsg_internal(argc, argv, sock, 1);
}

recvmsg получает сообщение с помощью системного вызова recvmsg(2) в режиме без блокировки.

Аналогично #recvmsg, но флаг без блокировки устанавливается перед системным вызовом, и системный вызов не повторяется.

remote_address → addrinfo Показать исходный код
static VALUE
bsock_remote_address(VALUE sock)
{
    union_sockaddr buf;
    socklen_t len = (socklen_t)sizeof buf;
    socklen_t len0 = len;
    rb_io_t *fptr;

    GetOpenFile(sock, fptr);
    if (getpeername(fptr->fd, &buf.addr, &len) < 0)
        rb_sys_fail("getpeername(2)");
    if (len0 < len) len = len0;
    return rsock_fd_socket_addrinfo(fptr->fd, &buf.addr, len);
}

Возвращает объект Addrinfo для удалённого адреса, полученного с помощью getpeername.

Обратите внимание, что addrinfo.protocol заполняется 0.

TCPSocket.open("www.ruby-lang.org", 80) {|s|
  p s.remote_address #=> #<Addrinfo: 221.186.184.68:80 TCP>
}

TCPServer.open("127.0.0.1", 1728) {|serv|
  c = TCPSocket.new("127.0.0.1", 1728)
  s = serv.accept
  p s.remote_address #=> #<Addrinfo: 127.0.0.1:36504 TCP>
}
send(mesg, flags [, dest_sockaddr]) → numbytes_sent Показать исходный код
VALUE
rsock_bsock_send(int argc, VALUE *argv, VALUE sock)
{
    struct rsock_send_arg arg;
    VALUE flags, to;
    rb_io_t *fptr;
    int n;
    rb_blocking_function_t *func;

    rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);

    StringValue(arg.mesg);
    if (!NIL_P(to)) {
        SockAddrStringValue(to);
        to = rb_str_new4(to);
        arg.to = (struct sockaddr *)RSTRING_PTR(to);
        arg.tolen = RSTRING_SOCKLEN(to);
        func = rsock_sendto_blocking;
    }
    else {
        func = rsock_send_blocking;
    }
    GetOpenFile(sock, fptr);
    arg.fd = fptr->fd;
    arg.flags = NUM2INT(flags);
    while (rsock_maybe_fd_writable(arg.fd),
           (n = (int)BLOCKING_REGION_FD(func, &arg)) < 0) {
        if (rb_io_wait_writable(arg.fd)) {
            continue;
        }
        rb_sys_fail("send(2)");
    }
    return INT2FIX(n);
}

Отправляет mesg через basicsocket.

mesg должно быть строкой.

flags должно быть битовым ИЛИ констант Socket::MSG_*.

dest_sockaddr должно быть упакованной строкой sockaddr или объектом addrinfo.

TCPSocket.open("localhost", 80) {|s|
  s.send "GET / HTTP/1.0\r\n\r\n", 0
  p s.read
}
sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) → numbytes_sent Показать исходный код
VALUE
rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
{
    return bsock_sendmsg_internal(argc, argv, sock, 0);
}

sendmsg отправляет сообщение с помощью системного вызова sendmsg(2) в блокирующем режиме.

mesg — строка для отправки.

flags — битовое ИЛИ констант MSG_*, таких как Socket::MSG_OOB.

dest_sockaddr — адрес назначения сокета для сокета без соединения. Он должен быть sockaddr, например, результатом Socket.sockaddr_in. Также можно использовать объект Addrinfo.

controls — список дополнительных данных. Элементом controls должен быть Socket::AncillaryData или массив из 3 элементов. Массив из 3 элементов должен содержать cmsg_level, cmsg_type и данные.

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

sendmsg можно использовать для реализации send_io следующим образом:

# use Socket::AncillaryData.
ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
sock.sendmsg("a", 0, nil, ancdata)

# use 3-element array.
ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
sock.sendmsg("\0", 0, nil, ancdata)
sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) → numbytes_sent Показать исходный код
VALUE
rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
{
    return bsock_sendmsg_internal(argc, argv, sock, 1);
}

#sendmsg_nonblock отправляет сообщение с помощью системного вызова sendmsg(2) в режиме без блокировки.

Аналогично #sendmsg, но флаг без блокировки устанавливается перед системным вызовом, и системный вызов не повторяется.

setsockopt(level, optname, optval) Показать исходный код
setsockopt(socketoption)
static VALUE
bsock_setsockopt(int argc, VALUE *argv, VALUE sock)
{
    VALUE lev, optname, val;
    int family, level, option;
    rb_io_t *fptr;
    int i;
    char *v;
    int vlen;

    if (argc == 1) {
        lev = rb_funcall(argv[0], rb_intern("level"), 0);
        optname = rb_funcall(argv[0], rb_intern("optname"), 0);
        val = rb_funcall(argv[0], rb_intern("data"), 0);
    }
    else {
        rb_scan_args(argc, argv, "30", &lev, &optname, &val);
    }

    rb_secure(2);
    GetOpenFile(sock, fptr);
    family = rsock_getfamily(fptr->fd);
    level = rsock_level_arg(family, lev);
    option = rsock_optname_arg(family, level, optname);

    switch (TYPE(val)) {
      case T_FIXNUM:
        i = FIX2INT(val);
        goto numval;
      case T_FALSE:
        i = 0;
        goto numval;
      case T_TRUE:
        i = 1;
      numval:
        v = (char*)&i; vlen = (int)sizeof(i);
        break;
      default:
        StringValue(val);
        v = RSTRING_PTR(val);
        vlen = RSTRING_SOCKLEN(val);
        break;
    }

    rb_io_check_closed(fptr);
    if (setsockopt(fptr->fd, level, option, v, vlen) < 0)
        rsock_sys_fail_path("setsockopt(2)", fptr->pathv);

    return INT2FIX(0);
}

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

Параметры

  • level — целое число, обычно одно из констант SOL_, таких как Socket::SOL_SOCKET, или уровень протокола. Также принимается строка или символ имени, возможно, без префикса.

  • optname — целое число, обычно одно из констант SO_, таких как Socket::SO_REUSEADDR. Также принимается строка или символ имени, возможно, без префикса.

  • optval — значение опции, передаваемое в подлежащий setsockopt() как указатель на определённое количество байтов. Способ передачи зависит от типа:

    • Fixnum: значение присваивается int, и указатель на int передаётся с длиной sizeof(int).

    • true или false: 1 или 0 (соответственно) присваивается int, и int передаётся как для Fixnum. Обратите внимание, что false должно быть передано, а не nil.

    • Строка: данные и длина строки передаются в сокет.

  • socketoption — экземпляр Socket::Option

Примеры

Некоторые опции сокета — целые числа с булевыми значениями, в этом случае setsockopt можно вызвать так:

sock.setsockopt(:SOCKET, :REUSEADDR, true)
sock.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
sock.setsockopt(Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true))

Некоторые опции сокета — целые числа с числовыми значениями, в этом случае setsockopt можно вызвать так:

sock.setsockopt(:IP, :TTL, 255)
sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255)
sock.setsockopt(Socket::Option.int(:INET, :IP, :TTL, 255))

Значения опций могут быть структурами. Передача их может быть сложной, так как это включает проверку ваших системных заголовков для определения правильного определения. Пример — ip_mreq, который может быть определён в ваших системных заголовках как:

struct ip_mreq {
  struct  in_addr imr_multiaddr;
  struct  in_addr imr_interface;
};

В этом случае setsockopt можно вызвать так:

optval = IPAddr.new("224.0.0.251").hton +
         IPAddr.new(Socket::INADDR_ANY, Socket::AF_INET).hton
sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, optval)
shutdown([how]) → 0 Показать исходный код
static VALUE
bsock_shutdown(int argc, VALUE *argv, VALUE sock)
{
    VALUE howto;
    int how;
    rb_io_t *fptr;

    rb_scan_args(argc, argv, "01", &howto);
    if (howto == Qnil)
        how = SHUT_RDWR;
    else {
        how = rsock_shutdown_how_arg(howto);
        if (how != SHUT_WR && how != SHUT_RD && how != SHUT_RDWR) {
            rb_raise(rb_eArgError, "`how' should be either :SHUT_RD, :SHUT_WR, :SHUT_RDWR");
        }
    }
    GetOpenFile(sock, fptr);
    if (shutdown(fptr->fd, how) == -1)
        rb_sys_fail("shutdown(2)");

    return INT2FIX(0);
}

Вызывает системный вызов shutdown(2).

s.shutdown(Socket::SHUT_RD) запрещает дальнейшее чтение.

s.shutdown(Socket::SHUT_WR) запрещает дальнейшую запись.

s.shutdown(Socket::SHUT_RDWR) запрещает дальнейшее чтение и запись.

how может быть символом или строкой:

  • :RD, :SHUT_RD, “RD” и “SHUT_RD” принимаются как Socket::SHUT_RD.

  • :WR, :SHUT_WR, “WR” и “SHUT_WR” принимаются как Socket::SHUT_WR.

  • :RDWR, :SHUT_RDWR, “RDWR” и “SHUT_RDWR” принимаются как Socket::SHUT_RDWR.

    UNIXSocket.pair {|s1, s2|

    s1.puts "ping"
    s1.shutdown(:WR)
    p s2.read          #=> "ping\n"
    s2.puts "pong"
    s2.close
    p s1.read          #=> "pong\n"
    

    }

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