зеркало из https://github.com/github/ruby.git
socket: avoid arg parsing in rsock_s_recvfrom_nonblock
* ext/socket/init.c (rsock_s_recvfrom_nonblock): avoid arg parsing with C API [ruby-core:71439] [Feature #11339] * ext/socket/basicsocket.c (bsock_recv_nonblock): adjust for above change, make private * ext/socket/socket.c (sock_recvfrom_nonblock): ditto * ext/socket/udpsocket.c (udp_recvfrom_nonblock): ditto * ext/socket/lib/socket.rb (BasicSocket#recv_nonblock): new wrapper for private method, move RDoc (Socket#recvfrom_nonblock): ditto (UDPSocket#recvfrom_nonblock): ditto Note, not adding bm_recv_nonblock.rb to benchmark/ directory since it is non-portable. It is only in this commit message. Benchmark results + code target 0: a (ruby 2.3.0dev (2015-11-12 trunk 52540) [x86_64-linux]) target 1: b (ruby 2.3.0dev (2015-11-12 avoid-kwarg-capi 52540) [x86_64-linux] ----------------------------------------------------------- recv_nonblock require 'socket' nr = 1000000 msg = 'hello world' buf = '' size = msg.bytesize UNIXSocket.pair(:SEQPACKET) do |a, b| nr.times do a.sendmsg(msg) b.recv_nonblock(size, 0, buf, exception: false) end end ----------------------------------------------------------- raw data: [["recv_nonblock", [[1.83511221408844, 1.8703329525887966, 1.8448856547474861, 1.859263762831688, 1.8331583738327026], [1.5637447573244572, 1.4062932096421719, 1.4247371144592762, 1.4108827747404575, 1.4802536629140377]]]] Elapsed time: 16.530452496 (sec) ----------------------------------------------------------- benchmark results: minimum results in each 5 measurements. Execution time (sec) name a b recv_nonblock 1.833 1.406 Speedup ratio: compare with the result of `a' (greater is better) name b recv_nonblock 1.304 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52598 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
7506498f38
Коммит
528ff1b9f9
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
|||
Tue Nov 17 08:16:09 2015 Eric Wong <e@80x24.org>
|
||||
|
||||
* ext/socket/init.c (rsock_s_recvfrom_nonblock):
|
||||
avoid arg parsing with C API
|
||||
[ruby-core:71439] [Feature #11339]
|
||||
* ext/socket/basicsocket.c (bsock_recv_nonblock):
|
||||
adjust for above change, make private
|
||||
* ext/socket/socket.c (sock_recvfrom_nonblock): ditto
|
||||
* ext/socket/udpsocket.c (udp_recvfrom_nonblock): ditto
|
||||
* ext/socket/lib/socket.rb (BasicSocket#recv_nonblock):
|
||||
new wrapper for private method, move RDoc
|
||||
(Socket#recvfrom_nonblock): ditto
|
||||
(UDPSocket#recvfrom_nonblock): ditto
|
||||
|
||||
Mon Nov 16 21:27:54 2015 Naohisa Goto <ngotogenome@gmail.com>
|
||||
|
||||
* test/dtrace/helper.rb (Dtrace::TestCase#trap_probe): dtrace buffer
|
||||
|
|
|
@ -643,59 +643,11 @@ bsock_recv(int argc, VALUE *argv, VALUE sock)
|
|||
return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* basicsocket.recv_nonblock(maxlen [, flags [, options ]) => mesg
|
||||
*
|
||||
* Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
|
||||
* O_NONBLOCK is set for the underlying file descriptor.
|
||||
* _flags_ is zero or more of the +MSG_+ options.
|
||||
* The result, _mesg_, is the data received.
|
||||
*
|
||||
* When recvfrom(2) returns 0, Socket#recv_nonblock returns
|
||||
* an empty string as data.
|
||||
* The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
|
||||
*
|
||||
* === Parameters
|
||||
* * +maxlen+ - the number of bytes to receive from the socket
|
||||
* * +flags+ - zero or more of the +MSG_+ options
|
||||
* * +options+ - keyword hash, supporting `exception: false`
|
||||
*
|
||||
* === Example
|
||||
* serv = TCPServer.new("127.0.0.1", 0)
|
||||
* af, port, host, addr = serv.addr
|
||||
* c = TCPSocket.new(addr, port)
|
||||
* s = serv.accept
|
||||
* c.send "aaa", 0
|
||||
* begin # emulate blocking recv.
|
||||
* p s.recv_nonblock(10) #=> "aaa"
|
||||
* rescue IO::WaitReadable
|
||||
* IO.select([s])
|
||||
* retry
|
||||
* end
|
||||
*
|
||||
* Refer to Socket#recvfrom for the exceptions that may be thrown if the call
|
||||
* to _recv_nonblock_ fails.
|
||||
*
|
||||
* BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
|
||||
* including Errno::EWOULDBLOCK.
|
||||
*
|
||||
* If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
|
||||
* it is extended by IO::WaitReadable.
|
||||
* So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
|
||||
*
|
||||
* By specifying `exception: false`, the options hash allows you to indicate
|
||||
* that recv_nonblock should not raise an IO::WaitWritable exception, but
|
||||
* return the symbol :wait_writable instead.
|
||||
*
|
||||
* === See
|
||||
* * Socket#recvfrom
|
||||
*/
|
||||
|
||||
/* :nodoc: */
|
||||
static VALUE
|
||||
bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
|
||||
bsock_recv_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
|
||||
{
|
||||
return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_RECV);
|
||||
return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_RECV);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -764,10 +716,14 @@ rsock_init_basicsocket(void)
|
|||
rb_define_method(rb_cBasicSocket, "remote_address", bsock_remote_address, 0);
|
||||
rb_define_method(rb_cBasicSocket, "send", rsock_bsock_send, -1);
|
||||
rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
|
||||
rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1);
|
||||
|
||||
rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_reverse_lookup, 0);
|
||||
rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
|
||||
|
||||
/* for ext/socket/lib/socket.rb use only: */
|
||||
rb_define_private_method(rb_cBasicSocket,
|
||||
"__recv_nonblock", bsock_recv_nonblock, 4);
|
||||
|
||||
rb_define_method(rb_cBasicSocket, "sendmsg", rsock_bsock_sendmsg, -1); /* in ancdata.c */
|
||||
rb_define_method(rb_cBasicSocket, "sendmsg_nonblock", rsock_bsock_sendmsg_nonblock, -1); /* in ancdata.c */
|
||||
rb_define_method(rb_cBasicSocket, "recvmsg", rsock_bsock_recvmsg, -1); /* in ancdata.c */
|
||||
|
|
|
@ -200,24 +200,19 @@ rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
|
|||
}
|
||||
|
||||
VALUE
|
||||
rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
|
||||
rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
|
||||
VALUE ex, enum sock_recv_type from)
|
||||
{
|
||||
rb_io_t *fptr;
|
||||
VALUE str;
|
||||
union_sockaddr buf;
|
||||
socklen_t alen = (socklen_t)sizeof buf;
|
||||
VALUE len, flg;
|
||||
long buflen;
|
||||
long slen;
|
||||
int fd, flags;
|
||||
VALUE addr = Qnil;
|
||||
VALUE opts = Qnil;
|
||||
socklen_t len0;
|
||||
|
||||
rb_scan_args(argc, argv, "12:", &len, &flg, &str, &opts);
|
||||
|
||||
if (flg == Qnil) flags = 0;
|
||||
else flags = NUM2INT(flg);
|
||||
flags = NUM2INT(flg);
|
||||
buflen = NUM2INT(len);
|
||||
str = rsock_strbuf(str, buflen);
|
||||
|
||||
|
@ -249,7 +244,7 @@ rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type
|
|||
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
if (rsock_opt_false_p(opts, sym_exception))
|
||||
if (ex == Qfalse)
|
||||
return sym_wait_readable;
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
|
||||
}
|
||||
|
|
|
@ -274,6 +274,56 @@ class BasicSocket < IO
|
|||
end
|
||||
addr
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# basicsocket.recv_nonblock(maxlen [, flags [, buf [, options ]]]) => mesg
|
||||
#
|
||||
# Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
|
||||
# O_NONBLOCK is set for the underlying file descriptor.
|
||||
# _flags_ is zero or more of the +MSG_+ options.
|
||||
# The result, _mesg_, is the data received.
|
||||
#
|
||||
# When recvfrom(2) returns 0, Socket#recv_nonblock returns
|
||||
# an empty string as data.
|
||||
# The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
|
||||
#
|
||||
# === Parameters
|
||||
# * +maxlen+ - the number of bytes to receive from the socket
|
||||
# * +flags+ - zero or more of the +MSG_+ options
|
||||
# * +options+ - keyword hash, supporting `exception: false`
|
||||
#
|
||||
# === Example
|
||||
# serv = TCPServer.new("127.0.0.1", 0)
|
||||
# af, port, host, addr = serv.addr
|
||||
# c = TCPSocket.new(addr, port)
|
||||
# s = serv.accept
|
||||
# c.send "aaa", 0
|
||||
# begin # emulate blocking recv.
|
||||
# p s.recv_nonblock(10) #=> "aaa"
|
||||
# rescue IO::WaitReadable
|
||||
# IO.select([s])
|
||||
# retry
|
||||
# end
|
||||
#
|
||||
# Refer to Socket#recvfrom for the exceptions that may be thrown if the call
|
||||
# to _recv_nonblock_ fails.
|
||||
#
|
||||
# BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
|
||||
# including Errno::EWOULDBLOCK.
|
||||
#
|
||||
# If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
|
||||
# it is extended by IO::WaitReadable.
|
||||
# So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
|
||||
#
|
||||
# By specifying `exception: false`, the options hash allows you to indicate
|
||||
# that recv_nonblock should not raise an IO::WaitWritable exception, but
|
||||
# return the symbol :wait_writable instead.
|
||||
#
|
||||
# === See
|
||||
# * Socket#recvfrom
|
||||
def recv_nonblock(len, flag = 0, str = nil, exception: true)
|
||||
__recv_nonblock(len, flag, str, exception)
|
||||
end
|
||||
end
|
||||
|
||||
class Socket < BasicSocket
|
||||
|
@ -284,6 +334,70 @@ class Socket < BasicSocket
|
|||
end
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
|
||||
# socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
|
||||
#
|
||||
# Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
|
||||
# O_NONBLOCK is set for the underlying file descriptor.
|
||||
# _flags_ is zero or more of the +MSG_+ options.
|
||||
# The first element of the results, _mesg_, is the data received.
|
||||
# The second element, _sender_addrinfo_, contains protocol-specific address
|
||||
# information of the sender.
|
||||
#
|
||||
# When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
|
||||
# an empty string as data.
|
||||
# The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
|
||||
#
|
||||
# === Parameters
|
||||
# * +maxlen+ - the maximum number of bytes to receive from the socket
|
||||
# * +flags+ - zero or more of the +MSG_+ options
|
||||
#
|
||||
# === Example
|
||||
# # In one file, start this first
|
||||
# require 'socket'
|
||||
# include Socket::Constants
|
||||
# socket = Socket.new(AF_INET, SOCK_STREAM, 0)
|
||||
# sockaddr = Socket.sockaddr_in(2200, 'localhost')
|
||||
# socket.bind(sockaddr)
|
||||
# socket.listen(5)
|
||||
# client, client_addrinfo = socket.accept
|
||||
# begin # emulate blocking recvfrom
|
||||
# pair = client.recvfrom_nonblock(20)
|
||||
# rescue IO::WaitReadable
|
||||
# IO.select([client])
|
||||
# retry
|
||||
# end
|
||||
# data = pair[0].chomp
|
||||
# puts "I only received 20 bytes '#{data}'"
|
||||
# sleep 1
|
||||
# socket.close
|
||||
#
|
||||
# # In another file, start this second
|
||||
# require 'socket'
|
||||
# include Socket::Constants
|
||||
# socket = Socket.new(AF_INET, SOCK_STREAM, 0)
|
||||
# sockaddr = Socket.sockaddr_in(2200, 'localhost')
|
||||
# socket.connect(sockaddr)
|
||||
# socket.puts "Watch this get cut short!"
|
||||
# socket.close
|
||||
#
|
||||
# Refer to Socket#recvfrom for the exceptions that may be thrown if the call
|
||||
# to _recvfrom_nonblock_ fails.
|
||||
#
|
||||
# Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
|
||||
# including Errno::EWOULDBLOCK.
|
||||
#
|
||||
# If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
|
||||
# it is extended by IO::WaitReadable.
|
||||
# So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
|
||||
#
|
||||
# === See
|
||||
# * Socket#recvfrom
|
||||
def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
|
||||
__recvfrom_nonblock(len, flag, str, exception)
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
|
||||
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts])
|
||||
|
@ -868,3 +982,60 @@ class Socket < BasicSocket
|
|||
|
||||
end
|
||||
|
||||
class UDPSocket < IPSocket
|
||||
|
||||
# call-seq:
|
||||
# udpsocket.recvfrom_nonblock(maxlen [, flags [, options]]) => [mesg, sender_inet_addr]
|
||||
#
|
||||
# Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
|
||||
# O_NONBLOCK is set for the underlying file descriptor.
|
||||
# If _maxlen_ is omitted, its default value is 65536.
|
||||
# _flags_ is zero or more of the +MSG_+ options.
|
||||
# The first element of the results, _mesg_, is the data received.
|
||||
# The second element, _sender_inet_addr_, is an array to represent the sender address.
|
||||
#
|
||||
# When recvfrom(2) returns 0,
|
||||
# Socket#recvfrom_nonblock returns an empty string as data.
|
||||
# It means an empty packet.
|
||||
#
|
||||
# === Parameters
|
||||
# * +maxlen+ - the number of bytes to receive from the socket
|
||||
# * +flags+ - zero or more of the +MSG_+ options
|
||||
# * +options+ - keyword hash, supporting `exception: false`
|
||||
#
|
||||
# === Example
|
||||
# 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
|
||||
#
|
||||
# Refer to Socket#recvfrom for the exceptions that may be thrown if the call
|
||||
# to _recvfrom_nonblock_ fails.
|
||||
#
|
||||
# UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
|
||||
# including Errno::EWOULDBLOCK.
|
||||
#
|
||||
# If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
|
||||
# it is extended by IO::WaitReadable.
|
||||
# So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
|
||||
#
|
||||
# By specifying `exception: false`, the options hash allows you to indicate
|
||||
# that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
|
||||
# return the symbol :wait_writable instead.
|
||||
#
|
||||
# === See
|
||||
# * Socket#recvfrom
|
||||
def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
|
||||
__recvfrom_nonblock(len, flag, str, exception)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -347,7 +347,8 @@ enum sock_recv_type {
|
|||
RECV_SOCKET /* Socket#recvfrom */
|
||||
};
|
||||
|
||||
VALUE rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
|
||||
VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
|
||||
VALUE ex, enum sock_recv_type from);
|
||||
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
|
||||
|
||||
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks);
|
||||
|
|
|
@ -813,72 +813,11 @@ sock_recvfrom(int argc, VALUE *argv, VALUE sock)
|
|||
return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
|
||||
* socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
|
||||
*
|
||||
* Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
|
||||
* O_NONBLOCK is set for the underlying file descriptor.
|
||||
* _flags_ is zero or more of the +MSG_+ options.
|
||||
* The first element of the results, _mesg_, is the data received.
|
||||
* The second element, _sender_addrinfo_, contains protocol-specific address
|
||||
* information of the sender.
|
||||
*
|
||||
* When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
|
||||
* an empty string as data.
|
||||
* The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
|
||||
*
|
||||
* === Parameters
|
||||
* * +maxlen+ - the maximum number of bytes to receive from the socket
|
||||
* * +flags+ - zero or more of the +MSG_+ options
|
||||
*
|
||||
* === Example
|
||||
* # In one file, start this first
|
||||
* require 'socket'
|
||||
* include Socket::Constants
|
||||
* socket = Socket.new(AF_INET, SOCK_STREAM, 0)
|
||||
* sockaddr = Socket.sockaddr_in(2200, 'localhost')
|
||||
* socket.bind(sockaddr)
|
||||
* socket.listen(5)
|
||||
* client, client_addrinfo = socket.accept
|
||||
* begin # emulate blocking recvfrom
|
||||
* pair = client.recvfrom_nonblock(20)
|
||||
* rescue IO::WaitReadable
|
||||
* IO.select([client])
|
||||
* retry
|
||||
* end
|
||||
* data = pair[0].chomp
|
||||
* puts "I only received 20 bytes '#{data}'"
|
||||
* sleep 1
|
||||
* socket.close
|
||||
*
|
||||
* # In another file, start this second
|
||||
* require 'socket'
|
||||
* include Socket::Constants
|
||||
* socket = Socket.new(AF_INET, SOCK_STREAM, 0)
|
||||
* sockaddr = Socket.sockaddr_in(2200, 'localhost')
|
||||
* socket.connect(sockaddr)
|
||||
* socket.puts "Watch this get cut short!"
|
||||
* socket.close
|
||||
*
|
||||
* Refer to Socket#recvfrom for the exceptions that may be thrown if the call
|
||||
* to _recvfrom_nonblock_ fails.
|
||||
*
|
||||
* Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
|
||||
* including Errno::EWOULDBLOCK.
|
||||
*
|
||||
* If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
|
||||
* it is extended by IO::WaitReadable.
|
||||
* So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
|
||||
*
|
||||
* === See
|
||||
* * Socket#recvfrom
|
||||
*/
|
||||
/* :nodoc: */
|
||||
static VALUE
|
||||
sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
|
||||
sock_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
|
||||
{
|
||||
return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
|
||||
return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_SOCKET);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2182,7 +2121,10 @@ Init_socket(void)
|
|||
rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
|
||||
|
||||
rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
|
||||
rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1);
|
||||
|
||||
/* for ext/socket/lib/socket.rb use only: */
|
||||
rb_define_private_method(rb_cSocket,
|
||||
"__recvfrom_nonblock", sock_recvfrom_nonblock, 4);
|
||||
|
||||
rb_define_singleton_method(rb_cSocket, "socketpair", rsock_sock_s_socketpair, -1);
|
||||
rb_define_singleton_method(rb_cSocket, "pair", rsock_sock_s_socketpair, -1);
|
||||
|
|
|
@ -214,63 +214,11 @@ udp_send(int argc, VALUE *argv, VALUE sock)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* udpsocket.recvfrom_nonblock(maxlen [, flags [, options]]) => [mesg, sender_inet_addr]
|
||||
*
|
||||
* Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
|
||||
* O_NONBLOCK is set for the underlying file descriptor.
|
||||
* If _maxlen_ is omitted, its default value is 65536.
|
||||
* _flags_ is zero or more of the +MSG_+ options.
|
||||
* The first element of the results, _mesg_, is the data received.
|
||||
* The second element, _sender_inet_addr_, is an array to represent the sender address.
|
||||
*
|
||||
* When recvfrom(2) returns 0,
|
||||
* Socket#recvfrom_nonblock returns an empty string as data.
|
||||
* It means an empty packet.
|
||||
*
|
||||
* === Parameters
|
||||
* * +maxlen+ - the number of bytes to receive from the socket
|
||||
* * +flags+ - zero or more of the +MSG_+ options
|
||||
* * +options+ - keyword hash, supporting `exception: false`
|
||||
*
|
||||
* === Example
|
||||
* 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
|
||||
*
|
||||
* Refer to Socket#recvfrom for the exceptions that may be thrown if the call
|
||||
* to _recvfrom_nonblock_ fails.
|
||||
*
|
||||
* UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
|
||||
* including Errno::EWOULDBLOCK.
|
||||
*
|
||||
* If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
|
||||
* it is extended by IO::WaitReadable.
|
||||
* So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
|
||||
*
|
||||
* By specifying `exception: false`, the options hash allows you to indicate
|
||||
* that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
|
||||
* return the symbol :wait_writable instead.
|
||||
*
|
||||
* === See
|
||||
* * Socket#recvfrom
|
||||
*/
|
||||
/* :nodoc: */
|
||||
static VALUE
|
||||
udp_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
|
||||
udp_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
|
||||
{
|
||||
return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_IP);
|
||||
return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_IP);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -287,5 +235,8 @@ rsock_init_udpsocket(void)
|
|||
rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
|
||||
rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
|
||||
rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
|
||||
rb_define_method(rb_cUDPSocket, "recvfrom_nonblock", udp_recvfrom_nonblock, -1);
|
||||
|
||||
/* for ext/socket/lib/socket.rb use only: */
|
||||
rb_define_private_method(rb_cUDPSocket,
|
||||
"__recvfrom_nonblock", udp_recvfrom_nonblock, 4);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче