erlang 监听高并发socket

原文 2014-05-29 22:58:26 发表于 CSDN,这里对以前写的文章做下收录。

看了erlang的一些开源网络框架RabbitMQ、Ranch,他们都使用多个进程同时accept一个socket。这种方式在使得socket端口监听的工作分担了更多的调度机会,但是,在erlang中,socket接受一个新连接后,如果想让另一个进程处理消息,就要显式的调用gen_tcp:controlling_process(Socket, Pid)。

所以问题来了,erlang多个进程同时监听一个socket安全吗?
这种方式在早期的erlang是不安全的,但R11B03 版本之后,erlang做了改进,允许多个进程同时监听同一个socket。

erlang R11B03 更新日志
OTP-6416 gen_tcp now allows for several processes to issue accept calls to the same listen-socket simultaniously. The different accepting processes will get connected sockets on a first-come-first-served basis.

当多个进程同时accept一个socket,erlang 内部将使用队列保存acceptor信息,以先来先服务的原则将新的连接关联到acceptor,再给acceptor投递消息 {inet_async, L, Ref, Result}。
具体看\erts\emulator\drivers\common\inet_drv.c 的 tcp_inet_ctl 函数,erlang对socket的处理都集中在inet_drv.c

erlang配合{backlog, N},监听新连接效果更佳
backlog是erlang用来设置socket等待连接队列。N为队列的长度,默认值5,显然太小了

erlang binary 数据转换问题

原文 2015-01-12 00:11:27 发表于 CSDN,这里对以前写的文章做下收录。

erlang 提供 binary_to_term,把一个二进制数据转为原始的 erlang 数据。但是,这个函数也有副作用。如果直接将对端传来的数据做一次 binary_to_term,就有可能导致VM crash掉。

binary_to_term 副作用
这是因为二进制数据带有原子时,binary_to_term 会生成这些原子。但VM原子总数是有限制,而且原子不参与GC。假如数据带有原子数量超过erlang VM限制,就会导致VM crash
所以,针对这个问题,erlang提供了另外一个函数 binary_to_term(Binary, [safe]),这个函数不会生成新的的原子,在这点上,这两个函数关系也像 list_to_atom 和 list_to_existing_atom

1> term_to_binary(atom).
<<131,100,0,4,97,116,111,109>>
2> binary_to_term(v(1), [safe]).
atom
3> binary_to_term(v(1)).
atom
4> binary_to_term(<<131,100,0,4,116,101,115,116>>, [safe]).
%%这里会抛出异常
** exception error: bad argument
     in function  binary_to_term/2
        called as binary_to_term(<<131,100,0,4,116,101,115,116>>,[safe])
5> binary_to_term(<<131,100,0,4,116,101,115,116>>).
test
6> binary_to_term(<<131,100,0,4,116,101,115,116>>, [safe]).
%%这里就不会抛出异常
test

继续阅读erlang binary 数据转换问题

erlang二进制数据垃圾回收

原文 2014-06-10 01:01:57 发表于 CSDN,这里对以前写的文章做下收录。

erlang 二进制数据在内存中有两种存在形式,当数据大小不到 64 bytes,就直接存在进程堆内,如果超过了 64 bytes,就被保存到进程外的共享堆里,可以给节点内所有进程共享。

erlang 有两种二进制容器:heap binaries 和 refc binaries。
heap binaries

Heap binaries are small binaries, up to 64 bytes, that are stored directly on the process heap. They will be copied when the process is garbage collected and when they are sent as a message. They don't require any special handling by the garbage collector.

这个就是进程堆二进制,是一些比较小的二进制数据,每个数据大小不超过 64bytes,这些数据保存在进程堆内。对于这里的二进制数据,垃圾回收走的是进程堆数据的回收机制,参考这里。如果发给其他进程的消息含有这些数据,erlang 将直接复制一份到别的进程堆内。
继续阅读erlang二进制数据垃圾回收

lua 开发防坑指南

原文 2015-09-27 10:47:28 发表于 CSDN,这里对以前写的文章做下收录。

Lua可以被C/C++ 代码调用,反过来也可以调用C/C++的函数,这使得Lua被广泛应用。Lua由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以运行。文章列举lua使用中遇到的坑点,做个汇总。

if判断

lua把 nil 和false 视为“假”,其他都为“真”

逻辑运算符 and or

lua的and or 可以用来构成三元表达式,如下:

> = 1 == 1 and 1 or 2
1

但如果是这样写,就不是你想要的结果了:

> = 1 == 1 and false or true
true

这是因为,and 运算符判定 false不成立,就继续执行了 or 运算符的结果
如果你一定要返回 true 或 false,要这么写:

> = ( 1 == 1 and {false} or {true} )[1]
false

继续阅读lua 开发防坑指南

erlang 开发防坑指南

原文 2015-02-12 23:25:02 发表于 CSDN,这里对以前写的文章做下收录。

任何语言在使用中都会遇到这样那样的问题,erlang也是。这里整理下我遇到的一些问题,避免继续踩坑。说实话,“防坑指南”这个标题有点过于招摇,不过还是希望引起重视,避免在实际开发中重复犯这些问题。

'--' 运算与 '++'运算

1> [1,2,3,4] -- [1] -- [2]. 
[2,3,4]

算是erlang经典的问题了。这是从后面算起的,先算 [1] -- [2] ,得到 [1] 后被 [1,2,3,4] --,最后得到 [2,3,4]
 '++'运算也是一样的,也是从后面开始算起。

2> [1,2,3,4] -- [1] ++ [2,3,4].
[]

另外,以下这种情况也要注意,只会减去遇到的第一个元素。

3> [1,2,3,2] -- [2].
[1,3,2]

继续阅读erlang 开发防坑指南

erlang 判断导出函数问题

原文 2014-11-01 01:27:49 发表于 CSDN,这里对以前写的文章做下收录。

erlang 本身提供一个接口 erlang:function_exported/3,可以用来检查模块是否有导出函数,但是有时候这个接口无法正常使用。
下面重现一下这个问题:

1> erlang:function_exported(crypto,start,0).
false
2> crypto:start().
ok
3> erlang:function_exported(crypto,start,0).
true

注意:例子中并不是说一定要 crypto:start() 才能使用这个函数,只是说这个函数确实存在。
继续阅读erlang 判断导出函数问题