我需要在Erlang中的单个侦听套接字上处理两个不兼容版本的协议。
不幸的是,协议升级设计不正确,因此新协议不是旧协议中的"升级协议"选项(切换到新协议或版本控制),而是纯TLS连接(旧协议是面向纯TCP请求-响应行的连接)。
现有的C实现使用recvmsg(MSG_PEEK)
从连接开始嗅探几个字节,然后将套接字传递给其中一个处理程序。Erlang不会在不读取套接字的情况下向套接字"窥视"功能
在二郎中,如何有效地做到这一点?
我提出了一些想法,但似乎都不令人满意:
- 一个小型的C前端服务器,它探查协议并将其分派到Erlang中的一个端点。缺点:部署复杂
- 在NIF中暴露
MSG_PEEK
。缺点:recvmsg可能会阻塞,这会对调度程序造成严重破坏 - 从套接字读取,然后在自定义的类似套接字的模块中回放完整数据(使用SSL套接字的
cb_info
选项)。缺点:使用纯Erlang来回代理数据会使实现复杂且速度减慢
需要考虑的是,首先通过gen_tcp:recv/2,3
读取几个字节,检查数据以确定要处理的协议,然后使用未记录的gen_tcp:unrecv/2
函数将接收到的数据推回套接字。类似这样的东西:
{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/1
和handle_this_socket/1
函数代表您自己的逻辑,用于检测和处理两个协议,ProtocolHandler
代表用于处理不同协议的不同模块。为此,请确保套接字处于{active,false}
模式。如果代码检测到更新的基于TLS的协议,则可以按照此处所述将TCP套接字升级为TLS(搜索"升级示例")。