【问题标题】:How handle only one client simultaneously in erlang gen_tcp?如何在 erlang gen_tcp 中同时处理一个客户端?
【发布时间】:2019-06-28 14:11:15
【问题描述】:

我有侦听 Ip:Port 的 TCP 服务器。

listen(Ip, Port) ->
  Opts = [
    binary,
    {active, false},
    {packet, 0},
    {reuseaddr, true},
    {ip, Ip}
  ],

  case gen_tcp:listen(Port, Opts) of
    {ok, ListenSock} ->
      ?MODULE:loop_accept(ListenSock);
    {error, Reason} ->
      exit(Reason)
  end.

loop_accept(ListenSock) ->
  {ok, Sock} = gen_tcp:accept(ListenSock),
  ?MODULE:loop(Sock),
  ?MODULE:loop_accept(ListenSock).

loop(Sock) ->
  case gen_tcp:recv(Sock, 0) of
    {ok, Data} ->
      gen_tcp:send(Sock, [<<"Response: ">>, Data]),
      ?MODULE:loop(Sock);

    {error, Reason} ->
      ok
  end.

任务:当一个客户端连接到 Ip:Port(例如telnet Ip Port)时,必须断开另一个尝试连接的客户端。换句话说,独占使用 Ip:Port。

问题:

  • 如何在 Erlang 上使用 gen_tcp 模块实现?
  • 可以通过 gen_tcp:listen 的选项解决吗?
  • 如何在 Erlang 中以编程方式放弃尝试连接?

附:我是 erlang 的新手。

【问题讨论】:

    标签: tcp erlang tcplistener gen-tcp


    【解决方案1】:

    首先,当您指定{packet, 0} 时,您不能像recv() 那样。阅读此answer about gen_tcp

    服务器可以:

    1. Pid = spawn(?MODULE, loop, [Sock])

    2. 监控#1中的进程:

      Ref = monitor(process, Pid)
      

      但为了防止出现竞态条件,您应该一步执行 #1 和 #2:

      {Pid, Ref} = spawn_monitor(?MODULE, loop [Sock]) 
      
    3. gen_tcp:accept(ListenSock) 执行后,执行:

      gen_tcp:close(ListenSock)
      
    4. 检测客户端何时终止,因此是时候开始监听新客户端了:

      receive {'DOWN', Ref, process, Pid, _Reason} -> 
      listen(Ip, Port)
      

      或者,如果客户端在发送完数据后不会终止,那么你可以在loop()中检测客户端何时关闭套接字:

       case gen_tcp:recv(Sock, 0) of
           {ok, Data} ->
               gen_tcp:send(Sock, [<<"Response: ">>, Data]),
               ?MODULE:loop(Sock);
      
           {error, closed} ->
               listen(Ip, Port);
      
           {error, Reason} ->
                ok
        end
      

    =====

    backlog 套接字选项(例如{backlog, 0}):

    backlog 选项设置操作系统套接字配置参数。来自man listen

    积压参数定义了队列的最大长度 挂起的连接。如果连接请求随队列到达 已满,客户端可能收到错误提示 被拒绝。或者,如果底层协议支持 重传,请求可能会被忽略,以便重试可能 成功。

    而且,Perl Monks 上的这个帖子很好读:TCP server: How to reject connections when busy? Some sn-ps about the backlog configuration:

    所以,看起来连接请求只是被忽略了(就像 TCP 一样 支持重传)

    ...当队列已满时,系统将停止应答 SYN 数据包,这会触发它们的重新发送。结果,对等方没有 表明您的服务器正忙。它只是一直在等待 建立连接。

    【讨论】:

    • 感谢您的回复并链接到另一个答案!我尝试使用backlog 选项,但它没有按我预期的那样工作。请告诉我为什么?
    • @Meatbot,请参阅我答案底部的回复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    • 2015-12-19
    • 2011-11-23
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 2014-05-23
    相关资源
    最近更新 更多