Exceptions inside loops

Hello all, quite new to ruby here.

I am trying to figure out how to catch exceptions and I am not having luck.
Basically I have a script that loops over an array of ports and tries to
connect to see if there is a service running. If there is nothing running
then I get a "Connection refused" error (ECONNREFUSED). In this case I just
want to print a small message and move on to the next port, however, my
attempt at this just terminates the loop entirely. Here's some (simplified)
code:

begin telnetPorts.each do |port|
   puts "Port " + port.to_s + ":"
   t = TCPSocket.new(host,port)
   banner = t.gets
   t.close
end

rescue SystemCallError
   puts "Unable to connect to port: " + $!
end

As it stands, this does catch the exception just fine, but moves to the next
block of code immediately. I tried using 'next' but it is giving me an error:
"unexpected next". So how does one simply move on to the next port in this
case? Do I need to rewrite it as a function?

Thanks for consideration,
-d

···

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more expected..."
- Dennis Ritchie and Ken Thompson, June 1972

darren kirby wrote:

begin telnetPorts.each do |port|

   puts "Port " + port.to_s + ":"
   t = TCPSocket.new(host,port)
   banner = t.gets
   t.close
end

rescue SystemCallError
   puts "Unable to connect to port: " + $!
end

I believe you just need to move your exception handling inside the
each's block

telnetPorts.each do |port|
  begin
    puts "Port #{port}:"
    t = TCPSocket.new( host.port )
    puts t.gets
    t.close
  rescue SystemCallError
    puts "Unable to gonnect to port #{port}: #$!"
  end
end

···

--
Posted via http://www.ruby-forum.com/\.

darren kirby wrote:

begin telnetPorts.each do |port|
   puts "Port " + port.to_s + ":"
   t = TCPSocket.new(host,port)
   banner = t.gets
   t.close
end

rescue SystemCallError
   puts "Unable to connect to port: " + $!
end

I see the question has been answered; let me just explain a little further.

Here's the code you posted above with standard indentation:

begin
  telnetPorts.each do |port|
    puts "Port " + port.to_s + ":"
    t = TCPSocket.new(host,port)
    banner = t.gets
    t.close
  end
rescue SystemCallError
   puts "Unable to connect to port: " + $!
end

The first "end" closes the do..end block given to the each method. The
second end closes the begin..end block. The rescue clause applies to the
begin..end block.

(Obviously) begin..end is used to introduce a new scope, often for
exception handling like you're doing here, but you can see that if an
exception is caught, you end up outside the loop. If you added a "retry"
or "redo" to the rescue clause, you'd simply start the loop again from
the top.

You can add rescue clauses inside begin..end blocks and also def..end
method bodies:

def barf
  raise "some exception"
rescue RuntimeError
  puts "some exception was raised"
end

Now you can go back to your already-working solution from Mike
Fletcher's post.

Cheers,
Dave

quoth the Mike Fletcher:

darren kirby wrote:
>> begin telnetPorts.each do |port|
>
> puts "Port " + port.to_s + ":"
> t = TCPSocket.new(host,port)
> banner = t.gets
> t.close
> end
>
> rescue SystemCallError
> puts "Unable to connect to port: " + $!
> end

I believe you just need to move your exception handling inside the
each's block

telnetPorts.each do |port|
  begin
    puts "Port #{port}:"
    t = TCPSocket.new( host.port )
    puts t.gets
    t.close
  rescue SystemCallError
    puts "Unable to gonnect to port #{port}: #$!"
  end
end

That did the trick, thank you.
Also thanks for for showing how to interpolate variables inside a string.
I will get this with time...

Thanks again,
-d

···

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more expected..."
- Dennis Ritchie and Ken Thompson, June 1972

quoth the Dave Burt:

darren kirby wrote:
> begin telnetPorts.each do |port|
> puts "Port " + port.to_s + ":"
> t = TCPSocket.new(host,port)
> banner = t.gets
> t.close
> end
>
> rescue SystemCallError
> puts "Unable to connect to port: " + $!
> end

I see the question has been answered; let me just explain a little further.

Here's the code you posted above with standard indentation:

begin
  telnetPorts.each do |port|
    puts "Port " + port.to_s + ":"
    t = TCPSocket.new(host,port)
    banner = t.gets
    t.close
  end
rescue SystemCallError
   puts "Unable to connect to port: " + $!
end

The first "end" closes the do..end block given to the each method. The
second end closes the begin..end block. The rescue clause applies to the
begin..end block.

(Obviously) begin..end is used to introduce a new scope, often for
exception handling like you're doing here, but you can see that if an
exception is caught, you end up outside the loop. If you added a "retry"
or "redo" to the rescue clause, you'd simply start the loop again from
the top.

You can add rescue clauses inside begin..end blocks and also def..end
method bodies:

def barf
  raise "some exception"
rescue RuntimeError
  puts "some exception was raised"
end

Now you can go back to your already-working solution from Mike
Fletcher's post.

Cheers,
Dave

Thanks for the additional enlightenment Dave, I did see that syntax in some
sample code but I was getting "Unexpected KRescue or somesuch error. However,
now it is working as it should, and I just need to find out how to send
Socket a timeout (SO_RCVTIMEO seems not to be defined) but that is another
post!

Thanks guys,
-d

···

--
darren kirby :: Part of the problem since 1976 :: http://badcomputer.org
"...the number of UNIX installations has grown to 10, with more expected..."
- Dennis Ritchie and Ken Thompson, June 1972