gen_tcp容易误用的一点解释
July 1st, 2011
原创文章,转载请注明: 转载自系统技术非业余研究
本文链接地址: gen_tcp容易误用的一点解释
前天有同学在玩erlang gen_tcp的时候碰到了点小麻烦,描述如下:
比如说连接到baidu.com,发个http请求,然后马上接收数据,发现接收出错,wireshark抓包发现数据都有往返发送,比较郁闷。
我把问题演示下:
$ erl Erlang R14B03 (erts-5.8.4) [source] [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<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<HTML><HEAD>\n<TITLE>400 Bad Request</TITLE>\n</HEAD><BODY>\n<H1>Bad Request</H1>\nYour browser sent a request that this server could not understand.<P>\nclient sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): /<P>\n</BODY></HTML>\n\r\n0\r\n\r\n"} ok 5>
搞清楚了问题,那解决方案很简单,connect的时候把active模式设成{active,false}.
再来演示下:
$ erl Erlang R14B03 (erts-5.8.4) [source] [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<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<HTML><HEAD>\n<TITLE>400 Bad Request</TITLE>\n</HEAD><BODY>\n<H1>Bad Request</H1>\nYour browser sent a request that this server could not understand.<P>\nclient sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): /<P>\n</BODY></HTML>\n\r\n0\r\n\r\n"} 4>
搞定!
玩得开心!
Post Footer automatically generated by wp-posturl plugin for wordpress.
不懂,我是初学者,最后一句话是什么意思?
能给出正确的写法么?
Yu Feng Reply:
July 1st, 2011 at 1:23 pm
已经写在文里了,谢谢你的提醒!
呵呵,多谢多谢,刚接触了一个星期的ERLANG,觉得很有趣的语言+平台,也开始翻看你之前博客的帖子了。我看你也正在写书,很期待
greate !!
嗯 嗯 设置为true也不能进行流量控制
在doc中的示例代码中 它使用了{active,false}后在accept之后再设置了一下{active,once}
谢谢菊苣的blog的说~erlang资料除了看看doc 书 还有官方example之外 这里最好啦^_^