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:
parent
7506498f38
commit
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>
|
Mon Nov 16 21:27:54 2015 Naohisa Goto <ngotogenome@gmail.com>
|
||||||
|
|
||||||
* test/dtrace/helper.rb (Dtrace::TestCase#trap_probe): dtrace buffer
|
* 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);
|
return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* :nodoc: */
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
static VALUE
|
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, "remote_address", bsock_remote_address, 0);
|
||||||
rb_define_method(rb_cBasicSocket, "send", rsock_bsock_send, -1);
|
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", 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, 0);
|
||||||
rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
|
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", 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, "sendmsg_nonblock", rsock_bsock_sendmsg_nonblock, -1); /* in ancdata.c */
|
||||||
rb_define_method(rb_cBasicSocket, "recvmsg", rsock_bsock_recvmsg, -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
|
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;
|
rb_io_t *fptr;
|
||||||
VALUE str;
|
|
||||||
union_sockaddr buf;
|
union_sockaddr buf;
|
||||||
socklen_t alen = (socklen_t)sizeof buf;
|
socklen_t alen = (socklen_t)sizeof buf;
|
||||||
VALUE len, flg;
|
|
||||||
long buflen;
|
long buflen;
|
||||||
long slen;
|
long slen;
|
||||||
int fd, flags;
|
int fd, flags;
|
||||||
VALUE addr = Qnil;
|
VALUE addr = Qnil;
|
||||||
VALUE opts = Qnil;
|
|
||||||
socklen_t len0;
|
socklen_t len0;
|
||||||
|
|
||||||
rb_scan_args(argc, argv, "12:", &len, &flg, &str, &opts);
|
flags = NUM2INT(flg);
|
||||||
|
|
||||||
if (flg == Qnil) flags = 0;
|
|
||||||
else flags = NUM2INT(flg);
|
|
||||||
buflen = NUM2INT(len);
|
buflen = NUM2INT(len);
|
||||||
str = rsock_strbuf(str, buflen);
|
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
|
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
||||||
case EWOULDBLOCK:
|
case EWOULDBLOCK:
|
||||||
#endif
|
#endif
|
||||||
if (rsock_opt_false_p(opts, sym_exception))
|
if (ex == Qfalse)
|
||||||
return sym_wait_readable;
|
return sym_wait_readable;
|
||||||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
|
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
|
||||||
}
|
}
|
||||||
|
@ -274,6 +274,56 @@ class BasicSocket < IO
|
|||||||
end
|
end
|
||||||
addr
|
addr
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
class Socket < BasicSocket
|
class Socket < BasicSocket
|
||||||
@ -284,6 +334,70 @@ class Socket < BasicSocket
|
|||||||
end
|
end
|
||||||
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:
|
# :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]) {|socket| ... }
|
||||||
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts])
|
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts])
|
||||||
@ -868,3 +982,60 @@ class Socket < BasicSocket
|
|||||||
|
|
||||||
end
|
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 */
|
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);
|
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);
|
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);
|
return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* :nodoc: */
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
static VALUE
|
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, "sysaccept", sock_sysaccept, 0);
|
||||||
|
|
||||||
rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
|
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, "socketpair", rsock_sock_s_socketpair, -1);
|
||||||
rb_define_singleton_method(rb_cSocket, "pair", 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* :nodoc: */
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
static VALUE
|
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
|
void
|
||||||
@ -287,5 +235,8 @@ rsock_init_udpsocket(void)
|
|||||||
rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
|
rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
|
||||||
rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
|
rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
|
||||||
rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
|
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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user