類別 UDPSocket
UDPSocket
代表 UDP/IP 通訊端。
公開類別方法
建立新的 UDPSocket
物件。
address_family 應為整數、字串或符號:Socket::AF_INET、"AF_INET"、:INET 等。
require 'socket' UDPSocket.new #=> #<UDPSocket:fd 3> UDPSocket.new(Socket::AF_INET6) #=> #<UDPSocket:fd 4>
static VALUE udp_init(int argc, VALUE *argv, VALUE sock) { VALUE arg; int family = AF_INET; int fd; if (rb_scan_args(argc, argv, "01", &arg) == 1) { family = rsock_family_arg(arg); } fd = rsock_socket(family, SOCK_DGRAM, 0); if (fd < 0) { rb_sys_fail("socket(2) - udp"); } return rsock_init_sock(sock, fd); }
公開實例方法
將 udpsocket 繫結到 host:port。
u1 = UDPSocket.new u1.bind("127.0.0.1", 4913) u1.send "message-to-self", 0, "127.0.0.1", 4913 p u1.recvfrom(10) #=> ["message-to", ["AF_INET", 4913, "localhost", "127.0.0.1"]]
static VALUE udp_bind(VALUE sock, VALUE host, VALUE port) { struct udp_arg arg; VALUE ret; GetOpenFile(sock, arg.fptr); arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0); ret = rb_ensure(udp_bind_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res); if (!ret) rsock_sys_fail_host_port("bind(2)", host, port); return INT2FIX(0); }
將 udpsocket 連線到 host:port。
這使得傳送資料時不需指定目的地位址。
u1 = UDPSocket.new u1.bind("127.0.0.1", 4913) u2 = UDPSocket.new u2.connect("127.0.0.1", 4913) u2.send "uuuu", 0 p u1.recvfrom(10) #=> ["uuuu", ["AF_INET", 33230, "localhost", "127.0.0.1"]]
static VALUE udp_connect(VALUE sock, VALUE host, VALUE port) { struct udp_arg arg; VALUE ret; GetOpenFile(sock, arg.fptr); arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0); ret = rb_ensure(udp_connect_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res); if (!ret) rsock_sys_fail_host_port("connect(2)", host, port); return INT2FIX(0); }
從 udpsocket
接收最多 maxlen 位元組的資料,使用 recvfrom(2),前提是基礎檔案描述符已設定 O_NONBLOCK。flags 為零或多個 MSG_
選項。結果的第一個元素 mesg 為接收到的資料。第二個元素 sender_inet_addr 為表示傳送者位址的陣列。
當 recvfrom(2) 傳回 0 時,Socket#recv_nonblock
會傳回 nil。在多數情況下,這表示連線已關閉,但也有可能是因為收到空封包,因為基礎 API 無法區分這兩種情況。
參數¶ ↑
-
maxlen
- 從通訊端接收的位元組數 -
flags
- 零或多個MSG_
選項 -
outbuf
- 目的String
緩衝區 -
options
- 關鍵字雜湊,支援 'exception: false`
範例¶ ↑
require 'socket' s1 = UDPSocket.new s1.bind("127.0.0.1", 0) s2 = UDPSocket.new s2.bind("127.0.0.1", 0) s2.connect(*s1.addr.values_at(3,1)) s1.connect(*s2.addr.values_at(3,1)) s1.send "aaa", 0 begin # emulate blocking recvfrom p s2.recvfrom_nonblock(10) #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]] rescue IO::WaitReadable IO.select([s2]) retry end
請參閱 Socket#recvfrom
,以了解在 recvfrom_nonblock 呼叫失敗時可能會引發的例外狀況。
UDPSocket#recvfrom_nonblock
可能會引發任何與 recvfrom(2) 失敗對應的錯誤,包括 Errno::EWOULDBLOCK。
如果例外狀況是 Errno::EWOULDBLOCK 或 Errno::EAGAIN,它會由 IO::WaitReadable
延伸。因此,IO::WaitReadable
可用於救援例外狀況以重試 recvfrom_nonblock。
透過指定關鍵字引數 exception 為 false
,你可以指出 recvfrom_nonblock
不應引發 IO::WaitReadable
例外狀況,而應傳回符號 :wait_readable
。
參閱¶ ↑
# File ext/socket/lib/socket.rb, line 1277 def recvfrom_nonblock(len, flag = 0, outbuf = nil, exception: true) __recvfrom_nonblock(len, flag, outbuf, exception) end
透過 udpsocket 傳送 mesg。
flags 應為 Socket::MSG_* 常數的按位元 OR。
u1 = UDPSocket.new u1.bind("127.0.0.1", 4913) u2 = UDPSocket.new u2.send "hi", 0, "127.0.0.1", 4913 mesg, addr = u1.recvfrom(10) u1.send mesg, 0, addr[3], addr[1] p u2.recv(100) #=> "hi"
static VALUE udp_send(int argc, VALUE *argv, VALUE sock) { VALUE flags, host, port; struct udp_send_arg arg; VALUE ret; if (argc == 2 || argc == 3) { return rsock_bsock_send(argc, argv, sock); } rb_scan_args(argc, argv, "4", &arg.sarg.mesg, &flags, &host, &port); StringValue(arg.sarg.mesg); GetOpenFile(sock, arg.fptr); arg.sarg.fd = arg.fptr->fd; arg.sarg.flags = NUM2INT(flags); arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0); ret = rb_ensure(udp_send_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res); if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port); return ret; }