类 UNIXServer
UNIXServer
代表一个 UNIX 域流服务器套接字。
公共类方法
创建一个绑定到 path 的新 UNIX 服务器套接字。
require 'socket' serv = UNIXServer.new("/tmp/sock") s = serv.accept p s.read
static VALUE unix_svr_init(VALUE sock, VALUE path) { return rsock_init_unixsock(sock, path, 1); }
公共实例方法
接受一个传入连接。它返回一个新的 UNIXSocket
对象。
UNIXServer.open("/tmp/sock") {|serv| UNIXSocket.open("/tmp/sock") {|c| s = serv.accept s.puts "hi" s.close p c.read #=> "hi\n" } }
static VALUE unix_accept(VALUE server) { struct sockaddr_un buffer; socklen_t length = sizeof(buffer); return rsock_s_accept(rb_cUNIXSocket, server, (struct sockaddr*)&buffer, &length); }
在为底层文件描述符设置 O_NONBLOCK 后,使用 accept(2) 接受传入连接。它返回一个已接受的 UNIXSocket
,用于传入连接。
示例¶ ↑
require 'socket' serv = UNIXServer.new("/tmp/sock") begin # emulate blocking accept sock = serv.accept_nonblock rescue IO::WaitReadable, Errno::EINTR IO.select([serv]) retry end # sock is an accepted socket.
请参考 Socket#accept
,了解在调用 UNIXServer#accept_nonblock
失败时可能抛出的异常。
UNIXServer#accept_nonblock
可能会引发任何与 accept(2) 失败相对应的错误,包括 Errno::EWOULDBLOCK。
如果异常是 Errno::EWOULDBLOCK、Errno::EAGAIN、Errno::ECONNABORTED 或 Errno::EPROTO,它将由 IO::WaitReadable
扩展。因此,可以使用 IO::WaitReadable
来捕获这些异常,以便重试 accept_nonblock。
通过将关键字参数 exception 指定为 false
,您可以指示 accept_nonblock
不应引发 IO::WaitReadable
异常,而是返回符号 :wait_readable
。
参见¶ ↑
# File ext/socket/lib/socket.rb, line 1360 def accept_nonblock(exception: true) __accept_nonblock(exception) end
监听连接,使用指定的 int
作为 backlog。只有当 socket
的类型为 SOCK_STREAM 或 SOCK_SEQPACKET 时,调用 listen 才会生效。
参数¶ ↑
-
backlog
- 等待连接队列的最大长度。
示例 1¶ ↑
require 'socket' include Socket::Constants socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) sockaddr = Socket.pack_sockaddr_in( 2200, 'localhost' ) socket.bind( sockaddr ) socket.listen( 5 )
示例 2(在任意端口监听,仅限 Unix 系统):¶ ↑
require 'socket' include Socket::Constants socket = Socket.new( AF_INET, SOCK_STREAM, 0 ) socket.listen( 1 )
Unix 系统异常¶ ↑
在 Unix 系统上,上述代码将正常工作,因为在 ADDR_ANY 地址上会创建一个新的 sockaddr
结构,用于内核分配的任意端口号。但在 Windows 上,这将无法工作,因为 Windows 要求在 listen 之前,通过调用 bind 来绑定 socket
。
如果 backlog 的值超过实现相关的最大队列长度,则将使用实现的最大队列长度。
在 Unix 系统上,如果调用 listen 失败,可能会引发以下系统异常
-
Errno::EBADF - socket 参数不是有效的文件描述符
-
Errno::EDESTADDRREQ - socket 未绑定到本地地址,并且协议不支持在未绑定套接字上监听
-
Errno::EINVAL - socket 已经连接
-
Errno::ENOTSOCK - socket 参数不指向套接字
-
Errno::EOPNOTSUPP - socket 协议不支持 listen
-
Errno::EACCES - 调用进程没有相应的权限
-
Errno::EINVAL - socket 已关闭
-
Errno::ENOBUFS - 系统中没有足够的资源来完成调用
Windows 异常¶ ↑
在 Windows 系统上,如果调用 listen 失败,可能会引发以下系统异常
-
Errno::ENETDOWN - 网络已关闭
-
Errno::EADDRINUSE - 套接字的本地地址已被使用。这通常发生在执行 bind 期间,但如果调用 bind 是针对部分通配符地址(涉及 ADDR_ANY),并且需要在调用 listen 时提交特定地址,则可能会延迟。
-
Errno::EINPROGRESS - Windows Sockets 1.1 调用正在进行中,或者服务提供商仍在处理回调函数
-
Errno::EINVAL -
socket
未通过调用 bind 绑定。 -
Errno::EISCONN -
socket
已经连接。 -
Errno::EMFILE - 没有可用的套接字描述符。
-
Errno::ENOBUFS - 没有可用的缓冲区空间。
-
Errno::ENOTSOC -
socket
不是套接字。 -
Errno::EOPNOTSUPP - 引用的
socket
不是支持 listen 方法的类型。
参见¶ ↑
-
基于 Unix 系统的 listen 手册页。
-
微软 Winsock 函数参考中的 listen 函数。
VALUE rsock_sock_listen(VALUE sock, VALUE log) { rb_io_t *fptr; int backlog; backlog = NUM2INT(log); GetOpenFile(sock, fptr); if (listen(fptr->fd, backlog) < 0) rb_sys_fail("listen(2)"); return INT2FIX(0); }
接受一个新的连接。它返回一个新的文件描述符,这是一个整数。
UNIXServer.open("/tmp/sock") {|serv| UNIXSocket.open("/tmp/sock") {|c| fd = serv.sysaccept s = IO.new(fd) s.puts "hi" s.close p c.read #=> "hi\n" } }
static VALUE unix_sysaccept(VALUE server) { struct sockaddr_un buffer; socklen_t length = sizeof(buffer); return rsock_s_accept(0, server, (struct sockaddr*)&buffer, &length); }