# How to do INTERESTING things with Ruby sockets?

**URL:** <https://www.ruby-forum.com/t/how-to-do-interesting-things-with-ruby-sockets/87948>\
**Category:** Ruby\
**Created:** [March 7, 2007, 2:36am UTC](https://www.ruby-forum.com/t/how-to-do-interesting-things-with-ruby-sockets/87948 "2007-03-07T02:36:01Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 7, 2007, 2:36am UTC](https://www.ruby-forum.com/t/how-to-do-interesting-things-with-ruby-sockets/87948/1 "2007-03-07T02:36:01Z")

</div>

I’ve done quite a bit of reading about socket programming in Ruby, but  
most of the examples show simple cases of accepting a socket  
connection, spitting out some fixed bit of data, and then closing.  
What about socket connections where you can’t predict the length or  
timing of data that you’ll receive? None of the available web pages  
give any hint of how to work interactively with sockets.

Here are a few things that I was hoping maybe some knowledgable people  
could help me figure out how to do with sockets in Ruby:

- Block until 1 or more bytes have been received, and then return as  
many as have arrived (even if fewer than some buffer size)

- Block until a fixed number of bytes have been received, or a time-  
out has elapsed

- Check how many bytes have been received without blocking

- Detect when the other end has closed the socket

- Distinguish between a timeout and a closed socket

Thank you for your help!

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 7, 2007, 2:50am UTC](https://www.ruby-forum.com/t/how-to-do-interesting-things-with-ruby-sockets/87948/2 "2007-03-07T02:50:02Z")

</div>

On 3/6/07, removed\_email\_address@domain.invalid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> - Distinguish between a timeout and a closed socket  
> You don’t say if this is a learning exercise in low-level socket  
> programming  
> or if you actually have to develop an app. If it’s the latter, you may  
> want  
> to look at the Ruby/EventMachine library. It wraps up the low-level  
> socket  
> issues so you can concentrate on the app-level code.

---

<div class="post-metadata">

**Author:** ![casper\_the\_ghost](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/58956e/32.png) [@casper\_the\_ghost](https://www.ruby-forum.com/u/casper_the_ghost)\
**Post date:** [March 7, 2007, 8:10pm UTC](https://www.ruby-forum.com/t/how-to-do-interesting-things-with-ruby-sockets/87948/3 "2007-03-07T20:10:42Z")

</div>

In article [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid),  
“removed\_email\_address@domain.invalid” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> I’ve done quite a bit of reading about socket programming in Ruby, but  
> most of the examples show simple cases of accepting a socket  
> connection, spitting out some fixed bit of data, and then closing.  
> What about socket connections where you can’t predict the length or  
> timing of data that you’ll receive? None of the available web pages  
> give any hint of how to work interactively with sockets.

To do the things that you seem to want to do, you will need to  
program to the low-level “Berkeley” socket interface. This is the  
interface adopted by both the UNIX/POSIX/Linux and Microsoft WINSOCK  
specifications, with slight alterations, of course. Ruby exposes these  
through the ‘socket’ library.

> Here are a few things that I was hoping maybe some knowledgable people  
> could help me figure out how to do with sockets in Ruby:
> 
> - Block until 1 or more bytes have been received, and then return as  
> many as have arrived (even if fewer than some buffer size)

This is the default behavior of the socket API.

> - Block until a fixed number of bytes have been received, or a time-  
> out has elapsed

To wait for a “full” buffer, you can use the MSG\_WAITALL flag to  
recv\* to wait for a full buffer. A timeout would be effected by  
using SO\_RCVTIMEO at the underlying API, but that doesn’t work  
under Ruby due to a deficiency in the user-mode threads implementation.

In any case, the underlying APIs do not let you mix the two  
concepts. If a timeout were to occur, a partial buffer would be  
returned if _any_ data were available. There is no way to eliminate  
the possibility of a partial read while still enabling a timeout.

> - Check how many bytes have been received without blocking

There is no portable way to do this, and I recommend strongly  
against it. However, if you must, most UNIX-inspired and WINSOCK  
systems support the FIONBIO ioctl. Most implementations try to  
give you an estimate of the number of octets that are available,  
but this estimate is often low (and on some systems is simply  
zero/one).

> - Detect when the other end has closed the socket

The only way to to do this portably (or easily) is to read the  
available data. When you read zero bytes, you have read all the  
available data, and the connection has been closed. There is no  
portable way to determine the reason (possible causes include at  
least a remote close, a remote reset, and a force close initiated  
by the local host).

> - Distinguish between a timeout and a closed socket

I’m presuming that you mean here a timeout on a read call and not  
the local host closing the socket. In that case, I don’t know of  
any way to do that straight-forwardly in Ruby in a single call,  
so I’d recommend the use of select with a non-blocking socket. I  
attach an example below. You should carefully read the Ruby and  
platform documentation on fcntl and select.

A few notes on the example below:

- It implements a client reader for RFC 868 (Time Protocol). This  
was an experiment in using Ruby and I’ve only exercised this  
program on UNIX/POSIX/Linux systems. I have exercised analogous,  
but non-Ruby programs, under WINSOCK.

- The use of non-blocking sockets is not mandatory. The program  
should generally work without setting this mode, but there then  
might be a few rare cases where the program pauses inexplicably  
for indeterminate periods of time.

* * *

#! /usr/bin/env ruby

# rb\_getnettime3 - an alternate form that uses a select call to effect

# a timeout when polling unresponsive hosts.

require ‘socket’  
require ‘fcntl’

hostname = (ARGV.length \> 0) ? ARGV[0] : ‘127.0.0.1’

timeport = Socket.getservbyname(‘time’, ‘udp’) # port 37  
RFC868\_POSIX\_ADJMENT = 2\_208\_988\_800 # diff between RFC 868 and POSIX

tsecs = 5

rmttime = 0  
begin  
rcvd = nil  
UDPSocket.open { |sock|  
origflags = sock.fcntl(Fcntl::F\_GETFL, 0)  
sock.fcntl(Fcntl::F\_SETFL, origflags |  
Fcntl::O\_NONBLOCK)

```
            sock.send('', 0, hostname, timeport)

            IO.select([sock], [], [], tsecs) or raise 'receive time 

```

out’

```
            rcvd = sock.recvfrom(4, 0) # read in one 'N'
    }
    raise 'Bad format in response' unless rcvd.length == 2

    data, rmthost = rcvd
    raise 'Invalid response from remote host' unless data.length == 

```

4

```
    rmttime = data.unpack('N')[0]

```

rescue RuntimeError =\> msg  
abort “Call to time port failed: #{msg}”  
end

adjtime = rmttime - RFC868\_POSIX\_ADJMENT  
puts “Remote time: #{Time.at(adjtime)}”
