3.Socket

  说到socket就会想到tcp、udp、http协议,先来分析一下erlang项目中如何使用tcp socket。

  RabbitMQ项目中使用了prim_inet:async_accept/2、prim_inet:async_recv/3等方法,这些是相对比较底层的api,在erlang官方文档中并没有介绍,不过我们可以通过源码看到,最终会进到erlang:port_control/3函数,与端口进行交互。然后我们进到gen_tcp模块,可以看到无论是调用了inet_tcp还是inet6_tcp,最终还是会回到prim_inet模块。因此gen_tcp是对prim_inet进行包装,是更高层的socket调用模块,用gen_tcp写socket层,代码也会更清理明了。
  使用gen_tcp模块收到内核协议栈过来完整的封包的时候,可以通过init:setopts/2设置接收消息的方式。官方文档:http://www.erlang.org/doc/man/inet.html
  {active, true | false | once | N}:true时,所有收到的信息都会被传递到接收进程;false时,只能接收通过gen_tcp:recv/2,3, gen_udp:recv/2,3 or gen_sctp:recv/1,2等函数接收到信息;once时,每次收到信息后需要手动重置,以待下次接收。这里讨论一下N,N可以理解为once的扩展,once是每收到一条信息都需要重置,而N则是收到N条信息后重置一次。参数N是OTP 17.0以后的版本才能使用。下面有个简单的例子:
-module(sockettcp).  
-export([start/0]).  
start() ->  
  {ok, LSock} = gen_tcp:listen(1234, [binary, {packet, 0},{active, false}]),  
  io:format("listen(~p) on ~p~n",[LSock, 1234]),  
  accept(LSock).  
accept(LSock) ->  
  {ok, ASock} = gen_tcp:accept(LSock),   
  Pid = spawn(fun() -> do_loop(ASock) end),  
  gen_tcp:controlling_process(ASock, Pid),  
  inet:setopts(ASock, [{active, 3}]),  
  accept(LSock).  
do_loop(ASock) ->  
  receive  
    {tcp, Socket, Data} ->  
       io:format("(~p)recv:~p~n",[Socket, Data]);  
    {tcp_passive,Socket} ->   
       inet:setopts(ASock, [{active, 3}]),  
       io:format("tcp_passive:~p~n",[Socket]);
    Err ->
       io:format("error:~p~n",[Err])
  end,
  do_loop(ASock).
  再开一个shell作为客户端输入:
{ok,S} = gen_tcp:connect({127,0,0,1},1234,[{packet,0}]).
gen_tcp:send(S, integer_to_binary(1)).
gen_tcp:send(S, integer_to_binary(1)).
gen_tcp:send(S, integer_to_binary(1)).
gen_tcp:send(S, integer_to_binary(1)).
  可以看到每间隔3个包,需要重置一次参数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值