Quoting pergesu / gmail.com, on Sun, Apr 03, 2005 at 03:33:47AM +0900:
> > > I don't want to override the protocol's idea of a timeout - I'd like
> > > some means of specifying a timeout for the connection though.  In

Be clear that you ARE overriding the protocols idea of a timeout by
terminating the connect() before the stack has decided the peer cannot
be connected.

> In Java:
> 
> Socket s = new Socket();
> s.connect(new InetSocketAddress(getHost(), port), timeout);
> 
> I can specify a timeout value for the connection, as you see above.

True enough, I was looking at the TCPSocket constructors, which don't
allow this.  Note this didn't exist prior to JDK 1.4, its a recent hack,
true to Java's "everything plus the sink" philosophy it looks like.

  http://java.sun.com/features/2002/08/j2se-network.html

I still find your "all the other languages" statement a little over the
top, JDK1.4 isn't a very large "all".

Overriding the TCP protocol's timeouts in the application is
questionable practice. I'm not telling you how to write your app, you
might have good reasons to do this, so do it. I am saying that overeager
timeouts and retransmissions have been known to cause very hard to find
and fix bugs when applications that work fine on a local network or
machine mysteriously start timing out over dialup or WiFi links.

> I don't see a way of doing that with the Ruby classes.  I'm new to
> Ruby, so I really don't know - is there a way to do it?

Yes, as I showed you;

  begin
    Timeout.timeout(18) do
      TCPSocket.new(...
    end
  rescue Timeout::Error
    ...
  end

You would wrap this into a nice function if you wanted to do it a lot.

Also, you may find that doing your connects in a seperate thread allows
you to not fiddle with the timeout, and still avoid your app blocking
if the network is slow or flaky.

Have fun.
Sam



> 
> On Apr 2, 2005 11:14 AM, Sam Roberts <sroberts / uniserve.com> wrote:
> > Quoting pergesu / gmail.com, on Sun, Apr 03, 2005 at 02:03:51AM +0900:
> > > every other language I've used, I can set a timeout value on the
> > > socket itself.  It doesn't look like that's the case in Ruby.  Is
> > 
> > The C, perl, and Java networking APIS don't support timeouts on TCP
> > connect(), and the C/BSD sockets API is what most (all?) other languages
> > use internally.
> > 
> > Out of curiosity, what are these languages?
> > 
> > > there a method somewhere in the Socket classe heirarchy that lets me
> > > specify a timeout?
> > >
> > > According to timeout, you can set an Exception that gets thrown when
> > > it times out.  I set that to StandardError, and just handle
> > 
> > Not sure what you mean. You can make timeout raise errors other than
> > Timeout::Error, and catch them, but you don't do so in the example you
> > posted.
> > 
> > > StandardError at the end.  According to the docs, Timeout::Error can't
> > > be used with rescue because it doesn't inherit from StandardError.
> > 
> > I assure you that Timeout::Error can be caught by rescue, as I showed, I
> > do it quite often and it works fine.
> > 
> > > I'd still like some means of setting a timeout value for a socket
> > > connection.  That's a pretty basic aspect of the protocol, there's no
> > > reason it shouldn't be in there.
> > 
> > I see no evidence that user configurable timeouts on connect() are not
> > part of the TCP protocol.
> > 
> > Cheers,
> > Sam
> > 
> > > On Apr 2, 2005 9:37 AM, Sam Roberts <sroberts / uniserve.com> wrote:
> > > > Quoting pergesu / gmail.com, on Sat, Apr 02, 2005 at 08:05:15PM +0900:
> > > > > I'm writing a little method that just tries to open a tcp socket
> > > > > connection, then closes it off.  I'm using timeout to limit the amount
> > > > > of time it tries to connect (is there a better way?).  If it times
> > > >
> > > > I have to wonder why you want to override the TCP protocols ideas of a
> > > > timeout. The protocol designers and implementors have a pretty good idea
> > > > of what  the timeouts should be.  If its not fast enough for you, you
> > > > probably want too much.  Doing this will make your code flaky and
> > > > unreliable when the network isn't as fast as your local network. A good
> > > > text on network programming should explain this. If you are finding your
> > > > app is blocked, you can use ruby threads to do connections in the
> > > > background.
> > > >
> > > > That said, you can't catch exceptions like that, try:
> > > >
> > > > begin
> > > >   Timeout::timeout(3) do
> > > >      long running op
> > > >   end
> > > > rescue Timeout::Error
> > > >   p "hi"
> > > > end
> > > >
> > > > Sam
> > > >
> > > > > out, I just want to say that the connect failed.  Despite catching the
> > > > > Timeout::Error (I think, anyway), I always get the Exception output.
> > > > > First, here's the method:
> > > > >
> > > > >       def execute
> > > > >               status = timeout(@timeoutval) {
> > > > >                       socket = TCPSocket.new(@host, @port) rescue false
> > > > >
> > > > >                       socket.close if socket
> > > > >                       return socket != false
> > > > >               } rescue Timeout::Error
> > > > >
> > > > >               return false
> > > > >       end
> > > > >
> > > > > And now the output from my unit test:
> > > > >
> > > > > Started
> > > > > /usr/local/lib/ruby/1.8/timeout.rb:42:in `new': execution expired
> > > > > (Timeout::Error)
> > > > >         from ./PortHostTest.rb:16:in `execute'
> > > > >         from ./PortHostTest.rb:15:in `timeout'
> > > > >         from /usr/local/lib/ruby/1.8/timeout.rb:55:in `timeout'
> > > > >         from ./PortHostTest.rb:15:in `execute'
> > > > >         from ./HostTest.rb:10:in `runTest'
> > > > >         from ../tests/test_HostTest.rb:14:in `test_simple'
> > > > >         from /usr/local/lib/ruby/1.8/test/unit/testcase.rb:70:in `__send__'
> > > > >         from /usr/local/lib/ruby/1.8/test/unit/testcase.rb:70:in `run'
> > > > >          ... 10 levels...
> > > > >         from /usr/local/lib/ruby/1.8/test/unit/autorunner.rb:194:in `run'
> > > > >         from /usr/local/lib/ruby/1.8/test/unit/autorunner.rb:14:in `run'
> > > > >         from /usr/local/lib/ruby/1.8/test/unit.rb:285
> > > > >         from /usr/local/lib/ruby/1.8/test/unit.rb:283
> > > > >
> > > >
> > > >
> > >
> > 
> >
>