класс BasicSocket
BasicSocket является базовым классом для всех Socket классов.
Публичные методы класса
static VALUE
bsock_do_not_rev_lookup(VALUE _)
{
return rsock_do_not_reverse_lookup?Qtrue:Qfalse;
} Получает глобальную do_not_reverse_lookup переменную.
BasicSocket.do_not_reverse_lookup #=> false
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
static VALUE
bsock_s_for_fd(VALUE klass, VALUE _descriptor)
{
rb_io_t *fptr;
int descriptor = RB_NUM2INT(_descriptor);
rsock_validate_descriptor(descriptor);
VALUE sock = rsock_init_sock(rb_obj_alloc(klass), descriptor);
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
Методы открытого экземпляра
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;
} Запрещает дальнейшее чтение с помощью системного вызова закрытия.
s1, s2 = UNIXSocket.pair s1.close_read s2.puts #=> Broken pipe (Errno::EPIPE)
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;
} Запрещает дальнейшую запись с помощью системного вызова закрытия.
UNIXSocket.pair {|s1, s2|
s1.print "ping"
s1.close_write
p s2.read #=> "ping"
s2.print "pong"
s2.close
p s1.read #=> "pong"
}
# File ext/socket/lib/socket.rb, line 251
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>]
}
}
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.
require 'socket'
BasicSocket.do_not_reverse_lookup = false
TCPSocket.open("www.ruby-lang.org", 80) {|sock|
p sock.do_not_reverse_lookup #=> false
}
BasicSocket.do_not_reverse_lookup = true
TCPSocket.open("www.ruby-lang.org", 80) {|sock|
p sock.do_not_reverse_lookup #=> true
}
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.
TCPSocket.open("www.ruby-lang.org", 80) {|sock|
p sock.do_not_reverse_lookup #=> true
p sock.peeraddr #=> ["AF_INET", 80, "221.186.184.68", "221.186.184.68"]
sock.do_not_reverse_lookup = false
p sock.peeraddr #=> ["AF_INET", 80, "carbon.ruby-lang.org", "54.163.249.195"]
}
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. Результатом является массив из двух элементов, содержащий эффективную uid и эффективную gid.
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
}
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 предпочтительнее бинарной строки, используйте BasicSocket#remote_address.
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 предпочтительнее бинарной строки, используйте BasicSocket#local_address.
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);
level = rsock_level_arg(family, lev);
option = rsock_optname_arg(family, level, optname);
len = 256;
#ifdef _AIX
switch (option) {
case SO_DEBUG:
case SO_REUSEADDR:
case SO_KEEPALIVE:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_OOBINLINE:
/* AIX doesn't set len for boolean options */
len = sizeof(int);
}
#endif
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.unpack1("i")
Значения параметров могут быть структурами. Их декодирование может быть сложным, поскольку оно включает в себя проверку заголовков вашей системы для определения правильного определения. Примером является +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
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 заполняется нулями.
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>
}
static VALUE
bsock_recv(int argc, VALUE *argv, VALUE sock)
{
return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
} Принимает сообщение.
maxlen — максимальное количество байтов для приёма.
flags должен быть побитовым ИЛИ констант Socket::MSG_*.
outbuf будет содержать только принятые данные после вызова метода, даже если он не пустой в начале.
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"
}
# File ext/socket/lib/socket.rb, line 371 def recv_nonblock(len, flag = 0, str = nil, exception: true) __recv_nonblock(len, flag, str, exception) end
Принимает до maxlen байтов из socket с помощью recvfrom(2) после установки O_NONBLOCK для базового дескриптора файла. flags — ноль или более опций MSG_. Результат, mesg, — принятые данные.
Когда recvfrom(2) возвращает 0, Socket#recv_nonblock возвращает пустую строку в качестве данных. Значение зависит от сокета: EOF в TCP, пустой пакет в UDP и т. д.
Параметры
-
maxlen— количество байтов для приёма с сокета -
flags— ноль или более опцийMSG_ -
buf— буфер назначенияString -
options— хеш ключевых слов, поддерживающий ‘исключение: false`
Пример
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.
BasicSocket#recv_nonblock может вызывать любую ошибку, соответствующую ошибке recvfrom(2), включая Errno::EWOULDBLOCK.
Если исключение Errno::EWOULDBLOCK или Errno::EAGAIN, оно дополняется IO::WaitReadable. Таким образом, IO::WaitReadable можно использовать для перехвата исключений для повторной попытки recv_nonblock.
Указав ключевой аргумент exception для false, вы можете указать, что recv_nonblock не должен генерировать исключение IO::WaitReadable, но вместо этого возвращает символ :wait_readable.
См. также
# File ext/socket/lib/socket.rb, line 426 def recvmsg(dlen = nil, flags = 0, clen = nil, scm_rights: false) __recvmsg(dlen, flags, clen, scm_rights) end
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_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
}
# File ext/socket/lib/socket.rb, line 442
def recvmsg_nonblock(dlen = nil, flags = 0, clen = nil,
scm_rights: false, exception: true)
__recvmsg_nonblock(dlen, flags, clen, scm_rights, exception)
end recvmsg получает сообщение с помощью системного вызова recvmsg(2) в режиме без блокировки.
Аналогично BasicSocket#recvmsg, но перед системным вызовом устанавливается флаг без блокировки, и системный вызов не повторяется.
Указав ключевое слово exception в false, можно указать, что recvmsg_nonblock не должен генерировать исключение IO::WaitReadable, а вместо этого возвращать символ :wait_readable.
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 заполнен нулями.
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>
}
VALUE
rsock_bsock_send(int argc, VALUE *argv, VALUE socket)
{
struct rsock_send_arg arg;
VALUE flags, to;
rb_io_t *fptr;
rb_blocking_function_t *func;
const char *funcname;
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;
funcname = "sendto(2)";
}
else {
func = rsock_send_blocking;
funcname = "send(2)";
}
RB_IO_POINTER(socket, fptr);
arg.fd = fptr->fd;
arg.flags = NUM2INT(flags);
while (true) {
#ifdef RSOCK_WAIT_BEFORE_BLOCKING
rb_io_wait(socket, RB_INT2NUM(RUBY_IO_WRITABLE), Qnil);
#endif
ssize_t n = (ssize_t)BLOCKING_REGION_FD(func, &arg);
if (n >= 0) return SSIZET2NUM(n);
if (rb_io_maybe_wait_writable(errno, socket, Qnil)) {
continue;
}
rb_sys_fail(funcname);
}
} Отправка 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
}
# File ext/socket/lib/socket.rb, line 303 def sendmsg(mesg, flags = 0, dest_sockaddr = nil, *controls) __sendmsg(mesg, flags, dest_sockaddr, controls) end
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)
# File ext/socket/lib/socket.rb, line 319
def sendmsg_nonblock(mesg, flags = 0, dest_sockaddr = nil, *controls,
exception: true)
__sendmsg_nonblock(mesg, flags, dest_sockaddr, controls, exception)
end sendmsg_nonblock отправляет сообщение с помощью системного вызова sendmsg(2) в режиме без блокировки.
Аналогично BasicSocket#sendmsg, но флаг без блокировки устанавливается перед системным вызовом, и системный вызов не повторяется.
Указав ключевое слово exception в false, можно указать, что sendmsg_nonblock не должен генерировать исключение IO::WaitWritable, а вместо этого возвращать символ :wait_writable.
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);
}
GetOpenFile(sock, fptr);
family = rsock_getfamily(fptr);
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— значение опции, передаваемое в underlying setsockopt() как указатель на определенное количество байтов. Способ передачи зависит от типа:-
Целое число: значение присваивается int, и указатель на int передаётся с длиной sizeof(int).
-
true или false: 1 или 0 (соответственно) присваивается int, и int передаётся как для
Integer. Обратите внимание, что нужно передавать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)
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–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.