Thanks to the Matz and colleagues for adding the *_nonblock functions. They have been a huge help. I've already gotten some big performance improvements in the EventMachine event-processing library. I thought it was a little strange that accept_nonblock is not available for TCPServer (because it inherits from IO rather than Socket) but it wasn't hard to work around that. (Just create a Socket object and call bind and listen on it myself.) The nonblock functions seem to work well with files and unix-domain sockets. I haven't tested datagrams yet but will do so shortly. Thanks again, team.
Nonblocking accept
on 26.05.2006 14:30
Re: Nonblocking accept
on 27.05.2006 03:58
In article <3a94cf510605260529x658e20e1q7d9754266675c3d5@mail.gmail.com>, "Francis Cianfrocca" <garbagecat10@gmail.com> writes: > Thanks to the Matz and colleagues for adding the *_nonblock functions. They > have been a huge help. I've already gotten some big performance improvements > in the EventMachine event-processing library. I thought it was a little > strange that accept_nonblock is not available for TCPServer (because it > inherits from IO rather than Socket) but it wasn't hard to work around that. > (Just create a Socket object and call bind and listen on it myself.) The > nonblock functions seem to work well with files and unix-domain sockets. I > haven't tested datagrams yet but will do so shortly. Since accept is for connection oriented sockets, UDP doesn't need it. Index: ext/socket/socket.c =================================================================== RCS file: /src/ruby/ext/socket/socket.c,v retrieving revision 1.164 diff -u -p -r1.164 socket.c --- ext/socket/socket.c 25 May 2006 23:43:29 -0000 1.164 +++ ext/socket/socket.c 27 May 2006 01:52:19 -0000 @@ -1383,6 +1383,20 @@ tcp_svr_init(argc, argv, sock) } static VALUE +s_accept_nonblock(VALUE klass, OpenFile *fptr, struct sockaddr *sockaddr, socklen_t *len) +{ + int fd2; + + rb_secure(3); + rb_io_set_nonblock(fptr); + fd2 = accept(fptr->fd, (struct sockaddr*)sockaddr, len); + if (fd2 < 0) { + rb_sys_fail("accept(2)"); + } + return init_sock(rb_obj_alloc(klass), fd2); +} + +static VALUE s_accept(klass, fd, sockaddr, len) VALUE klass; int fd; @@ -1435,6 +1449,49 @@ tcp_accept(sock) (struct sockaddr*)&from, &fromlen); } +/* + * call-seq: + * tcpserver.accept_nonblock => tcpsocket + * + * Accepts an incoming connection using accept(2) after + * O_NONBLOCK is set for the underlying file descriptor. + * It returns an accepted TCPSocket for the incoming connection. + * + * === Example + * require 'socket' + * serv = TCPServer.new(2202) + * begin + * sock = serv.accept_nonblock + * rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR + * IO.select([serv]) + * retry + * end + * # sock is an accepted socket. + * + * Refer to Socket#accept for the exceptions that may be thrown if the call + * to TCPServer#accept_nonblock fails. + * + * TCPServer#accept_nonblock may raise any error corresponding to accept(2) failure, + * including Errno::EAGAIN. + * + * === See + * * TCPServer#accept + * * Socket#accept + */ +static VALUE +tcp_accept_nonblock(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_storage from; + socklen_t fromlen; + + GetOpenFile(sock, fptr); + fromlen = sizeof(from); + return s_accept_nonblock(rb_cTCPSocket, fptr, + (struct sockaddr *)&from, &fromlen); +} + static VALUE tcp_sysaccept(sock) VALUE sock; @@ -1925,6 +1982,49 @@ unix_accept(sock) (struct sockaddr*)&from, &fromlen); } +/* + * call-seq: + * unixserver.accept_nonblock => unixsocket + * + * Accepts an incoming connection using accept(2) after + * O_NONBLOCK is set for the underlying file descriptor. + * It returns an accepted UNIXSocket for the incoming connection. + * + * === Example + * require 'socket' + * serv = UNIXServer.new("/tmp/sock") + * begin + * sock = serv.accept_nonblock + * rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR + * IO.select([serv]) + * retry + * end + * # sock is an accepted socket. + * + * Refer to Socket#accept for the exceptions that may be thrown if the call + * to UNIXServer#accept_nonblock fails. + * + * UNIXServer#accept_nonblock may raise any error corresponding to accept(2) failure, + * including Errno::EAGAIN. + * + * === See + * * UNIXServer#accept + * * Socket#accept + */ +static VALUE +unix_accept_nonblock(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_storage from; + socklen_t fromlen; + + GetOpenFile(sock, fptr); + fromlen = sizeof(from); + return s_accept_nonblock(rb_cUNIXSocket, fptr, + (struct sockaddr *)&from, &fromlen); +} + static VALUE unix_sysaccept(sock) VALUE sock; @@ -2784,19 +2884,12 @@ sock_accept_nonblock(sock) VALUE sock; { OpenFile *fptr; - int fd2; VALUE sock2; char buf[1024]; socklen_t len = sizeof buf; GetOpenFile(sock, fptr); - rb_io_set_nonblock(fptr); - fd2 = accept(fptr->fd, (struct sockaddr*)buf, &len); - if (fd2 < 0) { - rb_sys_fail("accept(2)"); - } - sock2 = init_sock(rb_obj_alloc(rb_cSocket), fd2); - + sock2 = s_accept_nonblock(rb_cSocket, fptr, (struct sockaddr *)buf, &len); return rb_assoc_new(sock2, rb_str_new(buf, len)); } @@ -3414,6 +3507,7 @@ Init_socket() rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket); rb_define_global_const("TCPserver", rb_cTCPServer); rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0); + rb_define_method(rb_cTCPServer, "accept_nonblock", tcp_accept_nonblock, 0); rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, 0); rb_define_method(rb_cTCPServer, "initialize", tcp_svr_init, -1); rb_define_method(rb_cTCPServer, "listen", sock_listen, 1); @@ -3442,6 +3536,7 @@ Init_socket() rb_define_global_const("UNIXserver", rb_cUNIXServer); rb_define_method(rb_cUNIXServer, "initialize", unix_svr_init, 1); rb_define_method(rb_cUNIXServer, "accept", unix_accept, 0); + rb_define_method(rb_cUNIXServer, "accept_nonblock", unix_accept_nonblock, 0); rb_define_method(rb_cUNIXServer, "sysaccept", unix_sysaccept, 0); rb_define_method(rb_cUNIXServer, "listen", sock_listen, 1); #endif
Re: Nonblocking accept
on 27.05.2006 04:31
Thanks for the patch, I'll test as soon as I can. In regard to datagrams, what I meant was nonblocking recvfrom. I haven't tried that one yet. Let me repeat- the performance boost from nonblocking connect is really great. Thanks again.
