[英]Erlang Ranch Websocket Client fails to detect dropped Internet connection
I've written a very standard websocket client using Gun.我使用 Gun 编写了一个非常标准的 websocket 客户端。 It works as expected, connects, sends and receives messages, etc. Everything is very normal.
它按预期工作,连接,发送和接收消息等。一切都很正常。
However, I discovered that it doesn't detect a broken internet connection.但是,我发现它没有检测到断开的互联网连接。 If I unplug the Ethernet cable from my PC, the Gun client does nothing.
如果我从 PC 上拔下以太网电缆,Gun 客户端什么也不做。 I don't get any kind of error, "DOWN" message, or any info of any kind.
我没有收到任何类型的错误、“DOWN”消息或任何类型的任何信息。 And, then if I reconnect the Ethernet cable, nothing happens.
然后,如果我重新连接以太网电缆,什么也不会发生。 Gun just seems to pause and does nothing.
枪似乎停了下来,什么也没做。
Ideally, I want some kind of message from Gun if the connection goes down.理想情况下,如果连接中断,我想从 Gun 那里得到某种消息。 That way, I can handle things accordingly, and attempt to reconnect.
这样,我可以相应地处理事情,并尝试重新连接。
What am I missing?我错过了什么? How can I detect a dropped connection from Gun?
如何检测 Gun 断开的连接?
My Client code is:我的客户代码是:
-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}.
Looks like you need implement a handler of ping/pong
frames, for more info, please take a look to RFC https://tools.ietf.org/html/rfc6455#section-5.5.2 and https://tools.ietf.org/html/rfc6455#section-5.5.3 .看起来您需要实现
ping/pong
帧的处理程序,有关更多信息,请查看 RFC https://tools.ietf.org/html/rfc6455#section-5.5.2和https://tools.ietf .org/html/rfc6455#section-5.5.3 。 So, when server send ping
, the client applications, eg: browser should answered pong
back to server side and you can handle it by WebSocket.因此,当服务器发送
ping
时,客户端应用程序,例如:浏览器应回复pong
回服务器端,您可以通过 WebSocket 处理它。 But if server send ping
and don't get pong
in answer from client side - this will be mean that the connect is lost.但是,如果服务器发送
ping
并且没有从客户端得到pong
的回答 - 这将意味着连接丢失。 Hope, this will be helpful.希望,这会有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.