[#7872] Nonblocking socket-connect — "Francis Cianfrocca" <garbagecat10@...>

All, I needed a nonblocking socket connect for my asynchronous-event

18 messages 2006/05/14
[#7873] Re: Nonblocking socket-connect — Tanaka Akira <akr@...17n.org> 2006/05/14

In article <3a94cf510605140559l7baa0205le341dac4f47d424b@mail.gmail.com>,

[#7874] Re: Nonblocking socket-connect — "Francis Cianfrocca" <garbagecat10@...> 2006/05/15

How about introducing the method Socket#set_nonblocking, or alternatively

[#7875] Re: Nonblocking socket-connect — Yukihiro Matsumoto <matz@...> 2006/05/15

Hi,

[#7876] Re: Nonblocking socket-connect — "Francis Cianfrocca" <garbagecat10@...> 2006/05/15

Well, it's ok then. I'm comfortable adding in the nonblocking

[#7877] Re: Nonblocking socket-connect — Yukihiro Matsumoto <matz@...> 2006/05/15

Hi,

Re: Nonblocking accept

From: Tanaka Akira <akr@...17n.org>
Date: 2006-05-27 01:55:22 UTC
List: ruby-core #7925
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

-- 
Tanaka Akira

In This Thread