Ruby 2.4

Addrinfo

class Addrinfo

Parent:Data

Addrinfo类映射struct addrinfo到红宝石。该结构标识Internet主机和服务。

公共类方法

foreach(nodename,service,family = nil,socktype = nil,protocol = nil,flags = nil,&block)显示源代码

遍历由:: getaddrinfo获取的Addrinfo对象列表。

Addrinfo.foreach(nil, 80) {|x| p x } #=> #<Addrinfo: 127.0.0.1:80 TCP (:80)> # #<Addrinfo: 127.0.0.1:80 UDP (:80)> # #<Addrinfo: [::1]:80 TCP (:80)> # #<Addrinfo: [::1]:80 UDP (:80)>

# File ext/socket/lib/socket.rb, line 225 def self.foreach(nodename, service, family=nil, socktype=nil, protocol=nil, flags=nil, &block) Addrinfo.getaddrinfo(nodename, service, family, socktype, protocol, flags).each(&block) end

getaddrinfo(nodename, service, family, socktype, protocol, flags) → addrinfo, ...()

getaddrinfo(nodename, service, family, socktype, protocol) → addrinfo, ...

getaddrinfo(nodename, service, family, socktype) → addrinfo, ...

getaddrinfo(nodename, service, family) → addrinfo, ...

getaddrinfo(nodename, service) → addrinfo, ...

以数组形式返回addrinfo对象的列表。

此方法将节点名(主机名)和服务(端口)转换为addrinfo。由于转换不是唯一的,因此结果是addrinfo对象的列表。

如果不需要转换,nodename或service可以为零。

家庭,袜型和协议暗示首选协议。如果结果将用于带SOCK_STREAM的套接字​​,则应将SOCK_STREAM指定为socktype。如果是这样,:: getaddrinfo返回适合于SOCK_STREAM的addrinfo列表。如果它们被省略或零,则结果不受限制。

同样,PF_INET6作为家庭限制了IPv6。

标志应该是按位OR或者Socket :: AI _?常量如下。请注意,常量的确切列表取决于操作系统。

AI_PASSIVE Get address to use with bind() AI_CANONNAME Fill in the canonical name AI_NUMERICHOST Prevent host name resolution AI_NUMERICSERV Prevent service name resolution AI_V4MAPPED Accept IPv4-mapped IPv6 addresses AI_ALL Allow all addresses AI_ADDRCONFIG Accept only if any address is assigned

请注意,只要应用程序知道地址的用法,就应该指定socktype。当socktype被省略并且servname被指定为一个整数时,某些平台会导致错误,因为例如某些端口号512是不明确的,没有socktype。

Addrinfo.getaddrinfo("www.kame.net", 80, nil, :STREAM) #=> [#<Addrinfo: 203.178.141.194:80 TCP (www.kame.net)>, # #<Addrinfo: [2001:200:dff:fff1:216:3eff:feb1:44d7]:80 TCP (www.kame.net)>]

static VALUE addrinfo_s_getaddrinfo(int argc, VALUE *argv, VALUE self) { VALUE node, service, family, socktype, protocol, flags; rb_scan_args(argc, argv, "24", &node, &service, &family, &socktype, &protocol, &flags return addrinfo_list_new(node, service, family, socktype, protocol, flags }

ip(host) → addrinfo Show source

为IP地址返回一个addrinfo对象。

结果的端口,socktype,协议由零填充。所以,创建套接字是不合适的。

Addrinfo.ip("localhost") #=> #<Addrinfo: 127.0.0.1 (localhost)>

static VALUE addrinfo_s_ip(VALUE self, VALUE host) { VALUE ret; rb_addrinfo_t *rai; ret = addrinfo_firstonly_new(host, Qnil, INT2NUM(PF_UNSPEC), INT2FIX(0), INT2FIX(0), INT2FIX(0) rai = get_addrinfo(ret rai->socktype = 0; rai->protocol = 0; return ret; }

new(sockaddr) → addrinfo Show source

new(sockaddr, family) → addrinfo

new(sockaddr, family, socktype) → addrinfo

new(sockaddr, family, socktype, protocol) → addrinfo

返回Addrinfo的新实例。该实例包含sockaddr,family,socktype,协议。sockaddr表示可用于连接(2)等的struct sockaddr。family,socktype和protocol是用于socket(2)的参数的整数。

sockaddr被指定为数组或字符串。该阵列应与IPSocket#addr或UNIXSocket#addr的值兼容。该字符串应该是由Socket.sockaddr_in或Socket.unpack_sockaddr_un生成的struct sockaddr。

sockaddr例子:

  • “AF_INET”, 46102, “localhost.localdomain”, “127.0.0.1”

  • “AF_INET6”, 42304, “ip6-localhost”, “::1”

  • “AF_UNIX”, “/tmp/sock”

  • Socket.sockaddr_in(“smtp”, “2001:DB8::1”)

  • Socket.sockaddr_in(80, “172.18.22.42”)

  • Socket.sockaddr_in(80, “www.ruby-lang.org”)

  • Socket.sockaddr_un(“/tmp/sock”)

在AF_INET / AF_INET6 sockaddr数组中,第4个元素(数字IP地址)用于在Addrinfo实例中构造套接字地址。如果第三个元素(文本主机名称)不为零,它也会被记录下来,但仅用于#inspect。

family被指定为一个整数来指定协议族,例如Socket :: PF_INET。它可以是一个符号或字符串,它是带或不带PF_前缀的常数名称,例如:INET,:INET6,:UNIX,“PF_INET”等。如果省略,则假定为PF_UNSPEC。

socktype被指定为一个整数来指定套接字类型,例如Socket :: SOCK_STREAM。它可以是一个符号或字符串,它是带或不带SOCK_前缀的常数名称,如:STREAM,:DGRAM,:RAW,“SOCK_STREAM”等。如果省略,则假定为0。

协议被指定为一个整数来指定协议,例如Socket :: IPPROTO_TCP。它必须是一个整数,不像家庭和袜子类型。如果省略,则假定为0。请注意,对于大多数协议来说,0是合理的值,除了原始套接字。

static VALUE addrinfo_initialize(int argc, VALUE *argv, VALUE self) { rb_addrinfo_t *rai; VALUE sockaddr_arg, sockaddr_ary, pfamily, socktype, protocol; int i_pfamily, i_socktype, i_protocol; struct sockaddr *sockaddr_ptr; socklen_t sockaddr_len; VALUE canonname = Qnil, inspectname = Qnil; if (check_addrinfo(self)) rb_raise(rb_eTypeError, "already initialized socket address" DATA_PTR(self) = rai = alloc_addrinfo( rb_scan_args(argc, argv, "13", &sockaddr_arg, &pfamily, &socktype, &protocol i_pfamily = NIL_P(pfamily) ? PF_UNSPEC : rsock_family_arg(pfamily i_socktype = NIL_P(socktype) ? 0 : rsock_socktype_arg(socktype i_protocol = NIL_P(protocol) ? 0 : NUM2INT(protocol sockaddr_ary = rb_check_array_type(sockaddr_arg if (!NIL_P(sockaddr_ary)) { VALUE afamily = rb_ary_entry(sockaddr_ary, 0 int af; StringValue(afamily if (rsock_family_to_int(RSTRING_PTR(afamily), RSTRING_LEN(afamily), &af) == -1) rb_raise(rb_eSocket, "unknown address family: %s", StringValueCStr(afamily) switch (af) { case AF_INET: /* ["AF_INET", 46102, "localhost.localdomain", "127.0.0.1"] */ #ifdef INET6 case AF_INET6: /* ["AF_INET6", 42304, "ip6-localhost", "::1"] */ #endif { VALUE service = rb_ary_entry(sockaddr_ary, 1 VALUE nodename = rb_ary_entry(sockaddr_ary, 2 VALUE numericnode = rb_ary_entry(sockaddr_ary, 3 int flags; service = INT2NUM(NUM2INT(service) if (!NIL_P(nodename)) StringValue(nodename StringValue(numericnode flags = AI_NUMERICHOST; #ifdef AI_NUMERICSERV flags |= AI_NUMERICSERV; #endif init_addrinfo_getaddrinfo(rai, numericnode, service, INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol), INT2NUM(flags), nodename, service break; } #ifdef HAVE_SYS_UN_H case AF_UNIX: /* ["AF_UNIX", "/tmp/sock"] */ { VALUE path = rb_ary_entry(sockaddr_ary, 1 StringValue(path init_unix_addrinfo(rai, path, SOCK_STREAM break; } #endif default: rb_raise(rb_eSocket, "unexpected address family" } } else { StringValue(sockaddr_arg sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg init_addrinfo(rai, sockaddr_ptr, sockaddr_len, i_pfamily, i_socktype, i_protocol, canonname, inspectname } return self; }

tcp(host, port) → addrinfo Show source

为TCP地址返回一个addrinfo对象。

Addrinfo.tcp("localhost", "smtp") #=> #<Addrinfo: 127.0.0.1:25 TCP (localhost:smtp)>

static VALUE addrinfo_s_tcp(VALUE self, VALUE host, VALUE port) { return addrinfo_firstonly_new(host, port, INT2NUM(PF_UNSPEC), INT2NUM(SOCK_STREAM), INT2NUM(IPPROTO_TCP), INT2FIX(0) }

udp(host, port) → addrinfo Show source

为UDP地址返回一个addrinfo对象。

Addrinfo.udp("localhost", "daytime") #=> #<Addrinfo: 127.0.0.1:13 UDP (localhost:daytime)>

static VALUE addrinfo_s_udp(VALUE self, VALUE host, VALUE port) { return addrinfo_firstonly_new(host, port, INT2NUM(PF_UNSPEC), INT2NUM(SOCK_DGRAM), INT2NUM(IPPROTO_UDP), INT2FIX(0) }

unix(path , socktype) → addrinfo Show source

为UNIX套接字地址返回一个addrinfo对象。

socktype指定套接字类型。如果省略,则使用STREAM。

Addrinfo.unix("/tmp/sock") #=> #<Addrinfo: /tmp/sock SOCK_STREAM> Addrinfo.unix("/tmp/sock", :DGRAM) #=> #<Addrinfo: /tmp/sock SOCK_DGRAM>

static VALUE addrinfo_s_unix(int argc, VALUE *argv, VALUE self) { VALUE path, vsocktype, addr; int socktype; rb_addrinfo_t *rai; rb_scan_args(argc, argv, "11", &path, &vsocktype if (NIL_P(vsocktype)) socktype = SOCK_STREAM; else socktype = rsock_socktype_arg(vsocktype addr = addrinfo_s_allocate(rb_cAddrinfo DATA_PTR(addr) = rai = alloc_addrinfo( init_unix_addrinfo(rai, path, socktype OBJ_INFECT(addr, path return addr; }

公共实例方法

afamily → integer Show source

以整数形式返回地址族。

Addrinfo.tcp("localhost", 80).afamily == Socket::AF_INET #=> true

static VALUE addrinfo_afamily(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self return INT2NUM(ai_get_afamily(rai) }

bind() { |sock| ... } Show source

创建一个绑定到自己的套接字。

如果给出了一个块,则使用套接字调用该块,并返回该块的值。否则返回套接字。

Addrinfo.udp("0.0.0.0", 9981).bind {|s| s.local_address.connect {|s| s.send "hello", 0 } p s.recv(10) #=> "hello" }

# File ext/socket/lib/socket.rb, line 173 def bind sock = Socket.new(self.pfamily, self.socktype, self.protocol) begin sock.ipv6only! if self.ipv6? sock.setsockopt(:SOCKET, :REUSEADDR, 1) sock.bind(self) rescue Exception sock.close raise end if block_given? begin yield sock ensure sock.close end else sock end end

canonname → string or nil Show source

以字符串形式返回规范名称。

如果没有规范名称,则返回nil。

当指定AI_CANONNAME时,规范名称由:: getaddrinfo设置。

list = Addrinfo.getaddrinfo("www.ruby-lang.org", 80, :INET, :STREAM, nil, Socket::AI_CANONNAME) p list[0] #=> #<Addrinfo: 221.186.184.68:80 TCP carbon.ruby-lang.org (www.ruby-lang.org)> p list[0].canonname #=> "carbon.ruby-lang.org"

static VALUE addrinfo_canonname(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self return rai->canonname; }

connect(opts) {|socket| ... } Show source

connect(opts)

创建一个连接到自己地址的套接字。

可选参数opts是由散列表示的选项。opts可能有以下选项:

:timeout

指定以秒为单位的超时。

如果给出了一个块,则使用套接字调用该块,并返回该块的值。否则返回套接字。

Addrinfo.tcp("www.ruby-lang.org", 80).connect {|s| s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n" puts s.read }

# File ext/socket/lib/socket.rb, line 135 def connect(timeout: nil, &block) connect_internal(nil, timeout, &block) end

connect_from(local_addr_args, opts) {|socket| ... } Show source

connect_from(local_addr_args, opts)

创建一个连接到自己地址的套接字。

如果一个或多个参数为local_addr_args,则将其用作套接字的本地地址。local_addr_args被赋予#family_addrinfo以获取实际地址。

如果没有给出local_addr_args,则套接字的本地地址未被绑定。

可选的最后一个参数opts是由散列表示的选项。opts可能有以下选项:

:timeout

指定以秒为单位的超时。

如果给出了一个块,则使用套接字调用该块,并返回该块的值。否则返回套接字。

Addrinfo.tcp("www.ruby-lang.org", 80).connect_from("0.0.0.0", 4649) {|s| s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n" puts s.read } # Addrinfo object can be taken for the argument. Addrinfo.tcp("www.ruby-lang.org", 80).connect_from(Addrinfo.tcp("0.0.0.0", 4649)) {|s| s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n" puts s.read }

# File ext/socket/lib/socket.rb, line 112 def connect_from(*args, timeout: nil, &block) connect_internal(family_addrinfo(*args), timeout, &block) end

connect_to(remote_addr_args, opts) {|socket| ... } Show source

connect_to(remote_addr_args, opts)

创建一个连接到remote_addr_args并绑定到自己的套接字。

可选的最后一个参数opts是由散列表示的选项。opts可能有以下选项:

:timeout

指定以秒为单位的超时。

如果给出了一个块,则使用套接字调用该块,并返回该块的值。否则返回套接字。

Addrinfo.tcp("0.0.0.0", 4649).connect_to("www.ruby-lang.org", 80) {|s| s.print "GET / HTTP/1.0\r\nHost: www.ruby-lang.org\r\n\r\n" puts s.read }

# File ext/socket/lib/socket.rb, line 158 def connect_to(*args, timeout: nil, &block) remote_addrinfo = family_addrinfo(*args) remote_addrinfo.send(:connect_internal, self, timeout, &block) end

family_addrinfo(*args) Show source

从参数创建一个Addrinfo对象。

这些论据被解释为与自我相似。

Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("www.ruby-lang.org", 80) #=> #<Addrinfo: 221.186.184.68:80 TCP (www.ruby-lang.org:80)> Addrinfo.unix("/tmp/sock").family_addrinfo("/tmp/sock2") #=> #<Addrinfo: /tmp/sock2 SOCK_STREAM>

# File ext/socket/lib/socket.rb, line 16 def family_addrinfo(*args) if args.empty? raise ArgumentError, "no address specified" elsif Addrinfo === args.first raise ArgumentError, "too many arguments" if args.length != 1 addrinfo = args.first if (self.pfamily != addrinfo.pfamily) || (self.socktype != addrinfo.socktype) raise ArgumentError, "Addrinfo type mismatch" end addrinfo elsif self.ip? raise ArgumentError, "IP address needs host and port but #{args.length} arguments given" if args.length != 2 host, port = args Addrinfo.getaddrinfo(host, port, self.pfamily, self.socktype, self.protocol)[0] elsif self.unix? raise ArgumentError, "UNIX socket needs single path argument but #{args.length} arguments given" if args.length != 1 path, = args Addrinfo.unix(path) else raise ArgumentError, "unexpected family" end end

getnameinfo → nodename, service()

getnameinfo(flags) → nodename, service

以一对字符串的形式返回nodename和service。这将addrinfo中的struct sockaddr转换为文本表示。

标志应该是按位OR的Socket :: NI _ ??? 常量。

Addrinfo.tcp("127.0.0.1", 80).getnameinfo #=> ["localhost", "www"] Addrinfo.tcp("127.0.0.1", 80).getnameinfo(Socket::NI_NUMERICSERV) #=> ["localhost", "80"]

static VALUE addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self VALUE vflags; char hbuf[1024], pbuf[1024]; int flags, error; rb_scan_args(argc, argv, "01", &vflags flags = NIL_P(vflags) ? 0 : NUM2INT(vflags if (rai->socktype == SOCK_DGRAM) flags |= NI_DGRAM; error = getnameinfo(&rai->addr.addr, rai->sockaddr_len, hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf), flags if (error) { rsock_raise_socket_error("getnameinfo", error } return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf) }

inspect → string Show source

返回一个以可读形式显示addrinfo的字符串。

Addrinfo.tcp("localhost", 80).inspect #=> "#<Addrinfo: 127.0.0.1:80 TCP (localhost)>" Addrinfo.unix("/tmp/sock").inspect #=> "#<Addrinfo: /tmp/sock SOCK_STREAM>"

static VALUE addrinfo_inspect(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self int internet_p; VALUE ret; ret = rb_sprintf("#<%s: ", rb_obj_classname(self) inspect_sockaddr(self, ret if (rai->pfamily && ai_get_afamily(rai) != rai->pfamily) { ID id = rsock_intern_protocol_family(rai->pfamily if (id) rb_str_catf(ret, " %s", rb_id2name(id) else rb_str_catf(ret, " PF_\?\?\?(%d)", rai->pfamily } internet_p = rai->pfamily == PF_INET; #ifdef INET6 internet_p = internet_p || rai->pfamily == PF_INET6; #endif if (internet_p && rai->socktype == SOCK_STREAM && (rai->protocol == 0 || rai->protocol == IPPROTO_TCP)) { rb_str_cat2(ret, " TCP" } else if (internet_p && rai->socktype == SOCK_DGRAM && (rai->protocol == 0 || rai->protocol == IPPROTO_UDP)) { rb_str_cat2(ret, " UDP" } else { if (rai->socktype) { ID id = rsock_intern_socktype(rai->socktype if (id) rb_str_catf(ret, " %s", rb_id2name(id) else rb_str_catf(ret, " SOCK_\?\?\?(%d)", rai->socktype } if (rai->protocol) { if (internet_p) { ID id = rsock_intern_ipproto(rai->protocol if (id) rb_str_catf(ret, " %s", rb_id2name(id) else goto unknown_protocol; } else { unknown_protocol: rb_str_catf(ret, " UNKNOWN_PROTOCOL(%d)", rai->protocol } } } if (!NIL_P(rai->canonname)) { VALUE name = rai->canonname; rb_str_catf(ret, " %s", StringValueCStr(name) } if (!NIL_P(rai->inspectname)) { VALUE name = rai->inspectname; rb_str_catf(ret, " (%s)", StringValueCStr(name) } rb_str_buf_cat2(ret, ">" return ret; }

inspect_sockaddr → string Show source

返回一个字符串,它以可读的形式显示addrinfo中的sockaddr 。

Addrinfo.tcp("localhost", 80).inspect_sockaddr #=> "127.0.0.1:80" Addrinfo.tcp("ip6-localhost", 80).inspect_sockaddr #=> "[::1]:80" Addrinfo.unix("/tmp/sock").inspect_sockaddr #=> "/tmp/sock"

VALUE rsock_addrinfo_inspect_sockaddr(VALUE self) { return inspect_sockaddr(self, rb_str_new("", 0) }

ip? → true or false Show source

如果addrinfo是Internet(IPv4 / IPv6)地址,则返回true。否则返回false。

Addrinfo.tcp("127.0.0.1", 80).ip? #=> true Addrinfo.tcp("::1", 80).ip? #=> true Addrinfo.unix("/tmp/sock").ip? #=> false

static VALUE addrinfo_ip_p(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self int family = ai_get_afamily(rai return IS_IP_FAMILY(family) ? Qtrue : Qfalse; }

ip_address → string Show source

以字符串形式返回IP地址。

Addrinfo.tcp("127.0.0.1", 80).ip_address #=> "127.0.0.1" Addrinfo.tcp("::1", 80).ip_address #=> "::1"

static VALUE addrinfo_ip_address(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self int family = ai_get_afamily(rai VALUE vflags; VALUE ret; if (!IS_IP_FAMILY(family)) rb_raise(rb_eSocket, "need IPv4 or IPv6 address" vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV ret = addrinfo_getnameinfo(1, &vflags, self return rb_ary_entry(ret, 0 }

ip_port → port Show source

以整数形式返回端口号。

Addrinfo.tcp("127.0.0.1", 80).ip_port #=> 80 Addrinfo.tcp("::1", 80).ip_port #=> 80

static VALUE addrinfo_ip_port(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self int family = ai_get_afamily(rai int port; if (!IS_IP_FAMILY(family)) { bad_family: #ifdef AF_INET6 rb_raise(rb_eSocket, "need IPv4 or IPv6 address" #else rb_raise(rb_eSocket, "need IPv4 address" #endif } switch (family) { case AF_INET: if (rai->sockaddr_len != sizeof(struct sockaddr_in)) rb_raise(rb_eSocket, "unexpected sockaddr size for IPv4" port = ntohs(rai->addr.in.sin_port break; #ifdef AF_INET6 case AF_INET6: if (rai->sockaddr_len != sizeof(struct sockaddr_in6)) rb_raise(rb_eSocket, "unexpected sockaddr size for IPv6" port = ntohs(rai->addr.in6.sin6_port break; #endif default: goto bad_family; } return INT2NUM(port }

ip_unpack → addr, port()

以2元素数组的形式返回IP地址和端口号。

Addrinfo.tcp("127.0.0.1", 80).ip_unpack #=> ["127.0.0.1", 80] Addrinfo.tcp("::1", 80).ip_unpack #=> ["::1", 80]

static VALUE addrinfo_ip_unpack(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self int family = ai_get_afamily(rai VALUE vflags; VALUE ret, portstr; if (!IS_IP_FAMILY(family)) rb_raise(rb_eSocket, "need IPv4 or IPv6 address" vflags = INT2NUM(NI_NUMERICHOST|NI_NUMERICSERV ret = addrinfo_getnameinfo(1, &vflags, self portstr = rb_ary_entry(ret, 1 rb_ary_store(ret, 1, INT2NUM(atoi(StringValueCStr(portstr))) return ret; }

ipv4? → true or false Show source

如果addrinfo是IPv4地址,则返回true。否则返回false。

Addrinfo.tcp("127.0.0.1", 80).ipv4? #=> true Addrinfo.tcp("::1", 80).ipv4? #=> false Addrinfo.unix("/tmp/sock").ipv4? #=> false

static VALUE addrinfo_ipv4_p(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self return ai_get_afamily(rai) == AF_INET ? Qtrue : Qfalse; }

ipv4_loopback?() Show source

对于IPv4环回地址(127.0.0.0/8),返回true。否则返回false。

static VALUE addrinfo_ipv4_loopback_p(VALUE self) { uint32_t a; if (!extract_in_addr(self, &a)) return Qfalse; if ((a & 0xff000000) == 0x7f000000) /* 127.0.0.0/8 */ return Qtrue; return Qfalse; }

ipv4_multicast?() Show source

对于IPv4多播地址(224.0.0.0/4),返回true。否则返回false。

static VALUE addrinfo_ipv4_multicast_p(VALUE self) { uint32_t a; if (!extract_in_addr(self, &a)) return Qfalse; if ((a & 0xf0000000) == 0xe0000000) /* 224.0.0.0/4 */ return Qtrue; return Qfalse; }

ipv4_private?() Show source

对IPv4专用地址(10.0.0.0/8,172.16.0.0/12,192.168.0.0/16)返回true。否则返回false。

static VALUE addrinfo_ipv4_private_p(VALUE self) { uint32_t a; if (!extract_in_addr(self, &a)) return Qfalse; if ((a & 0xff000000) == 0x0a000000 || /* 10.0.0.0/8 */ (a & 0xfff00000) == 0xac100000 || /* 172.16.0.0/12 */ (a & 0xffff0000) == 0xc0a80000) /* 192.168.0.0/16 */ return Qtrue; return Qfalse; }

ipv6? → true or false Show source

如果addrinfo是IPv6地址,则返回true。否则返回false。

Addrinfo.tcp("127.0.0.1", 80).ipv6? #=> false Addrinfo.tcp("::1", 80).ipv6? #=> true Addrinfo.unix("/tmp/sock").ipv6? #=> false

static VALUE addrinfo_ipv6_p(VALUE self) { #ifdef AF_INET6 rb_addrinfo_t *rai = get_addrinfo(self return ai_get_afamily(rai) == AF_INET6 ? Qtrue : Qfalse; #else return Qfalse; #endif }

ipv6_linklocal?() Show source

IPv6链接本地地址(ff80 :: / 10)返回true。否则返回false。

static VALUE addrinfo_ipv6_linklocal_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_LINKLOCAL(addr)) return Qtrue; return Qfalse; }

ipv6_loopback?() Show source

对于IPv6回送地址(:: 1)返回true。否则返回false。

static VALUE addrinfo_ipv6_loopback_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_LOOPBACK(addr)) return Qtrue; return Qfalse; }

ipv6_mc_global?() Show source

IPv6多播全局范围地址返回true。否则返回false。

static VALUE addrinfo_ipv6_mc_global_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_MC_GLOBAL(addr)) return Qtrue; return Qfalse; }

ipv6_mc_linklocal?() Show source

对IPv6多播链路本地范围地址返回true。否则返回false。

static VALUE addrinfo_ipv6_mc_linklocal_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_MC_LINKLOCAL(addr)) return Qtrue; return Qfalse; }

ipv6_mc_nodelocal?() Show source

对IPv6多播节点本地范围地址返回true。否则返回false。

static VALUE addrinfo_ipv6_mc_nodelocal_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_MC_NODELOCAL(addr)) return Qtrue; return Qfalse; }

ipv6_mc_orglocal?() Show source

对IPv6多播组织本地范围地址返回true。否则返回false。

static VALUE addrinfo_ipv6_mc_orglocal_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_MC_ORGLOCAL(addr)) return Qtrue; return Qfalse; }

ipv6_mc_sitelocal?() Show source

IPv6多播站点本地范围地址返回true。否则返回false。

static VALUE addrinfo_ipv6_mc_sitelocal_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_MC_SITELOCAL(addr)) return Qtrue; return Qfalse; }

ipv6_multicast?() Show source

IPv6多播地址(ff00 :: / 8)返回true。否则返回false。

static VALUE addrinfo_ipv6_multicast_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_MULTICAST(addr)) return Qtrue; return Qfalse; }

ipv6_sitelocal?() Show source

对IPv6站点本地地址(ffc0 :: / 10)返回true。否则返回false。

static VALUE addrinfo_ipv6_sitelocal_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_SITELOCAL(addr)) return Qtrue; return Qfalse; }

ipv6_to_ipv4() Show source

返回IPv4映射/兼容IPv6地址的IPv4地址。如果self不是IPv4映射/兼容IPv6地址,则返回nil 。

Addrinfo.ip("::192.0.2.3").ipv6_to_ipv4 #=> #<Addrinfo: 192.0.2.3> Addrinfo.ip("::ffff:192.0.2.3").ipv6_to_ipv4 #=> #<Addrinfo: 192.0.2.3> Addrinfo.ip("::1").ipv6_to_ipv4 #=> nil Addrinfo.ip("192.0.2.3").ipv6_to_ipv4 #=> nil Addrinfo.unix("/tmp/sock").ipv6_to_ipv4 #=> nil

static VALUE addrinfo_ipv6_to_ipv4(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self struct in6_addr *addr; int family = ai_get_afamily(rai if (family != AF_INET6) return Qnil; addr = &rai->addr.in6.sin6_addr; if (IN6_IS_ADDR_V4MAPPED(addr) || IN6_IS_ADDR_V4COMPAT(addr)) { struct sockaddr_in sin4; INIT_SOCKADDR_IN(&sin4, sizeof(sin4) memcpy(&sin4.sin_addr, (char*)addr + sizeof(*addr) - sizeof(sin4.sin_addr), sizeof(sin4.sin_addr) return rsock_addrinfo_new((struct sockaddr *)&sin4, (socklen_t)sizeof(sin4), PF_INET, rai->socktype, rai->protocol, rai->canonname, rai->inspectname } else { return Qnil; } }

ipv6_unique_local?() Show source

对于IPv6唯一本地地址(fc00 :: / 7,RFC4193)返回true。否则返回false。

static VALUE addrinfo_ipv6_unique_local_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_UNIQUE_LOCAL(addr)) return Qtrue; return Qfalse; }

ipv6_unspecified?() Show source

对IPv6未指定地址(::)返回true。否则返回false。

static VALUE addrinfo_ipv6_unspecified_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_UNSPECIFIED(addr)) return Qtrue; return Qfalse; }

ipv6_v4compat?() Show source

对IPv4兼容的IPv6地址(:: / 80)返回true。否则返回false。

static VALUE addrinfo_ipv6_v4compat_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_V4COMPAT(addr)) return Qtrue; return Qfalse; }

ipv6_v4mapped?() Show source

对IPv4映射的IPv6地址(:: ffff:0:0/80)返回true。否则返回false。

static VALUE addrinfo_ipv6_v4mapped_p(VALUE self) { struct in6_addr *addr = extract_in6_addr(self if (addr && IN6_IS_ADDR_V4MAPPED(addr)) return Qtrue; return Qfalse; }

listen(backlog=Socket::SOMAXCONN) { |sock| ... } Show source

创建一个绑定到自己的侦听套接字。

# File ext/socket/lib/socket.rb, line 195 def listen(backlog=Socket::SOMAXCONN) sock = Socket.new(self.pfamily, self.socktype, self.protocol) begin sock.ipv6only! if self.ipv6? sock.setsockopt(:SOCKET, :REUSEADDR, 1) sock.bind(self) sock.listen(backlog) rescue Exception sock.close raise end if block_given? begin yield sock ensure sock.close end else sock end end

pfamily → integer Show source

以整数形式返回协议族。

Addrinfo.tcp("localhost", 80).pfamily == Socket::PF_INET #=> true

static VALUE addrinfo_pfamily(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self return INT2NUM(rai->pfamily }

protocol → integer Show source

以整数形式返回套接字类型。

Addrinfo.tcp("localhost", 80).protocol == Socket::IPPROTO_TCP #=> true

static VALUE addrinfo_protocol(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self return INT2NUM(rai->protocol }

socktype → integer Show source

以整数形式返回套接字类型。

Addrinfo.tcp("localhost", 80).socktype == Socket::SOCK_STREAM #=> true

static VALUE addrinfo_socktype(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self return INT2NUM(rai->socktype }

to_sockaddr → string Show source

to_s → string

以套装结构sockaddr字符串的形式返回套接字地址。

Addrinfo.tcp("localhost", 80).to_sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"

static VALUE addrinfo_to_sockaddr(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self VALUE ret; ret = rb_str_new((char*)&rai->addr, rai->sockaddr_len OBJ_INFECT(ret, self return ret; }

to_sockaddr → string Show source

以套装结构sockaddr字符串的形式返回套接字地址。

Addrinfo.tcp("localhost", 80).to_sockaddr #=> "\x02\x00\x00P\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"

static VALUE addrinfo_to_sockaddr(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self VALUE ret; ret = rb_str_new((char*)&rai->addr, rai->sockaddr_len OBJ_INFECT(ret, self return ret; }

unix? → true or false Show source

如果addrinfo是UNIX地址,则返回true。否则返回false。

Addrinfo.tcp("127.0.0.1", 80).unix? #=> false Addrinfo.tcp("::1", 80).unix? #=> false Addrinfo.unix("/tmp/sock").unix? #=> true

static VALUE addrinfo_unix_p(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self #ifdef AF_UNIX return ai_get_afamily(rai) == AF_UNIX ? Qtrue : Qfalse; #else return Qfalse; #endif }

unix_path → path Show source

以字符串形式返回套接字路径。

Addrinfo.unix("/tmp/sock").unix_path #=> "/tmp/sock"

static VALUE addrinfo_unix_path(VALUE self) { rb_addrinfo_t *rai = get_addrinfo(self int family = ai_get_afamily(rai struct sockaddr_un *addr; char *s, *e; if (family != AF_UNIX) rb_raise(rb_eSocket, "need AF_UNIX address" addr = &rai->addr.un; s = addr->sun_path; e = (char*)addr + rai->sockaddr_len; if (e < s) rb_raise(rb_eSocket, "too short AF_UNIX address: %"PRIuSIZE" bytes given for minimum %"PRIuSIZE" bytes.", (size_t)rai->sockaddr_len, (size_t)(s - (char *)addr) if (addr->sun_path + sizeof(addr->sun_path) < e) rb_raise(rb_eSocket, "too long AF_UNIX path (%"PRIuSIZE" bytes given but %"PRIuSIZE" bytes max)", (size_t)(e - addr->sun_path), sizeof(addr->sun_path) while (s < e && *(e-1) == '\0') e--; return rb_str_new(s, e-s }

私有实例方法

connect_internal(local_addrinfo,timeout = nil){| socket | ...}显示源文件

创建一个连接到地址的新Socket local_addrinfo

如果local_addrinfo为零,则套接字的地址未被绑定。

超时指定秒超时。发生超时时会引发Errno :: ETIMEDOUT。

如果给出了一个块,则为每个地址生成创建的套接字。

# File ext/socket/lib/socket.rb, line 49 def connect_internal(local_addrinfo, timeout=nil) # :yields: socket sock = Socket.new(self.pfamily, self.socktype, self.protocol) begin sock.ipv6only! if self.ipv6? sock.bind local_addrinfo if local_addrinfo if timeout case sock.connect_nonblock(self, exception: false) when 0 # success or EISCONN, other errors raise break when :wait_writable sock.wait_writable(timeout) or raise Errno::ETIMEDOUT, 'user specified timeout' end while true else sock.connect(self) end rescue Exception sock.close raise end if block_given? begin yield sock ensure sock.close end else sock end end