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]).