I have been trying to understand the basic idea behind UDP hole punching, and I'm having trouble understanding the difference between the following two socket bindings:
sock = UDPSocket.new
sock.bind('', port )
and
sock = UDPSocket.new
sock.bind('0.0.0.0', port)
Previously I had thought using '' or '0.0.0.0' did the same thing -- allow the socket to listen on any network interface -- but since the code didn't work with them interchanged I must be missing something.
For the initial 'punch' the datagram is sent from a socket bound to '', which is then closed and the actual communication with the remote host is done over a socket bound to 0.0.0.0. I know 0.0.0.0 generally refers to the default route, but I can't figure out the significance of that in this situation. Does binding a socket to 0.0.0.0 mean you're assigning it the address of the default gateway?
Looks like both provides the same behavior: your socket is listening on all interfaces on given port:
ruby 38156 grych 7u IPv4 0x40a92a845129cab1 0t0 UDP *:6666
My system is Darwin 14.0 (OS X Mavericks), ruby 2.0.0 - I am wondering if it depends on the OS.
I had already created a qt program that listens on a specific port on my server. And it works fine. Now I want to create a simple ruby program to do the same. Right now I just have a simple test server using netcat which establishes a network socket and accepts UDP data (this is Ubuntu server by the way):
$ sudo nc -l 1720
Now I am just trying to listen on the port in Ruby:
# network.rb
require 'socket'
socket = UDPSocket.new
socket.bind('64.xxx.xx.xxx', 1720)
This right away raises this exception:
network.rb:4:in `bind': Cannot assign requested address - bind(2) (Errno::EADDRNOTAVAIL)
WHy is it saying the address is not available? All that is there is a netcat socket. The goal is that I will have UDP data coming in from GPRS devices to that port, and then I will have ruby sitting on my ubuntu server listening for that data, then decoding it, and storing it into a postgresql database.
You are making a server or client?
you used nc, so i guess you are making client.
server is bind
client is connect:
c = UDPSocket.new
c.connect("127.0.0.1", 1111)
"address is not available" usually as the port is used.
or you can ping the address fisrt to check if the address can be reached
I was getting the same error by running:
rails s -b 10.0.0.61
It turns out that my local IP wasn't 10.0.0.61 and this was causing the error.
I am having trouble to bind to a server address. I have a connection, to a server (using Savon XML Library). Now I just need to listen to that server and gather its HTTP packets that sends. The server each time sends:
http://200.34.12.168/Videos/1/frame/0
http://200.34.12.168/Videos/1/frame/1
http://200.34.12.168/Videos/1/frame/2
http://200.34.12.168/Videos/1/frame/3
http://200.34.12.168/Videos/1/frame/4
...
..
which are HTTP packets. I am trying to create a UDP server that listens to these. This is what I have so far:
s = UDPSocket.new
s.bind('200.34.12.168', 80)
5.times do
text, sender = s.recvfrom(16)
puts text
end
it fails at the bind function. How can I listen to a UDP connection with ruby?
The Error I get:
"`bind': Can't assign requested address - bind(2) (Errno::EADDRNOTAVAIL)"
Do you have a web browser running - it may already be bound to port 80..
My windows system has the firewall enabled.
I would like to allow incoming connections on a particular port (say: 4546).
Is there a ruby library that can help me do this ?
Detail:
I have a sinatra application (webserver) running on port 4546. I needed to bring down the firewall in order for it to work.
I am looking for a way to not keep the port 4546 under the firewall list.
Yes, you can do that with this:
require 'socket' # Get sockets from stdlib
server = TCPServer.open(4546) # Socket to listen on port 4546
loop { # Servers run forever
client = server.accept # Wait for a client to connect
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close # Disconnect from the client
}
I've written this ruby program to send a UDP Packet to port 16800:
require 'socket'
sock = UDPSocket.new
sock.bind("", 47123)
sock.send("Hello!", 0, "192.168.0.100", 16800)
sock.close
where 192.168.0.100 is my own ip address. However, the packet doesn't show in Wireshark and my UDP server listening on port 16800 on the same PC (running Linux) isn't receiving anything.
When I slightly rewrite the program to
require 'socket'
sock = UDPSocket.new
sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
sock.bind("", 47123)
sock.send("Hello!", 0, "<broadcast>", 16800)
sock.close
the packet does show up in Wireshark, but my server still isn't receiving anything.
Am I missing something obvious?
EDIT:
The server code, for completeness
require 'socket'
sock = UDPSocket.new
sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
sock.bind(nil, 16800)
while true
packet = sock.recvfrom(1024)
puts packet
end
However, this was copied somewhere from the internet, and while editing it for stackoverflow, i found out that the server always receives packets sent to 127.0.0.1 but when I change nil to "", the server suddenly also receives the packets sent above. Is this a bug in the ruby socket implementation?
I just used your very code and the problem is you're not binding to a specific IP address. I don't know about Linux but on OS X there's an issue where sometimes the default will attach to an unused IP6 address rather than the interface you were expecting.
Changing "" to 192.168.1.255 on the server, and including "192.168.1.255" on the bind in the client made all this work for me :)
UDPSocket.BIND takes a host and a port. Try changing the nil to your IP address. From http://coderrr.wordpress.com/2008/05/28/get-your-local-ip-address/; use
require 'socket'
def local_ip
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
UDPSocket.open do |s|
s.connect '64.233.187.99', 1
s.addr.last
end
ensure
Socket.do_not_reverse_lookup = orig
end
to get your IP
Have you tried sending to "localhost" or "127.0.0.1"? This will send directly to the local computer and will help diagnose the problem further.
Kind of speculating here, but you might want to consider something like this - when you use the computer's own IP, the packets aren't visible on the physical link b/c the tcp/ip stack doesn't have to push them that far to get them where they are going, it can turn them around internally to the computer at one of the higher layers in that seven-layer stack model (the 'transport' layer, perhaps?)
If such a connection is supposed to work, and you see the packages using Wireshark, then you should also check the software firewall on your machine. If it blocks traffic to the UDP port you want to use you can still see the package using Wireshark!