使用 Ninenine 牧场实现 Long live tcp 连接

Posted

技术标签:

【中文标题】使用 Ninenine 牧场实现 Long live tcp 连接【英文标题】:Implementing Long live tcp connection using ninenine ranch 【发布时间】:2019-06-07 21:42:20 【问题描述】:

我正在尝试实现与ninnenine ranch erlang library 的长期 TCP 连接。 但是查看文档我看不到这样做的方法。 我也编写了自己的牧场协议,如下所示

   start_link(Ref, _Socket, Transport, Opts) ->
        Pid = spawn_link(?MODULE, init, [Ref, Transport, Opts]),
        ok, Pid.

    init(Ref, Transport, _Opts = []) ->
        ok, Socket = ranch:handshake(Ref),
        loop(Socket, Transport).

    loop(Socket, Transport) ->
        case Transport:recv(Socket, 0, 5000) of
          ok, Data when Data =/= <<4>> ->
          %% Transport:send(Socket, Data),
          io:format("~w Connction accpted~n", [Data]);
          _ -> ok
               %%, Transport:close(Socket)
        end.

如您所见,我已经评论了Transport:close(Socket),并且我没有向客户发送任何回复,因为Transsport:send(socket,Data) 也被评论认为这将解决问题,但我的连接仍然会立即关闭打开。我有一个如下所示的 golang 客户端

package main
import (
    "fmt"
    "log"
    "net"

)

    func main()
        conn, err := net.Dial("tcp", "localhost:5555")
                if err != nil 
                    fmt.Println(err)
                
                fmt.Println(conn /*, i*/)
                conn.Write(XMLData)
                buffer := make([]byte, 10024)
                n, err := conn.Read(buffer)
                fmt.Println(buffer[:n])
                //conn.Close()

    

我虽然是在牧场超时造成的。我搜索了,我发现在牧场中,在文件 src/ranch_tcp.erl 中,我们有如下实现的函数 listen

listen(Opts) ->
Opts2 = ranch:set_option_default(Opts, backlog, 1024),
Opts3 = ranch:set_option_default(Opts2, nodelay, true),
Opts4 = ranch:set_option_default(Opts3, send_timeout, 30000),
Opts5 = ranch:set_option_default(Opts4, send_timeout_close, true),
%% We set the port to 0 because it is given in the Opts directly.
%% The port in the options takes precedence over the one in the
%% first argument.
gen_tcp:listen(0, ranch:filter_options(Opts5, disallowed_listen_options(),
    [binary, active, false, packet, raw, reuseaddr, true])).

如您所见,有一个超时选项,特别是 Opts5 Opts5 = ranch:set_option_default(Opts4, send_timeout_close, true) 和 Opts4 Opts4 = ranch:set_option_default(Opts3, send_timeout, 30000),。我禁用了它们但仍然无法正常工作。那么我应该怎么做才能使用牧场建立长期有效的 tcp 连接。

【问题讨论】:

【参考方案1】:

你的协议实现有缺陷

loop(Socket, Transport) -> case Transport:recv(Socket, 0, 5000) of ok, Data when Data =/= <<4>> -> %% Transport:send(Socket, Data), io:format("~w Connction accpted~n", [Data]); _ -> ok %%, Transport:close(Socket) end.

您不会在任何 case 子句分支中递归调用 loop/2,因此当 loop/2 返回导致 tcp 连接断开时,您的协议进程会终止。

【讨论】:

以上是关于使用 Ninenine 牧场实现 Long live tcp 连接的主要内容,如果未能解决你的问题,请参考以下文章

数据结构实验之修理牧场

智慧农牧物联网云计算平台,打造精准养殖可溯源数字牧场

bzoj 3437小P的牧场

bzoj 3437: 小P的牧场 -- 斜率优化

牧场onWEB的攻略玩法

码头工人群或牧场牛中的芹菜工人