7

問題があります: 1M の同時オープン TCP 接続を保持できる Erlang サーバーを作成したいと考えています。OS (Oracle Linux 7) を調整して、ファイル記述子を上げました。サーバー上で gen_tcp:listen を実行します

// point_1
Socket = gen_tcp:accept
spawn(handle(Socket)) //
point_1 に戻る別のスレッド

順番に接続しても問題ありません。100 秒で 100K クライアントを接続しました。しかし、私はそれ以上の忍耐がありませんでした。

それらを同時に接続したい場合たとえば、100から約80の接続しか作成されません。

これは私がすべてを実行する方法です:

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

// ポート 9999 でリッスンする 1 つのサーバーを起動します

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.
4

1 に答える 1

7

ここには少なくとも 2 つの問題があります。

  • リッスン バックログを上げる必要があります。{backlog, N}デフォルトは 5 です。リッスン オプションを設定することで値を上げることができます{backlog, 1024}

  • 接続server/2を受け入れ、実行する新しいプロセスを生成しますが、その新しいプロセスを受け入れられたソケットの制御プロセスloop/1にしないため、関数に問題があります。この関数は、着信メッセージを受信するためにソケットにモードを設定しようとしますが、制御プロセスで実行されていないため、機能しません。(代わりに thereと言って戻り値を確認する必要があります。)loop/1{active,once}inet_setopts/2ok = 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されるため、ソケットの制御プロセスを変更する必要はありません。

于 2015-09-22T08:13:05.643 に答える