2

我正在实现一个 gen_server 作为一个 gen_server,它作为一个 ssl 身份验证服务器的接口。如果收到的数据包错误(例如错误的用户名和密码),ssl 服务器将切断连接。连接必须是持久的。

在我的 gen_server 中,我使用 handle_cast/2 打开与服务器的 ssl 连接:

 handle_cast(connect, State) ->
    ......
    case ssl:connect(Address, Port, Options, Timeout) of
        {ok, NewSocket} ->
           {noreply, State#state{socket=NewSocket}};
        {error, Reason} ->
           gen_server:cast(?SERVER, connect),
           {noreply, State#state{socket=undefined}};

然后我在 handle_cast/2 中等待其他其他消息,例如可以使用:

 gen_server:cast(Pid, {authenticate, User, Password}).

每当我收到这样的强制转换消息时,我都会生成一个新函数,该函数使用 gen_server:call/3 从服务器状态恢复 SSL 套接字并将身份验证消息发送到 SSL 服务器。如果发送部分返回错误,我会尝试重新连接,否则我会在套接字上读取一段时间,以确保套接字不会关闭,如果是,我会重新连接。

send_auth(_, _, 0) ->
    {error, max_num_reached}; 

send_auth(User, Password, Num) ->
    Socket = gen_server:call(?SERVER, socket),
    %% also a check that socket is not 'undefined'
    case ssl:send(Socket, AuthMessage) of
      ok ->
          case ssl:recv(Socket, 0, 2000) of
            {error, timeout} ->
                ok;
            _ ->
                gen_server:cast(?SERVER, connect),
                send_auth(User, Password, Num-1)
          end,
      {error, closed} ->
          gen_server:cast(?SERVER, connect),
          send_auth(User, Password, Num-1)
    end.

我做了很多测试,但每次,如果一条消息(不是最后一条)是错误的,则实际上没有传递以下消息。

如何允许所有有效的身份验证消息都传递到身份验证服务器?此外,如何确保服务器仅在尚未尝试连接时才会连接?否则就像 DOS 攻击一样!

4

1 回答 1

0
  1. 据我所知,系统中只有一个身份验证服务器,那么为什么不能在gen_server的初始化中直接连接到它呢?如果连接有点可靠,如果连接有任何问题,您可以杀死gen_server并让主管重新启动它。它可能会解决您的 DOS 问题。
  2. 当您使用send_auth生成其他进程时,您只需在参数中传递套接字连接,而不是进行 gen_server 调用。
  3. 为了保证交付,您将在您的协议中添加某种确认。身份验证服务器应该回复send_auth并确认它得到了它。并且send_auth应该重试,直到它收到该确认或有一些其他后备行为,以防它永远不会这样做。
于 2012-11-01T00:43:17.747 回答