Erlang同时连接1M客户端

时间:2015-09-22 07:47:24

标签: sockets erlang connect gen-tcp

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

// point_1
  Socket = gen_tcp:接受
    spawn(handle(Socket))//另一个线程
    回到point_1

如果我顺序连接没问题,在100秒内连接100K客户端;但我没有更多的信仰。

如果我想以 conncurent 的方式连接它们,例如,只有大约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.

1 个答案:

答案 0 :(得分:7)

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

  • 你需要提高听力积压;它默认为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,因此无需更改套接字的控制进程。