繁体   English   中英

Erlang Ranch Websocket 客户端无法检测到断开的 Internet 连接

[英]Erlang Ranch Websocket Client fails to detect dropped Internet connection

我使用 Gun 编写了一个非常标准的 websocket 客户端。 它按预期工作,连接,发送和接收消息等。一切都很正常。

但是,我发现它没有检测到断开的互联网连接。 如果我从 PC 上拔下以太网电缆,Gun 客户端什么也不做。 我没有收到任何类型的错误、“DOWN”消息或任何类型的任何信息。 然后,如果我重新连接以太网电缆,什么也不会发生。 枪似乎停了下来,什么也没做。

理想情况下,如果连接中断,我想从 Gun 那里得到某种消息。 这样,我可以相应地处理事情,并尝试重新连接。

我错过了什么? 如何检测 Gun 断开的连接?

我的客户代码是:

-module(test_client).
-behaviour(gen_server).

-include_lib("kernel/include/logger.hrl").


%% API.
-export([start_link/0]).

%% gen_server.
-export([init/1]).
-export([handle_call/3]).
-export([handle_cast/2]).
-export([handle_info/2]).
-export([terminate/2]).
-export([code_change/3]).

-record(state, {
    uri,
    port,
    path
}).

%% API.

-spec start_link() -> {ok, pid()}.
start_link() ->
    gen_server:start_link(?MODULE, [], []).

%% gen_server.

init([]) ->

    ?LOG_INFO(#{pid=>self(), module=>?MODULE, where=>init, msg=>started}),

    URI = "127.0.0.1",
    Port = 443,
    Path = "/ws",
    Opts = #{transport => tls, protocols => [http],retry => 5,retry_timeout => 2000},

    gen_server:cast(self(), connect),

    {ok,  #state{uri=URI, port=Port, path=Path, conn_opts=Opts}}.

handle_call(_Request, _From, State) ->
    {reply, ignored, State}.

handle_cast(connect, State0) ->
    {ok, ConnPid} = gun:open(State0#state.uri, State0#state.port, State0#state.conn_opts),
    _ = monitor(process, ConnPid),
    {noreply, State0#state{conn_pid=ConnPid};

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({gun_up, ConnPID, http}, State) ->
    ?LOG_INFO(#{pid=>self(), module=>?MODULE, where=>info, msg=>gun_up, conn_pid=>ConnPID}),
    gun:ws_upgrade(ConnPid),
    {noreply, State#state{conn_pid=ConnPID}};

handle_info({gun_upgrade, ConnPID, ConnRef, _, _}, State) ->
    ?LOG_INFO(#{pid=>self(), module=>?MODULE, where=>info, msg=>gun_upgrade, conn_pid=>ConnPID, conn_ref=>ConnRef}),
    {noreply, State#state{conn_pid=ConnPID}};

handle_info({gun_down, ConnPID, ws, closed, _, _}, State) ->
    ?LOG_INFO(#{pid=>self(), module=>?MODULE, where=>info, msg=>gun_down, conn_pid=>ConnPID}),
    gun:close(ConnPID),
    gen_server:cast(self(), retry_connect),
    {noreply, State#state{conn_pid=null}};   

handle_info({gun_ws, _ConnPID, _ConnRef, RawMsg}, State) ->
    io:format("Receive: ~p~n", [RawMsg]),
    {noreply, State};

handle_info({gun_response, ConnPID, _ConnRef, _Err, Code, _Headers}, State0) ->
    ?LOG_ERROR(#{pid=>self(), module=>?MODULE, where=>info, msg=>gun_response, code=>Code}),
    gun:close(ConnPID),
    {noreply, State0#state{conn_pid=null}};

handle_info({gun_error, ConnPID, _StreamRef, Reason}, State0) ->
    ?LOG_ERROR(#{pid=>self(), module=>?MODULE, where=>info, msg=>gun_error, code=>Reason}),
    gun:close(ConnPID),
    {noreply, State0#state{conn_pid=null}};

handle_info({gun_error, ConnPID,Reason}, State0) ->
    ?LOG_ERROR(#{pid=>self(), module=>?MODULE, where=>info, msg=>gun_error, code=>Reason}),
    gun:close(ConnPID),
    {noreply, State0#state{conn_pid=null}};

handle_info({'DOWN', Mref, process, ConnPid, Reason}, State) ->
    ?LOG_ERROR(#{pid=>self(), module=>?MODULE, where=>info, msg=>monitor_down, code=>Reason}),
    demonitor(Mref),
    gun:close(ConnPid),
    {noreply, State#state{conn_pid=null}};   

handle_info(Info, State) ->
    ?LOG_ERROR(#{pid=>self(), module=>?MODULE, where=>info, status=>unknown, msg=>Info}),
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

看起来您需要实现ping/pong帧的处理程序,有关更多信息,请查看 RFC https://tools.ietf.org/html/rfc6455#section-5.5.2https://tools.ietf .org/html/rfc6455#section-5.5.3 因此,当服务器发送ping时,客户端应用程序,例如:浏览器应回复pong回服务器端,您可以通过 WebSocket 处理它。 但是,如果服务器发送ping并且没有从客户端得到pong的回答 - 这将意味着连接丢失。 希望,这会有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM