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;
}