sockets - Erlang同时连接1M客户端

标签 sockets erlang connect gen-tcp

我有一个问题:我想创建一个可以容纳 1M 同时打开的 tcp 连接的 Erlang 服务器。我调整了我的操作系统 (Oracle Linux 7) 以提高文件描述符。
在我做的服务器上
gen_tcp:听

//点_1
套接字 = gen_tcp:accept
spawn(handle(Socket))//另一个线程
回到 point_1

如果我按顺序连接没问题,在 100 秒内我连接了 100K 个客户端;但我已经没有耐心了。

如果我想将它们连接到 并发例如,只有大约 80 个连接由 100 个连接而成。

这就是我运行一切的方式:

erlc *.erl
erl +Q 134217727 +P 1000000 -env ERL_MAX_PORTS 40960000 -env ERTS_MAX_PORTS 40960000

//启动一个监听 9999 端口的服务器
ex:start(1, 9999) 

//100 个客户端尝试在端口 9999 上连接
ex:connect_clients(100, 9999)

让我向您展示一些代码:
start(Num,LPort) ->
  case gen_tcp:listen(LPort,[{active, false},{packet,2}]) of
    {ok, ListenSock} ->
      start_servers(Num,ListenSock),
      {ok, Port} = inet:port(ListenSock),
      Port;
    {error,Reason} ->
      {error,Reason}
  end.

start_servers(0,_) ->
  ok;
start_servers(Num,LS) ->
  spawn(?MODULE,server,[LS,0]),
  start_servers(Num-1,LS).

server(LS, Nr) ->
  io:format("before accept ~w~n",[Nr]),
  case gen_tcp:accept(LS) of
    {ok,S} ->
      io:format("after accept ~w~n",[Nr]),
      spawn(ex,loop,[S]),
      server(LS, Nr+1);
    Other ->
      io:format("accept returned ~w - goodbye!~n",[Other]),
      ok
  end.

loop(S) ->
  inet:setopts(S,[{active,once}]),
  receive
    {tcp,S, _Data} ->
      Answer = 1, 
      gen_tcp:send(S,Answer),
      loop(S);
    {tcp_closed,S} ->
      io:format("Socket ~w closed [~w]~n",[S,self()]),
      ok
  end.

client(PortNo) ->
  {ok,Sock} = gen_tcp:connect("localhost", PortNo,
    []).

connect_clients(Number, Port) ->
  spawn(ex, client, [Port]),
  case Number of
    0 -> ok;
    _ -> connect_clients(Number-1, Port)
  end.

最佳答案

我在这里看到至少两个问题:

  • 你需要增加你的聆听积压;它默认为 5。您可以通过设置 {backlog, N} 来提高它。在您的收听选项中,例如 {backlog, 1024} .
  • 您的 server/2函数有问题,因为它接受一个连接,然后产生一个新进程来运行 loop/1但它并没有使这个新进程成为 controlling process对于接受的套接字。 loop/1函数尝试设置 {active,once}套接字上的模式以尝试接收传入的消息,但由于它没有在控制进程中运行,所以它不会工作。 (你应该通过在那里说 inet_setopts/2 来验证 ok = inet:setopts(S,[{active,once}]), 的返回值。)

  • 而不是产生循环,你应该产生一个新的接受器,像这样:
    server(LS, Nr) ->
      io:format("before accept ~w~n",[Nr]),
      case gen_tcp:accept(LS) of
        {ok,S} ->
          io:format("after accept ~w~n",[Nr]),
          spawn(ex,server,[LS,Nr+1]),
          loop(S);
        Other ->
          io:format("accept returned ~w - goodbye!~n",[Other]),
          ok
      end.
    

    通过这种方法,接受套接字的进程运行 loop/1因此无需更改套接字的控制过程。

    关于sockets - Erlang同时连接1M客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32711242/

    相关文章:

    Android 蓝牙 .connect() 异常 Nexus 7 OBDII 适配器

    c++ - 将 PID 缓存到端口映射 Windows 的安全方法

    compiler-construction - Erlang 编译器是如何实现模式匹配的?

    erlang - 如何防止io :format from outputting its ASCII characters representation?

    erlang - 使用 Elixir Genstage 的运行时动态计算图

    使用 c connect() 连接被拒绝?

    c# - 处理数千个 UDP 数据包并使用 Threads 将它们保存在远程数据库中的最佳方法是什么?

    javascript - Node.js:使用套接字连接到服务器

    c# - 为什么 System.Net.Sockets.Socket.AcceptAsync 在长时间不活动后完成 ConnectionReset?

    java - Android - 以编程方式连接到wifi