2

i use ranch to listen socket, but in a short time about five seconds, ranch closed the socket, and my setting of socket is above, so what' wrong?

    {ok, _} = ranch:start_listener(server,200, ranch_tcp, [{port, 5555},{active, once},    {max_connections, 1024}], server_protocol, []), %% start the listener

the protocol file is below, the ranch listen to accept a socket, and the reverse the receive data, but what's wrong is that, when send data back to the client, after about five seconds, the client receive the message says that the socket is closed by server, i don't know if is ranch's default settings cause this?

-module(reverse_protocol).
-behaviour(gen_server).
-behaviour(ranch_protocol).
%% API.
-export([start_link/4]).
%% gen_server.
-export([init/1]).
-export([init/4]).
-export([handle_call/3]).
-export([handle_cast/2]).
-export([handle_info/2]).
-export([terminate/2]).
-export([code_change/3]).
-define(TIMEOUT, 5000).
-record(state, {socket, transport}).

%% API.
start_link(Ref, Socket, Transport, Opts) ->
proc_lib:start_link(?MODULE, init, [Ref, Socket, Transport, Opts]).
%% gen_server.
%% This function is never called. We only define it so that
%% we can use the -behaviour(gen_server) attribute.

init([]) -> {ok, undefined}.

init(Ref, Socket, Transport, _Opts = []) ->
ok = proc_lib:init_ack({ok, self()}),
ok = ranch:accept_ack(Ref),
ok = Transport:setopts(Socket, [{active, once}]),
gen_server:enter_loop(?MODULE, [],
    #state{socket=Socket, transport=Transport},
    ?TIMEOUT).

handle_info({tcp, Socket, Data}, State=#state{
    socket=Socket, transport=Transport}) ->
Transport:setopts(Socket, [{active, once}]),
Transport:send(Socket, reverse_binary(Data)),
{noreply, State, ?TIMEOUT};

handle_info({tcp_closed, _Socket}, State) ->
{stop, normal, State};

handle_info({tcp_error, _, Reason}, State) ->
{stop, Reason, State};

handle_info(timeout, State) ->
{stop, normal, State};

handle_info(_Info, State) ->
{stop, normal, State}.

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

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

terminate(_Reason, _State) ->
ok.

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

%% Internal.
reverse_binary(B) when is_binary(B) ->
[list_to_binary(lists:reverse(binary_to_list(
    binary:part(B, {0, byte_size(B)-2})
))), "\r\n"].
4

1 回答 1

2

所以你的问题是因为你的 gen_server 进程超时并关闭。关闭的套接字是这样做的副作用,因为牧场将套接字链接到生成的处理程序进程。

一旦新进程通过调用 进入 gen_server 循环,它在发送消息之前gen_server:enter_loop有几毫秒的时间来接收消息。?TIMEOUTtimeout

-define(TIMEOUT, 5000).

init(Ref, Socket, Transport, _Opts = []) ->
  ok = proc_lib:init_ack({ok, self()}),
  ok = ranch:accept_ack(Ref),
  ok = Transport:setopts(Socket, [{active, once}]),
  gen_server:enter_loop(?MODULE, [],
    #state{socket=Socket, transport=Transport},
    ?TIMEOUT). %% timeout because of this!

handle_info({tcp, Socket, Data}, State=#state{
  socket=Socket, transport=Transport}) ->
  Transport:setopts(Socket, [{active, once}]),
  Transport:send(Socket, reverse_binary(Data)),
  {noreply, State, ?TIMEOUT}; %% timeout because of this!

因此,当这五秒钟过去并且 gen_server 在那段时间内没有收到任何消息时,它会向自己发送一条timeout消息,然后由handle_info

handle_info(timeout, State) ->
  {stop, normal, State};

handle_info告诉 gen_server 停止,这会导致 Socket 关闭,因为两者是链接在一起的。

您可以完全删除超时,或者只是阻止超时导致进程关闭。

以下是我将如何更改handle_info超时代码:

handle_info(timeout, State) ->
  io:format("the socket is idle~n"),
  {noreply,State};
于 2014-05-22T21:56:06.643 回答