# Socket problem

**URL:** <https://rubytalk.org/t/socket-problem/3699>\
**Category:** ruby-talk\
**Created:** [19 December 2002 02:53 UTC](https://rubytalk.org/t/socket-problem/3699 "2002-12-19T02:53:24Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Child](https://avatars.discourse-cdn.com/v4/letter/c/b9bd4f/32.png) [@Child](https://rubytalk.org/u/Child)\
**Post date:** [19 December 2002 02:53 UTC](https://rubytalk.org/t/socket-problem/3699/1 "2002-12-19T02:53:24Z")

</div>

Hello

I am new to ruby, but I think it’s excellent language - no doubt the  
best one (cleanest, fastest to write in etc.) I ever used 🙂

I’m trying to write a NNTP client and I encountered some problems with  
sockets. I have to read server response from socket. The response is  
multiline and ends with “.\r\n”. Is there any way to get whole response  
at once? At the moment I use gets and read the response line by line,  
which is horribly inefficient. In C program I used ioctl FIONREAD call  
to read number of available bytes and then fetched them with read, but  
can’t get this call working in ruby - always get “Bad address  
(Errno::EFAULT” error. And if I use recv with arbitrary number (eg.  
10000) it hangs forever.

Thanks for any help.

> **···**
>
> –  
> Marek Janukowicz  
> [http://starware.one.pl](http://starware.one.pl)

---

<div class="post-metadata">

**Author:** ![Nobuyoshi\_Nakada](https://avatars.discourse-cdn.com/v4/letter/n/edb3f5/32.png) [@Nobuyoshi\_Nakada](https://rubytalk.org/u/Nobuyoshi_Nakada)\
**Post date:** [19 December 2002 03:43 UTC](https://rubytalk.org/t/socket-problem/3699/2 "2002-12-19T03:43:39Z")

</div>

Hi,

> **···**
>
> At Thu, 19 Dec 2002 11:53:24 +0900, Child wrote:
> 
> > I’m trying to write a NNTP client and I encountered some problems with  
> > sockets. I have to read server response from socket. The response is  
> > multiline and ends with “.\r\n”. Is there any way to get whole response  
> > at once? At the moment I use gets and read the response line by line,  
> > which is horribly inefficient. In C program I used ioctl FIONREAD call  
> > to read number of available bytes and then fetched them with read, but  
> > can’t get this call working in ruby - always get “Bad address  
> > (Errno::EFAULT” error. And if I use recv with arbitrary number (eg.  
> > 10000) it hangs forever.
> 
> socket.gets(“\r\n.\r\n”)
> 
> –  
> Nobu Nakada

---

<div class="post-metadata">

**Author:** ![Ernest\_Ellingson1](https://avatars.discourse-cdn.com/v4/letter/e/90db22/32.png) [@Ernest\_Ellingson1](https://rubytalk.org/u/Ernest_Ellingson1)\
**Post date:** [19 December 2002 16:16 UTC](https://rubytalk.org/t/socket-problem/3699/3 "2002-12-19T16:16:39Z")

</div>

“Child” [child@t9.ds.pwr.wroc.pl](mailto:child@t9.ds.pwr.wroc.pl) wrote in message  
news:slrnb02blb.ejn.child@child.t9.ds.pwr.wroc.pl…

> Hello
> 
> I am new to ruby, but I think it’s excellent language - no doubt the  
> best one (cleanest, fastest to write in etc.) I ever used 🙂
> 
> I’m trying to write a NNTP client and I encountered some problems with  
> sockets. I have to read server response from socket. The response is  
> multiline and ends with “.\r\n”. Is there any way to get whole response  
> at once? At the moment I use gets and read the response line by line,  
> which is horribly inefficient. In C program I used ioctl FIONREAD call  
> to read number of available bytes and then fetched them with read, but  
> can’t get this call working in ruby - always get “Bad address  
> (Errno::EFAULT” error. And if I use recv with arbitrary number (eg.  
> 10000) it hangs forever.
> 
> Thanks for any help.
> 
> –  
> Marek Janukowicz  
> [http://starware.one.pl](http://starware.one.pl)

Below is a pretty basic server that makes use of “select” to do what you  
want to do.  
You have to be a little careful with “select”. I returns nil if nothing is  
going on  
with the read end of the socket. If something is there to read. It will  
return an  
array. However, it will also return an array of three empty arrays if the  
socket is closed  
on the other end, at least it does in Windows. Thus, the begin and rescue  
sections.  
Of course I’m assuming the protocol you are using doesn’t permit lines with  
only a \r\n unless  
the line marks the end of the data.

class SocketProc  
def initalize(session)  
@sess=session  
end  
def readIn()  
dataIn=“”  
while true  
begin  
foo=select([@sess],nil, nil, timeoutvalue)  
if foo  
bar=@sess.readline  
@dataIn.concat(bar)  
break if bar=~/^\r\n/  
end  
rescue  
@sess.close  
end  
end  
processData (dataIn)  
end  
def processData(dataIn)  
#do what you want including writing to @sess  
@sess.close  
end  
end

server=TCPServer.new(port)  
BasicSocket.do\_not\_reverse\_lookup=true  
#the do\_not\_reverse\_lookup is necessary if you want some speed. By default  
it is false.  
while (session=server.accept) do  
Thread.new(session) do |aSession|  
z=SocketProc.new(aSession)  
while aSession  
z.readIn  
end  
end  
end

---

<div class="post-metadata">

**Author:** ![Tanaka\_Akira1](https://avatars.discourse-cdn.com/v4/letter/t/a88e57/32.png) [@Tanaka\_Akira1](https://rubytalk.org/u/Tanaka_Akira1)\
**Post date:** [19 December 2002 03:47 UTC](https://rubytalk.org/t/socket-problem/3699/4 "2002-12-19T03:47:59Z")

</div>

In article [200212190343.gBJ3hZb22278@sharui.nakada.kanuma.tochigi.jp](mailto:200212190343.gBJ3hZb22278@sharui.nakada.kanuma.tochigi.jp),  
[nobu.nokada@softhome.net](mailto:nobu.nokada@softhome.net) writes:

> socket.gets(“\r\n.\r\n”)

Unfortunately it doesn’t work if the text response is empty.

> **···**
>
> –  
> Tanaka Akira

---

<div class="post-metadata">

**Author:** ![Nobuyoshi\_Nakada](https://avatars.discourse-cdn.com/v4/letter/n/edb3f5/32.png) [@Nobuyoshi\_Nakada](https://rubytalk.org/u/Nobuyoshi_Nakada)\
**Post date:** [19 December 2002 04:49 UTC](https://rubytalk.org/t/socket-problem/3699/5 "2002-12-19T04:49:14Z")

</div>

Hi,

> **···**
>
> At Thu, 19 Dec 2002 12:47:59 +0900, Tanaka Akira wrote:
> 
> > > socket.gets(“\r\n.\r\n”)
> > 
> > Unfortunately it doesn’t work if the text response is empty.
> 
> Hmm, then read the status response at first, and read the text  
> response if present, according to the protocol.
> 
> Fetching available data is possible with io/wait extension  
> library, but I don’t guess it’s reliable to determin the end of  
> input.
> 
> –  
> Nobu Nakada

---

<div class="post-metadata">

**Author:** ![Tanaka\_Akira1](https://avatars.discourse-cdn.com/v4/letter/t/a88e57/32.png) [@Tanaka\_Akira1](https://rubytalk.org/u/Tanaka_Akira1)\
**Post date:** [19 December 2002 05:04 UTC](https://rubytalk.org/t/socket-problem/3699/6 "2002-12-19T05:04:14Z")

</div>

In article [200212190449.gBJ4nBb24264@sharui.nakada.kanuma.tochigi.jp](mailto:200212190449.gBJ4nBb24264@sharui.nakada.kanuma.tochigi.jp),  
[nobu.nokada@softhome.net](mailto:nobu.nokada@softhome.net) writes:

> Hmm, then read the status response at first, and read the text  
> response if present, according to the protocol.

I expected following case.

> list active comp.lang.r\*  
> 215 Newsgroups in form “group high low flags”.  
> comp.lang.rexx 0000037710 0000037671 y  
> .  
> list active [comp.lang.ru](http://comp.lang.ru)\*  
> 215 Newsgroups in form “group high low flags”.  
> .

(Note that comp.lang.ruby is not exist in our news server.)

The client reads text response after status line.  
The status line is “215 … .\r\n”.

So, socket.gets(“\r\n.\r\n”) works on “list active comp.lang.r\*” but  
not on “list active [comp.lang.ru](http://comp.lang.ru)\*”. Because the text response with  
terminator is only “.\r\n” which is not terminated by “\r\n.\r\n”.

> Fetching available data is possible with io/wait extension  
> library, but I don’t guess it’s reliable to determin the end of  
> input.

I think ungetc can solve the problem by unget “\r\n” before reading  
a text response. But stdio doesn’t support more than one byte with  
ungetc.

> **···**
>
> –  
> Tanaka Akira

---

<div class="post-metadata">

**Author:** ![Nobuyoshi\_Nakada](https://avatars.discourse-cdn.com/v4/letter/n/edb3f5/32.png) [@Nobuyoshi\_Nakada](https://rubytalk.org/u/Nobuyoshi_Nakada)\
**Post date:** [19 December 2002 05:25 UTC](https://rubytalk.org/t/socket-problem/3699/7 "2002-12-19T05:25:26Z")

</div>

Hi,

At Thu, 19 Dec 2002 14:04:14 +0900,

> > Hmm, then read the status response at first, and read the text  
> > response if present, according to the protocol.
> 
> I expected following case.
> 
> > list active comp.lang.r\*  
> > 215 Newsgroups in form “group high low flags”.  
> > comp.lang.rexx 0000037710 0000037671 y  
> > .  
> > list active [comp.lang.ru](http://comp.lang.ru)\*  
> > 215 Newsgroups in form “group high low flags”.  
> > .
> 
> (Note that comp.lang.ruby is not exist in our news server.)
> 
> The client reads text response after status line.  
> The status line is “215 … .\r\n”.
> 
> So, socket.gets(“\r\n.\r\n”) works on “list active comp.lang.r\*” but  
> not on “list active [comp.lang.ru](http://comp.lang.ru)\*”. Because the text response with  
> terminator is only “.\r\n” which is not terminated by “\r\n.\r\n”.

Sorry, misunderstood.

response = socket.gets  
if response.has\_text?  
while s = socket.gets(“.\r\n”)  
response \<\< s  
break if /^.\r\n\z/ =~ s  
end  
end

> > Fetching available data is possible with io/wait extension  
> > library, but I don’t guess it’s reliable to determin the end of  
> > input.
> 
> I think ungetc can solve the problem by unget “\r\n” before reading  
> a text response. But stdio doesn’t support more than one byte with  
> ungetc.

ungetc(?\n) and gets(“\n.\r\n”) ?

> **···**
>
> –  
> Nobu Nakada

---

<div class="post-metadata">

**Author:** ![Tanaka\_Akira1](https://avatars.discourse-cdn.com/v4/letter/t/a88e57/32.png) [@Tanaka\_Akira1](https://rubytalk.org/u/Tanaka_Akira1)\
**Post date:** [19 December 2002 05:56 UTC](https://rubytalk.org/t/socket-problem/3699/8 "2002-12-19T05:56:42Z")

</div>

In article [200212190525.gBJ5PNb24601@sharui.nakada.kanuma.tochigi.jp](mailto:200212190525.gBJ5PNb24601@sharui.nakada.kanuma.tochigi.jp),  
[nobu.nokada@softhome.net](mailto:nobu.nokada@softhome.net) writes:

> ungetc(?\n) and gets(“\n.\r\n”) ?

Wow. It will work… especially if a news server spools articles in  
LF-form.

> **···**
>
> –  
> Tanaka Akira

---

<div class="post-metadata">

**Author:** ![Child](https://avatars.discourse-cdn.com/v4/letter/c/b9bd4f/32.png) [@Child](https://rubytalk.org/u/Child)\
**Post date:** [19 December 2002 11:35 UTC](https://rubytalk.org/t/socket-problem/3699/9 "2002-12-19T11:35:38Z")

</div>

> response = socket.gets  
> if response.has\_text?  
> while s = socket.gets(“.\r\n”)  
> response \<\< s  
> break if /^.\r\n\z/ =~ s  
> end  
> end

It is exactly the way I do it at the moment - very slow (speed is very  
important when fetching a lot of headers/bodies)

> > I think ungetc can solve the problem by unget “\r\n” before reading  
> > a text response. But stdio doesn’t support more than one byte with  
> > ungetc.
> 
> ungetc(?\n) and gets(“\n.\r\n”) ?

This one should be good.

Thank you for all your answers. Speed is essential to me only when  
fetching headers (and I think I can expect no empty headers), so I can  
use the “gets (”\r\n.\r\n")" form. I made some tests and the profiler  
shows (in a simple example - fetching all articles in group) that the  
time used by the fetching method is now about 10-15% instead of 40-50%  
:). So I think I’ll use one “gets …” when fetching headers, and  
ungetc/loop/whatever in other cases.

Thanks once again!

> **···**
>
> On Thu, 19 Dec 2002 14:25:26 +0900, [nobu.nokada@softhome.net](mailto:nobu.nokada@softhome.net) wrote:
> 
> –  
> Marek Janukowicz

---

<div class="post-metadata">

**Author:** ![Greg\_Millam1](https://avatars.discourse-cdn.com/v4/letter/g/8797f3/32.png) [@Greg\_Millam1](https://rubytalk.org/u/Greg_Millam1)\
**Post date:** [19 December 2002 11:40 UTC](https://rubytalk.org/t/socket-problem/3699/10 "2002-12-19T11:40:28Z")

</div>

This all reminds me - is there a way to make a socket nonblocking?  
like O\_NONBLOCK in C’s socket() call.

It would seem to me if it could be made nonblocking, a simple call to  
sock.readlines() would return all data that has already come in, instead  
of hanging until it’s closed like it does with blocking sockets.

Just a thought.

- Greg

> **···**
>
> –  
> Greg Millam  
> walker at [deafcode.com](http://deafcode.com)

---

<div class="post-metadata">

**Author:** ![Nobuyoshi\_Nakada](https://avatars.discourse-cdn.com/v4/letter/n/edb3f5/32.png) [@Nobuyoshi\_Nakada](https://rubytalk.org/u/Nobuyoshi_Nakada)\
**Post date:** [19 December 2002 13:46 UTC](https://rubytalk.org/t/socket-problem/3699/11 "2002-12-19T13:46:05Z")

</div>

Hi,

> This all reminds me - is there a way to make a socket nonblocking?  
> like O\_NONBLOCK in C’s socket() call.
> 
> It would seem to me if it could be made nonblocking, a simple call to  
> sock.readlines() would return all data that has already come in, instead  
> of hanging until it’s closed like it does with blocking sockets.

It’ll return when the next data just doesn’t arrive yet.

# io/nonblock.rb

require “fcntl”  
class IO  
def nonblock?  
(fcntl(Fcntl::F\_GETFL) & File::NONBLOCK) != 0  
end

def nonblock=(nb)  
f = fcntl(Fcntl::F\_GETFL)  
if nb  
f |= File::NONBLOCK  
else  
f &= ~File::NONBLOCK  
end  
fcntl(Fcntl::F\_SETFL, f)  
end

def nonblock(nb = true)  
nb, self.nonblock = nonblock?, nb  
yield  
ensure  
self.nonblock = nb  
end  
end

> **···**
>
> At Thu, 19 Dec 2002 20:40:28 +0900, Greg Millam wrote:
> 
> –  
> Nobu Nakada
