代码之家  ›  专栏  ›  技术社区  ›  Peer Stritzinger

如何设计一个灵活的Erlang协议栈创建API

  •  8
  • Peer Stritzinger  · 技术社区  · 14 年前

    对我目前的方法不满意,我只是试图重新设计我在Erlang中构建协议栈的方式。按重要性排序的功能:

    1. 性能

    2. 增加新协议变体的灵活性和实现速度

    3. 它将有助于开发人员从shell中探索协议变体

    我的当前模型( alreday described in this question )除了send()by函数调用和receive by消息的难看的不对称性之外,它已经达到了极限。

    整个协议引擎的总体情况如下:

    底部部分:

    • 在每个堆栈的底部有几个端口,或者有时也有一个gen_tcp(对于独立的通道有多个相同的堆栈,因此我们不能太静态,只需要注册进程,就必须到处传递Pids。

    顶部:

    • 由事件发生触发(一般来说,不是由事件处理器触发)的是面向连接的协议端(例如 connect() close() 语义学。

    • 当前计划将传递一个模块名列表+来自顶层的可选参数,在 连接()

    • 顶层进程将被链接,因此当出现任何问题时,整个连接都将失败。

    模块类型和它们之间的通信类型

    目前发现的模块有几种:

    • 带有state的模块,一些适合gen_server,一些gen_fsm,但大多数可能是简单的服务器循环,因为selective receive将非常有用,并且经常简化代码。

    层之间的通信类型:

    • 发送某些内容的同步调用,阻塞直到有应答,然后将结果作为返回值返回。

    • 多路复用器,可向下切换到多个模块(这是我在这里的定义,以便于讨论)

    • 具有不同连接点(目前由原子命名)的解复用器,用于与向上的模块通信。

    目前我唯一的解复用器在堆栈的静态底部,而不是动态创建的顶部。多路复用器目前只在顶部。

    在我之前链接的问题处理的回答和评论中,我听说通常API应该只包含函数,而不是消息,除非另有说服,否则我同意这一点。

    请原谅对这个问题的冗长解释,但我认为它对于各种协议的实现仍然是通用的。

    我将在答案中写下我到目前为止的计划,同时也将解释最终的实现和我的经验,以便在这里实现一些通常有用的东西。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Peer Stritzinger    14 年前

    我会把我的计划作为答案的一部分:

    • connect将传递一个要堆栈的模块列表,在参数的情况下类似于proplist,例如:

      connect([module1, module2, {module3, [params3]}], param0, further_params)
      

      每一层剥去头部,调用下一层连接。

    • connect()

      • 向堆栈下移的异步发送将由下层连接返回
      • 异步接收堆栈的recv将作为param传递给低级连接
      • 调用sync sending并等待返回的回复——不确定如何处理这些问题,可能也是从较低级别的connect返回的
    • 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]).
      

    目前我决定不会有一个额外的同步调用函数,我只是使用发送。

    encode/1 decode/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)).
    

    一旦我有一个有状态的例子,我也会发布它。