packetie
packetie

Reputation: 5069

non blocking tcp client socket in ruby failed

Trying to create a TCP socket in a non-blocking manner, but it failed. Any idea?

$ ruby nonblock_sock.rb 
/home/tom/.rvm/rubies/ruby-2.3.1/lib/ruby/2.3.0/socket.rb:1207:in `__connect_nonblock': Operation now in progress - connect(2) would block (IO::EINPROGRESSWaitWritable)
    from /home/tom/.rvm/rubies/ruby-2.3.1/lib/ruby/2.3.0/socket.rb:1207:in `connect_nonblock'
    from nonblock_sock.rb:6:in `<main>'

Here is the code snippet

#not working yet, 
require 'socket'

socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) 
sockaddr = Socket.pack_sockaddr_in(80, 'localhost') 
socket.connect_nonblock(sockaddr);

Upvotes: 0

Views: 1888

Answers (1)

kiddorails
kiddorails

Reputation: 13014

Change it to:

require 'socket'
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) 
sockaddr = Socket.pack_sockaddr_in(80, '127.0.0.1')  #this
socket.connect_nonblock(sockaddr)

If I recall correctly, one needs to pass the IP instead of hostname(localhost) while creating address. With this, connect_nonblock should raise EINPROGRESS where it is connecting in non-blocking manner in background which I think we can check with IO.select later.

Edit: IO::EINPROGRESSWaitWritable is raised as expected. connect_nonblock leaves the connection establishment process for background and raises it.

You should be handling it like this:

begin
  socket.connect_nonblock(sockaddr)
rescue Errno::EINPROGRESS 
  IO.select(nil, [socket]) #wait for socket to be writable
  begin
    socket.connect_nonblock(sockaddr)
  rescue Errno::EISCONN
    #=> This means connection to remote host has established successfully.
    socket.write("stuff")
  end
end

Upvotes: 2

Related Questions