how to read from a TCP socket line by line

Luke Gorrie luke@REDACTED
Wed Aug 15 17:30:58 CEST 2001


Daniel Solaz <dsolaz@REDACTED> writes:

I got tips and tricks for these, curtesy of tony rogvall:

> Ah yes, now I see it in the docs, but they say:
> "line mode, a packet is a line terminated with newline, lines longer 
> than the receive buffer are truncated"
> 
> What does the last part mean?  If "truncated" means what I think it 
> means, how do I ensure my buffer is large enough when reading binary 
> data?

You can use the {buffer, ByteSize} option when opening the socket to
say how long the buffer should be. If a line is longer than that, then
you'll get it in several parts (only the last containing a
newline). So for long lines maybe you'll need to concatenate them
yourself, I'm not sure if there's a practical limit on the socket
buffer size.

> Note that after reading the HTTP response header line by line I should 
> switch to buffer mode (using gen_tcp:recv/3), since the response body 
> may be binary data.
> 
> In Modula-3 I've solved this using "read one line" and "read one 
> buffer" methods on the same reader.  But in Erlang it seems I either 
> open the socket in active mode and get lines as messages, or open the 
> socket in passive mode and get buffers.

You can do packet-based reads both as messages and with
gen_tcp:recv. The trick with recv is to have the socket in packet
mode, and pass a length of 0.

Here's an example, using a buffer size too small to get the whole
line:

  13> {ok, S} = gen_tcp:connect("mail.bluetail.com", 25, [{active, false}, {packet, line}, {buffer, 40}]).
  {ok,#Port<0.10>}
  14> gen_tcp:recv(S, 0).
  {ok,"220 mail.bluetail.com ESMTP BLUETAIL Mai"}
  15> gen_tcp:recv(S, 0).
  {ok,"l Robustifier (2.2.2/3.1.2); Wed, 15 Aug"}
  16> gen_tcp:recv(S, 0).
  {ok," 2001 17:16:59 +0200\r\n"}

When you've finished reading the headers, you can take the socket out
of line mode with:

  inet:setopts(S, [{packet, raw}])

Then you can read the body.

There are also some nifty tricks in the inet module:

You can find out the default/current settings for a socket, e.g:

  32> {ok, S} = gen_tcp:connect("mail.bluetail.com", 25, []).
  {ok,#Port<0.14>}        
  33> inet:getopts(S, [buffer, active, packet]).             
  {ok,[{buffer,1024},{active,true},{packet,0}]}

If you want to see all options, then you can call inet:options() to
get the complete list and pass that in for the second argument of
getopts/2.

Another nice thing is inet:i() which is like a "netstat" for erlang
showing all open sockets:

  35> inet:i().
  Port Module   Recv Sent Owner    Local Address       Foreign Address      State     
  13   inet_tcp 0    0    <0.54.0> 192.168.128.43:4371 192.168.128.251:smtp CONNECTED 
  14   inet_tcp 102  0    <0.54.0> 192.168.128.43:4373 192.168.128.251:smtp CONNECTED 
  Port Module Recv Sent Owner Local Address Foreign Address State 
  ok





More information about the erlang-questions mailing list