2014-11-01 26 views
1

我需要在Erlang的单个监听套接字上处理两个不兼容的协议版本。Erlang:不需要从套接字中消耗数据的协议

不幸的是,协议升级设计不正确,所以在旧版本切换到较新版本或版本控制时,而不是“升级协议”选项,新协议是普通的TLS连接(旧版本是普通的TCP请求响应面向行的)。

现有的C实现使用recvmsg(MSG_PEEK)嗅探从连接开始的几个字节,然后将套接字传递给其中一个处理程序。 Erlang不会公开功能,在没有读取它的情况下“偷看”到套接字中。

如何在Erlang中有效地执行此操作?

我想出了一些想法,但他们都不令人满意:

  • 这嗅着协议,并分发到二郎端点的一个小C前端服务器。缺点:部署复杂化。在NIF中公开MSG_PEEK。缺点:recvmsg可能会阻塞,这会对调度程序造成严重破坏。
  • 从套接字中读取数据,然后在自定义类套接字模块中重放完整数据(使用cb_info选项用于SSL套接字)。缺点:使用纯Erlang代理数据来回复杂和减慢实现速度。
+0

我不明白你的解释是什么阻止你模仿C的实现,模式匹配对于这项工作来说通常很棒。 – Pascal 2014-11-01 13:58:43

+0

从您的问题来看,目前还不清楚较旧的协议是仅限TCP还是较新的一种TLS,或者它们都是TLS? C代码是否只是定期监听/接受,然后在嗅探后升级到TLS? – 2014-11-01 14:02:46

+0

@Pascal Erlang没有提供任何方式在没有阅读的情况下“偷看”流。 – dottedmag 2014-11-01 14:07:39

回答

6

事情要考虑的是先读几个字节通过gen_tcp:recv/2,3,检查数据,以决定你要处理哪些协议与,然后使用undocumented gen_tcp:unrecv/2 function接收到的数据回推入插槽。是这样的:

{ok, Data} = gen_tcp:recv(Socket, NumberOfBytesToRead), 
ProtocolHandler = decide_which_protocol(Data), 
gen_tcp:unrecv(Socket, Data), 
ProtocolHandler:handle_this_socket(Socket). 

其中decide_which_protocol/1handle_this_socket/1函数代表自己的用于检测和处理您两种协议逻辑,和ProtocolHandler表示用于处理不同协议的不同模块。确保插座处于{active,false}模式。如果代码检测到较新的基于TLS的协议,则可以将TCP套接字升级为TLS,如described here (search for "Upgrade example")

+0

'unrecv'正是需要的。非常感谢! – dottedmag 2014-11-01 14:14:34

相关问题