Ruby 2.4

UNIXSocket

UNIXSocket类

Parent:BasicSocket

UNIXSocket表示一个UNIX域流客户端套接字。

公共类方法

new(path) → unixsocket Show source

创建连接到路径 的新的UNIX客户端套接字。

require 'socket' s = UNIXSocket.new("/tmp/sock") s.send "hello", 0

static VALUE unix_init(VALUE sock, VALUE path) { return rsock_init_unixsock(sock, path, 0 }

pair([type , protocol]) → unixsocket1, unixsocket2()

创建一对互相连接的socket。

socktype应该是一个套接字类型,例如::STREAM,:DGRAM,:RAW等。

协议应该是在域中定义的协议。0是域的默认协议

s1, s2 = UNIXSocket.pair s1.send "a", 0 s1.send "b", 0 p s2.recv(10) #=> "ab"

static VALUE unix_s_socketpair(int argc, VALUE *argv, VALUE klass) { VALUE domain, type, protocol; VALUE args[3]; domain = INT2FIX(PF_UNIX rb_scan_args(argc, argv, "02", &type, &protocol if (argc == 0) type = INT2FIX(SOCK_STREAM if (argc <= 1) protocol = INT2FIX(0 args[0] = domain; args[1] = type; args[2] = protocol; return rsock_sock_s_socketpair(3, args, klass }

socketpair([type , protocol]) → unixsocket1, unixsocket2()

创建一对互相连接的插座。

socktype 应该是一个套接字类型,例如::STREAM,:DGRAM,:RAW等。

protocol 应该是在域中定义的协议。0是域的默认协议。

s1, s2 = UNIXSocket.pair s1.send "a", 0 s1.send "b", 0 p s2.recv(10) #=> "ab"

static VALUE unix_s_socketpair(int argc, VALUE *argv, VALUE klass) { VALUE domain, type, protocol; VALUE args[3]; domain = INT2FIX(PF_UNIX rb_scan_args(argc, argv, "02", &type, &protocol if (argc == 0) type = INT2FIX(SOCK_STREAM if (argc <= 1) protocol = INT2FIX(0 args[0] = domain; args[1] = type; args[2] = protocol; return rsock_sock_s_socketpair(3, args, klass }

公共实例方法

addr → address_family, unix_path()

以包含address_family和unix_path的数组的形式返回本地地址。

serv = UNIXServer.new("/tmp/sock") p serv.addr #=> ["AF_UNIX", "/tmp/sock"]

static VALUE unix_addr(VALUE sock) { rb_io_t *fptr; struct sockaddr_un addr; socklen_t len = (socklen_t)sizeof addr; socklen_t len0 = len; GetOpenFile(sock, fptr if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0) rsock_sys_fail_path("getsockname(2)", fptr->pathv if (len0 < len) len = len0; return rsock_unixaddr(&addr, len }

path → path Show source

返回unixsocket本地地址的路径。

s = UNIXServer.new("/tmp/sock") p s.path #=> "/tmp/sock"

static VALUE unix_path(VALUE sock) { rb_io_t *fptr; GetOpenFile(sock, fptr if (NIL_P(fptr->pathv)) { struct sockaddr_un addr; socklen_t len = (socklen_t)sizeof(addr socklen_t len0 = len; if (getsockname(fptr->fd, (struct sockaddr*)&addr, &len) < 0) rsock_sys_fail_path("getsockname(2)", fptr->pathv if (len0 < len) len = len0; fptr->pathv = rb_obj_freeze(rsock_unixpath_str(&addr, len) } return rb_str_dup(fptr->pathv }

peeraddr → address_family, unix_path()

以包含address_family和unix_path的数组的形式返回远程地址。

serv = UNIXServer.new("/tmp/sock") c = UNIXSocket.new("/tmp/sock") p c.peeraddr #=> ["AF_UNIX", "/tmp/sock"]

static VALUE unix_peeraddr(VALUE sock) { rb_io_t *fptr; struct sockaddr_un addr; socklen_t len = (socklen_t)sizeof addr; socklen_t len0 = len; GetOpenFile(sock, fptr if (getpeername(fptr->fd, (struct sockaddr*)&addr, &len) < 0) rsock_sys_fail_path("getpeername(2)", fptr->pathv if (len0 < len) len = len0; return rsock_unixaddr(&addr, len }

recv_io([klass , mode]) → io Show source

UNIXServer.open("/tmp/sock") {|serv| UNIXSocket.open("/tmp/sock") {|c| s = serv.accept c.send_io STDOUT stdout = s.recv_io p STDOUT.fileno #=> 1 p stdout.fileno #=> 7 stdout.puts "hello" # outputs "hello\n" to standard output. } }

klass将确定返回的io类(使用IO.for_fd单例方法或类似方法)。 如果klass为零,则返回整数文件描述符。

mode 与传递给IO.for_fd的参数相同

static VALUE unix_recv_io(int argc, VALUE *argv, VALUE sock) { VALUE klass, mode; rb_io_t *fptr; struct iomsg_arg arg; struct iovec vec[2]; char buf[1]; int fd; #if FD_PASSING_BY_MSG_CONTROL union { struct cmsghdr hdr; char pad[sizeof(struct cmsghdr)+8+sizeof(int)+8]; } cmsg; #endif rb_scan_args(argc, argv, "02", &klass, &mode if (argc == 0) klass = rb_cIO; if (argc <= 1) mode = Qnil; GetOpenFile(sock, fptr arg.msg.msg_name = NULL; arg.msg.msg_namelen = 0; vec[0].iov_base = buf; vec[0].iov_len = sizeof(buf arg.msg.msg_iov = vec; arg.msg.msg_iovlen = 1; #if FD_PASSING_BY_MSG_CONTROL arg.msg.msg_control = (caddr_t)&cmsg; arg.msg.msg_controllen = (socklen_t)CMSG_SPACE(sizeof(int) arg.msg.msg_flags = 0; cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int) cmsg.hdr.cmsg_level = SOL_SOCKET; cmsg.hdr.cmsg_type = SCM_RIGHTS; fd = -1; memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int) #else arg.msg.msg_accrights = (caddr_t)&fd; arg.msg.msg_accrightslen = sizeof(fd fd = -1; #endif arg.fd = fptr->fd; while ((int)BLOCKING_REGION_FD(recvmsg_blocking, &arg) == -1) { if (!rb_io_wait_readable(arg.fd)) rsock_sys_fail_path("recvmsg(2)", fptr->pathv } #if FD_PASSING_BY_MSG_CONTROL if (arg.msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr)) { rb_raise(rb_eSocket, "file descriptor was not passed (msg_controllen=%d smaller than sizeof(struct cmsghdr)=%d)", (int)arg.msg.msg_controllen, (int)sizeof(struct cmsghdr) } if (cmsg.hdr.cmsg_level != SOL_SOCKET) { rb_raise(rb_eSocket, "file descriptor was not passed (cmsg_level=%d, %d expected)", cmsg.hdr.cmsg_level, SOL_SOCKET } if (cmsg.hdr.cmsg_type != SCM_RIGHTS) { rb_raise(rb_eSocket, "file descriptor was not passed (cmsg_type=%d, %d expected)", cmsg.hdr.cmsg_type, SCM_RIGHTS } if (arg.msg.msg_controllen < (socklen_t)CMSG_LEN(sizeof(int))) { rb_raise(rb_eSocket, "file descriptor was not passed (msg_controllen=%d smaller than CMSG_LEN(sizeof(int))=%d)", (int)arg.msg.msg_controllen, (int)CMSG_LEN(sizeof(int)) } if ((socklen_t)CMSG_SPACE(sizeof(int)) < arg.msg.msg_controllen) { rb_raise(rb_eSocket, "file descriptor was not passed (msg_controllen=%d bigger than CMSG_SPACE(sizeof(int))=%d)", (int)arg.msg.msg_controllen, (int)CMSG_SPACE(sizeof(int)) } if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) { rsock_discard_cmsg_resource(&arg.msg, 0 rb_raise(rb_eSocket, "file descriptor was not passed (cmsg_len=%d, %d expected)", (int)cmsg.hdr.cmsg_len, (int)CMSG_LEN(sizeof(int)) } #else if (arg.msg.msg_accrightslen != sizeof(fd)) { rb_raise(rb_eSocket, "file descriptor was not passed (accrightslen=%d, %d expected)", arg.msg.msg_accrightslen, (int)sizeof(fd) } #endif #if FD_PASSING_BY_MSG_CONTROL memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int) #endif rb_update_max_fd(fd if (rsock_cmsg_cloexec_state < 0) rsock_cmsg_cloexec_state = rsock_detect_cloexec(fd if (rsock_cmsg_cloexec_state == 0 || fd <= 2) rb_maygvl_fd_fix_cloexec(fd if (klass == Qnil) return INT2FIX(fd else { ID for_fd; int ff_argc; VALUE ff_argv[2]; CONST_ID(for_fd, "for_fd" ff_argc = mode == Qnil ? 1 : 2; ff_argv[0] = INT2FIX(fd ff_argv[1] = mode; return rb_funcallv(klass, for_fd, ff_argc, ff_argv } }

recvfrom(maxlen [, flags, outbuf]) → mesg, unixaddress()

通过unixsocket 接收消息。

maxlen 是要接收的最大字节数。

flags 应该是Socket :: MSG_ *常量的按位或。

即使outbuf 在开始时不是空的,outbuf 也只会包含方法调用后接收到的数据。

s1 = Socket.new(:UNIX, :DGRAM, 0) s1_ai = Addrinfo.unix("/tmp/sock1") s1.bind(s1_ai) s2 = Socket.new(:UNIX, :DGRAM, 0) s2_ai = Addrinfo.unix("/tmp/sock2") s2.bind(s2_ai) s3 = UNIXSocket.for_fd(s2.fileno) s1.send "a", 0, s2_ai p s3.recvfrom(10) #=> ["a", ["AF_UNIX", "/tmp/sock1"]]

static VALUE unix_recvfrom(int argc, VALUE *argv, VALUE sock) { return rsock_s_recvfrom(sock, argc, argv, RECV_UNIX }

send_io(io) → nil Show source

发送io 作为文件描述符传递。

s1, s2 = UNIXSocket.pair s1.send_io STDOUT stdout = s2.recv_io p STDOUT.fileno #=> 1 p stdout.fileno #=> 6 stdout.puts "hello" # outputs "hello\n" to standard output.

io 可以是任何类型的IO对象或整型文件描述符。

static VALUE unix_send_io(VALUE sock, VALUE val) { int fd; rb_io_t *fptr; struct iomsg_arg arg; struct iovec vec[1]; char buf[1]; #if FD_PASSING_BY_MSG_CONTROL union { struct cmsghdr hdr; char pad[sizeof(struct cmsghdr)+8+sizeof(int)+8]; } cmsg; #endif if (rb_obj_is_kind_of(val, rb_cIO)) { rb_io_t *valfptr; GetOpenFile(val, valfptr fd = valfptr->fd; } else if (FIXNUM_P(val)) { fd = FIX2INT(val } else { rb_raise(rb_eTypeError, "neither IO nor file descriptor" } GetOpenFile(sock, fptr arg.msg.msg_name = NULL; arg.msg.msg_namelen = 0; /* Linux and Solaris doesn't work if msg_iov is NULL. */ buf[0] = '\0'; vec[0].iov_base = buf; vec[0].iov_len = 1; arg.msg.msg_iov = vec; arg.msg.msg_iovlen = 1; #if FD_PASSING_BY_MSG_CONTROL arg.msg.msg_control = (caddr_t)&cmsg; arg.msg.msg_controllen = (socklen_t)CMSG_LEN(sizeof(int) arg.msg.msg_flags = 0; MEMZERO((char*)&cmsg, char, sizeof(cmsg) cmsg.hdr.cmsg_len = (socklen_t)CMSG_LEN(sizeof(int) cmsg.hdr.cmsg_level = SOL_SOCKET; cmsg.hdr.cmsg_type = SCM_RIGHTS; memcpy(CMSG_DATA(&cmsg.hdr), &fd, sizeof(int) #else arg.msg.msg_accrights = (caddr_t)&fd; arg.msg.msg_accrightslen = sizeof(fd #endif arg.fd = fptr->fd; while ((int)BLOCKING_REGION_FD(sendmsg_blocking, &arg) == -1) { if (!rb_io_wait_writable(arg.fd)) rsock_sys_fail_path("sendmsg(2)", fptr->pathv } return Qnil; }