Ephemeral Port Confusion (além de alguns erlang)

1

Então, meu entendimento do sistema de portas efêmeras é que há uma tupla de quatro valores identificando cada conexão: {ip de origem, porta de origem, ip de destino, porta de destino}, sendo a porta de origem uma das portas efêmeras em um sistema . Uma conexão não pode ter a mesma tupla que qualquer outra, então se você estiver fazendo um monte de conexões simultâneas da sua máquina para a mesma porta em outra, você só pode fazer tantas conexões quantas portas efêmeras livres, único parâmetro que pode ser alterado. Isso tudo faz sentido para mim (mas, por favor, me corrija se eu estiver errado em alguma coisa).

No entanto, teoricamente, se você usasse dois endereços IP de origem diferentes, isso duplicaria o número de conexões que você poderia fazer. Eu decidi que queria testar isso, então eu escrevi um teste cliente / servidor em erlang que faz e mantém tantas conexões quanto possível. Usando apenas um endereço IP, minhas conexões ficaram em torno de 52k. O endereço IP que eu usei era 127.0.0.1.

Em seguida, modifiquei o script para usar também o endereço de rede local da máquina (172.16.202.132). Definitivamente estava fazendo conexões nos dois ips:

# lsof -Pnl +M -i4
beam.smp  7528     1000  947u  IPv4 3441692      0t0  TCP 172.16.202.132:32064->172.16.202.132:8888 (ESTABLISHED)
beam.smp  7528     1000  948u  IPv4 3441695      0t0  TCP 127.0.0.1:37225->127.0.0.1:8888 (ESTABLISHED)

(repetido aparentemente infinitamente)

Mas mais uma vez minhas conexões terminaram em 52k. Eu modifiquei os dois programas para que o servidor e o cliente usassem a porta 8889 e a 8888. Eu estava quase certo de que isso me daria mais, mas mais uma vez eu encerrei a 52k. Conexões estavam sendo feitas corretamente:

# lsof -Pnl +M -i4
beam.smp  7528     1000  946u  IPv4 3441689      0t0  TCP 172.16.202.132:26620->172.16.202.132:8889 (ESTABLISHED)
beam.smp  7528     1000  947u  IPv4 3441692      0t0  TCP 172.16.202.132:32064->172.16.202.132:8888 (ESTABLISHED)
beam.smp  7528     1000  948u  IPv4 3441695      0t0  TCP 127.0.0.1:37225->127.0.0.1:8888 (ESTABLISHED)
beam.smp  7528     1000  949u  IPv4 3441698      0t0  TCP 127.0.0.1:27965->127.0.0.1:8889 (ESTABLISHED)

(repetido aparentemente infinitamente)

Alguém pode lançar alguma luz sobre por que isso pode estar ocorrendo? Estou usando o Ubuntu 10.04, erlang R13B03. Aqui está o código que estou usando para o cliente / servidor também:

Servidor:

-module(contest).
-compile(export_all).
-define(TCP_OPTS, [binary, {packet, raw}, {nodelay, true}, {reuseaddr, true}, {active, false},{keepalive,true}]).

start() ->
    erlang:register(counter,spawn(fun()->?MODULE:counter(0) end)),

    %Gets the listen socket, generates acceptor threads
    case gen_tcp:listen(8888, ?TCP_OPTS) of
    {ok, Listen1} -> 
        ?MODULE:gen_accepts(10,Listen1)
    end,

    case gen_tcp:listen(8889, ?TCP_OPTS) of
    {ok, Listen2} -> 
        ?MODULE:gen_accepts(10,Listen2)
    end,

    ?MODULE:supervisor_loop({Listen1,Listen2}).

%Serves the purpose of keeping the listen socket open
%indefinitely
supervisor_loop(LS) ->
    receive
    _ -> ?MODULE:supervisor_loop(LS)
    end.    

%Generates I acceptor threads which constantly listen for
%new connections. Upon getting one, a new acceptor thread
%is spawned and the one which receieved a connection 
%continues on to process the connection
gen_accepts(0,_) -> ok;
gen_accepts(I,LS) ->
    spawn(?MODULE,accept_loop,[LS]),
    ?MODULE:gen_accepts(I-1,LS).

%Acceptor loop which spawns off sock processors when connections
%come in
accept_loop(Listen) ->
    case gen_tcp:accept(Listen) of
        {ok, Socket} ->
                Pid = spawn(fun()->?MODULE:process_sock(Socket) end),
                gen_tcp:controlling_process(Socket,Pid),
        whereis(counter)!plus;
        {error,_} -> ok
        end,
    ?MODULE:accept_loop(Listen).

%Holds socket, doesn't do anything
process_sock(Sock) ->
    receive
    _ -> process_sock(Sock)
        end.

counter(C) ->
    receive
    plus ->
        io:fwrite("~p\n",[C+1]),
        counter(C+1)
    end.

Cliente:

-module(flooder).
-compile(export_all).

start() -> 
    spawn(fun()->start("172.16.202.132",8888)end),
    spawn(fun()->start("172.16.202.132",8889)end).

start(Ip,Port) ->
    spawn(?MODULE,connect,[Ip,Port]),
    timer:sleep(2),

    case Ip of
    "127.0.0.1" -> ?MODULE:start("172.16.202.132",Port);
    "172.16.202.132" -> ?MODULE:start("127.0.0.1",Port)
    end.

connect(Ip,Port) ->
    case gen_tcp:connect(
        Ip,
        Port,
        [list,{active,true}]
    ) of
    {ok, Sock} -> io:fwrite("Connected on ~s\n",[Ip]),loop(Sock);
    {error,E} -> eMessage("connect",E)
    end.

loop(Sock) ->
    receive
    _ -> loop(Sock)
    end.

eMessage(W,E) ->
    io:fwrite("~w at ~s: ~s\n",[self(),W,E]).
    
por Mediocre Gopher 20.05.2011 / 16:51

1 resposta

3

Seu sistema operacional tem um número máximo de conexões IPv4, independentemente de quantos endereços IP você está ouvindo. Esse é provavelmente o limite em que você está correndo. Também pode haver limites por processo e por usuário. Verifique todos esses.

    
por 20.05.2011 / 17:49

Tags