>表现
>灵活性和实施速度,增加了新的协议变体
>从shell开始探索协议变体将有助于开发
我的当前模型(alreday described in this question)除了函数调用和通过消息接收的send()的丑陋不对称外,正在达到其极限.
整个协议引擎的整体情况如下所示:
底部:
>在每个堆栈的底部有几个端口或者有时也可能是gen_tcp(独立通道有多个相同的堆栈,所以我们不能在这里注册过程太静态,必须在任何地方传递Pids.
>在端口之上是一些由主管管理的模块(从系统启动并且在没有错误的情况下保持整个生命周期).
上半部分:
>由事件发生(在一般意义上不在event_handler意义上)触发的是面向连接的协议结束(例如,使用connect()和close()语义.
>协议堆栈的最高端可能只能动态启动,因为堆叠在一起以形成堆栈的模块是动态可配置的,并且可能会从连接更改为连接.
>目前计划将从顶层传递一个模块名称列表可选参数,当在堆栈中调用connect()时,这些参数会被消耗掉.
> Toplevel进程将被链接,因此当出现任何问题时,整个连接都会失败.
模块类型和它们之间的通信类型
到目前为止发现了几种模块:
>无状态滤波器模块
>具有状态的模块,一些适合gen_server,一些gen_fsm但大多数可能是简单的服务器循环,因为选择性接收将非常有用并且经常简化代码.
层之间的通信类型:
>独立发送和接收数据包(从外部看独立)
>发送内容的同步调用,阻塞直到有答案,然后将结果作为返回值返回.
>多路复用器,可以与多个模块进行通信(这是我在这里的定义,以便于讨论)
>具有不同附着点(当前由原子命名)的解复用器与面向上的模块进行通信.
目前我唯一的解复用器位于堆栈的静态底部,而不是动态创建的顶部.多路复用器目前仅位于顶部.
在我之前链接的问题处理的答案和评论中,我听说API通常只包含函数而不是消息,除非另有说服,否则我同意这一点.
请原谅问题的冗长解释,但我认为它仍然适用于各种协议实现.
我将在答案中编写我迄今为止计划的内容,并且还将在稍后解释由此产生的实现和我的经验,以便在此处获得通常有用的内容.
到目前为止,我将把我计划的内容作为答案的一部分:> connect将一个模块列表传递给堆栈,在params的情况下看起来像一个proplist,例如:
connect([module1, module2, {module3, [params3]}], param0, further_params)
每一层剥离头部并调用下一层连接.
> connect()“以某种方式”向上和/或向下传递有趣的参考
>发送异步发送下行栈将由低级别连接返回
> recv for async接收堆栈将作为参数传递给较低级别的连接
>调用同步发送并等待返回的回复 – 不知道如何处理这些,可能还从较低级别的连接返回
>多路复用器路由列表可能如下所示
connect([module1, multiplexer, [[m_a_1, m_a_2, {m_a_3, [param_a_3]}], [m_b_1, m_b_2], [{m_c_1, [param_c_1]}, m_c_2]], param0, further_params]).
目前我决定不会有同步调用的额外功能,我只是使用发送它.
在这种情况下,对于无状态的模块存在该想法的实现示例:编码/ 1和解码/ 1对分组执行一些操作和反向转换,例如将二进制表示解析为记录并返回:
connect(Chan, [Down|Rest], [], Recv_fun) -> {Down_module, Param} = case Down of {F, P} -> {F, P}; F when is_atom (F) -> {F, []} end, Send_fun = Down_module:connect(Chan, Rest, Param, fun(Packet) -> recv(Packet, Recv_fun) end), {ok, fun(Packet) -> send(Packet, Send_fun) end}. send(Packet, Send_fun) -> Send_fun(encode(Packet)). recv(Packet, Recv_fun) -> Recv_fun(decode(Packet)).
只要我有一个有状态的例子,我也会发布它.