gen_tcp容易误用的一点解释

前天有同学在玩erlang gen_tcp的时候碰到了点小麻烦,描述如下:

比如说连接到baidu.com,发个http请求,然后马上接收数据,发现接收出错,wireshark抓包发现数据都有往返发送,比较郁闷。

我把问题演示下:

 
$ erl
Erlang R14B03 (erts-5.8.4) 1 [64-bit] [smp:16:16] [rq:16] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.4  (abort with ^G)
1> {ok,Sock} = gen_tcp:connect("baidu.com", 80, []).
{ok,#Port<0.582>}
2> gen_tcp:send(Sock, "GET / HTTP/1.1\r\n\r\n").
ok
3> gen_tcp:recv(Sock,0).
{error,einval}

这个问题的根源在于gen_tcp默认的{active,true},也就是说当gen_tcp收到网络包的时候,默认是把报文发送给它的宿主进程。而gen_tcp:recv是用户主动去拉数据,这二个模式是互斥的。

我们来看下代码otp/erts/emulator/drivers/common/inet_drv.c:7462

case TCP_REQ_RECV: {
..
        if (desc->inet.active || (len != 8))
            return ctl_error(EINVAL, rbuf, rsize);
..

那就解释为什么 gen_tcp:recv(Sock,0)返回错误码{error,einval}。
同时我们来验证下,报文是以消息的方式发送的。

 
4> flush().
Shell got {tcp,#Port<0.582>,
               "HTTP/1.1 400 Bad Request\r\nDate: Fri, 01 Jul 2011 03:51:25 GMT\r\nServer: Apache\r\nConnection: Keep-Alive\r\nTransfer-Encoding: chunked\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n127\r\n\n\n400 Bad Request\n\n

Bad Request

\nYour browser sent a request that this server could not understand.

\nclient sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): /

\n\n\r\n0\r\n\r\n"} ok 5>

搞清楚了问题,那解决方案很简单,connect的时候把active模式设成{active,false}.
再来演示下:

$ erl
Erlang R14B03 (erts-5.8.4) 1 [64-bit] [smp:16:16] [rq:16] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.8.4  (abort with ^G)
1> {ok,Sock} = gen_tcp:connect("baidu.com", 80, [{active,false}]).
{ok,#Port<0.582>}
2> gen_tcp:send(Sock, "GET / HTTP/1.1\r\n\r\n").
ok
3>  gen_tcp:recv(Sock,0).
{ok,"HTTP/1.1 400 Bad Request\r\nDate: Fri, 01 Jul 2011 05:25:15 GMT\r\nServer: Apache\r\nConnection: Keep-Alive\r\nTransfer-Encoding: chunked\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n127\r\n\n\n400 Bad Request\n\n

Bad Request

\nYour browser sent a request that this server could not understand.

\nclient sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): /

\n\n\r\n0\r\n\r\n"} 4>

搞定!

玩得开心!

你可能感兴趣的:(gen_tcp)