I love Ruby. Completely. I don't want to write in anything else. However, meeting with the BSD sockets interface left me with a sour taste. Here's what I learned. Hopefully, you'll find this post and won't waste time if you have to work with Ruby's sockets.
You can send packets with send
The method name is good for consistency, but a horrible choice in general, if you ask me, because it overrides
send in Object (used to send a message to an object, same thing as calling a method).
send's parameters are a string representing the data (same encoding as in
recv), and a number for flags. The number is NOT optional (messed up choice, in my opinion), so my sockets code always has
send data, 0 in it.
send fails oddlyIf you're seeeing
in `send': symbol string may not contain `\0' (ArgumentError) then your socket is object is null. This happens because nil uses Object's send, so it thinks you're passing it a method name.
pack_sockaddr_in doesn't like localhost
Silly me, I looked the example using
www.google.com and I thought I can give pack_sockaddr_in any address. If I give it
localhost, I get
in `connect': Invalid argument - connect(2) (Errno::EINVAL).
Solution: use
127.0.0.1Using strings for send / recv is annoyingIf I'm using sockets, I'm working at the byte level. Using Fixnum arrays to represent bytes in a packet is a lot more convenient than using strings. Here are snippers for converting between the two formats. (I did Scheme at MIT, so I love
map-
reduce... I meant,
collect-
inject).
bytes > string:
block_string = block.flatten.map { |value| value.chr }.join('')
string > bytes:
block = (0...block_string.length).map { |i| block_string[i] }
That's about it. Hope this helps someone!
Victor