tags:

views:

88

answers:

2

I've this ruby code that connects to a TCP server (namely, netcat). It loops 20 times, and sends "ABCD ". If I kill netcat, it takes TWO iterations of the loop for an exception to be triggered. On the first loop after netcat is killed, no exception is triggered, and "send" reports that 5 bytes have been correctly written... Which in the end is not true, since of course the server never received them.

Is there a way to work around this issue ? Right now I'm losing data : since I think it's been correctly transfered, I'm not replaying it.

#!/usr/bin/env ruby
require 'rubygems'
require 'socket'

sock = TCPSocket.new('192.168.0.10', 5443)
sock.sync = true

20.times do
  sleep 2
  begin
    count = sock.write("ABCD ")
    puts "Wrote #{count} bytes"
  rescue Exception => myException
    puts "Exception rescued : #{myException}"
  end
end
A: 

I tried without the sleep function (just to make sure it wasn't putting on hold anything) and still no luck:

#!/usr/bin/env ruby
require 'rubygems'
require 'socket'
require 'activesupport' # Fixnum.seconds

sock = TCPSocket.new('127.0.0.1', 5443)
sock.sync = true

will_restart_at = Time.now + 2.seconds
should_continue = true

while should_continue
  if will_restart_at <= Time.now
    will_restart_at = Time.now + 2.seconds
    begin
      count = sock.write("ABCD ")
      puts "Wrote #{count} bytes"
    rescue Exception => myException
      puts "Exception rescued : #{myException}"
      should_continue = false
    end
  end
end

I analyzed with Wireshark and the two solutions are exactly behaving identically.

I think (and can't be sure) that until you actually call your_socket.write (which will not fail as the socket is still opened because you weren't probing for its possible destruction), the socket won't raise any error.

I tried to simulate this with nginx and manual TCP sockets. And look at that:

irb> sock = TCPSocket.new('127.0.0.1', 80)
=> #<TCPSocket:0xb743b824>
irb> sock.write("salut")
=> 5
irb> sock.read
=> "<html>\r\n<head><title>400 Bad Request</title></head>\r\n<body>\r\n</body>\r\n</html>\r\n"

# Here, I kill nginx

irb> sock.write("salut")
=> 5
irb> sock.read
=> ""
irb> sock.write("salut")
Errno::EPIPE: Broken pipe

So what's the conclusion from here? Unless you're actually expecting some data from the server, you're screwed to detect that you've lost the connection :)

Cesario
+1  A: 

To detect a gracefully close, you'll have to read from the socket - read returning 0 indicates the socket has closed.

If you do need know if data got sent successfully though, there's no way other than implementing ACKs of the data at the application level.

nos
Indeed. So that pretty much means I'm screwed ? "The binary interface employs a plain TCP socket for binary content; it is streaming in nature and has zero acknowledgment responses. "http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingWIthAPS/CommunicatingWIthAPS.html#//apple_ref/doc/uid/TP40008194-CH101-SW3
Ecco