Ruby readpartial and read_nonblock not throwing EOFError
First i wanna talk about some basic knowledge, EOF means end of file, it's like signal will send to caller when there is no more data can be read from data source, for example, open a File and after read the entire file will receives an EOF, or just simple close the io stream.
Then there are several differences between these 4 methods
gets
reads a line from stream, in ruby it uses$/
as the default line delimiter, but you can pass a parameter as line delimiter, because if the client and server are not the same operating system, the line delimiter maybe different, it's a block method, if never meet a line delimiter or EOF it will block, and returns nil when receives an EOF, sogets
will never meet anEOFError
.read(length)
reads length bytes from stream, it's a block method, if length is omitted then it will block until read EOF, if there is a length then it returns only once has read certain amount of data or meet EOF, and returns empty string when receives an EOF, soread
will never meet anEOFError
.readpartial(maxlen)
reads at most maxlen bytes from stream, it will read available data and return immediately, it's kind like a eager version ofread
, if the data is too large you can usereadpartial
instead ofread
to prevent from blocking, but it's still a block method, it blocks if no data available immediately,readpartial
will raises anEOFError
if receives an EOF.read_nonblock(maxlen)
is kind likereadpartial
, but like the name said it's a nonblock method, even no data available it raise anErrno::EAGAIN
immediately it means no data right now, you should care about this error, normally inErrno::EAGAIN
rescue clause should callIO.select([conn])
first for less unnecessary cycle, it will block until the conn becomes available to read, thenretry
,read_nonblock
will raises anEOFError
if receives an EOF.
Now let's see your example, as i see what you are doing is try to read data by "hitting the url" first, it's just a HTTP GET request, some text like "GET / HTTP/1.1\r\n", connection are keep alive in HTTP/1.1 by default, so using readpartial
or read_nonblock
will never receive an EOF, unless put Connection: close
header in your request, or change your gets method as below:
buffer = ""if m = @client.gets buffer << m break if m.strip == ""else breakendbuffer
You can't use read
here, because you don't know the exact length of the request package, use large length or just simply omitted will cause block.