Ruby readpartial and read_nonblock not throwing EOFError Ruby readpartial and read_nonblock not throwing EOFError unix unix

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, so gets will never meet an EOFError.

  • 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, so read will never meet an EOFError.

  • readpartial(maxlen) reads at most maxlen bytes from stream, it will read available data and return immediately, it's kind like a eager version of read, if the data is too large you can use readpartial instead of read to prevent from blocking, but it's still a block method, it blocks if no data available immediately, readpartial will raises an EOFError if receives an EOF.

  • read_nonblock(maxlen) is kind like readpartial, but like the name said it's a nonblock method, even no data available it raise an Errno::EAGAIN immediately it means no data right now, you should care about this error, normally in Errno::EAGAIN rescue clause should call IO.select([conn]) first for less unnecessary cycle, it will block until the conn becomes available to read, then retry, read_nonblock will raises an EOFError 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.