Итак, мое понимание системы эфемерных портов состоит в том, что существует кортеж из четырех значений, идентифицирующих каждое соединение: {исходный IP-адрес, исходный порт, целевой IP-адрес, целевой порт}, причем исходный порт является одним из эфемерных портов в системе. Соединение не может иметь тот же кортеж, что и любое другое, поэтому, если вы делаете несколько одновременных подключений со своего компьютера к одному и тому же порту на другом, вы можете сделать столько подключений, сколько у вас есть свободных эфемерных портов, так как это единственный параметр, который можно изменить. Все это имеет для меня смысл (но, пожалуйста, поправьте меня, если я ошибаюсь в чем-либо).
Однако теоретически, если бы вы использовали два разных исходных IP-адреса, это удвоило бы количество потенциально возможных подключений. Я решил, что хочу это протестировать, поэтому написал тест клиент / сервер на erlang, который устанавливает и поддерживает столько соединений, сколько может. Используя только один IP-адрес, мои соединения ограничивались примерно 52 КБ. Я использовал IP-адрес 127.0.0.1.
Затем я изменил сценарий, чтобы он также использовал локальный сетевой адрес машины (172.16.202.132). Это определенно было связано с обоими IP-адресами:
# 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)
(повторяется, казалось бы, бесконечно)
Но снова мои соединения упали до 52k. Я изменил две программы так, чтобы сервер и клиент использовали порт 8889, а также 8888. Я был почти уверен, что это даст мне больше, но снова я ограничился 52k. Подключения выполнялись правильно:
# 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)
(повторяется, казалось бы, бесконечно)
Может ли кто-нибудь пролить свет на то, почему это может происходить? Я использую Ubuntu 10.04, erlang R13B03. Вот код, который я также использую для клиента / сервера:
Сервер:
-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.
Клиент:
-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]).
Ваша ОС имеет максимальное количество подключений IPv4, независимо от того, сколько IP-адресов вы слушаете. Вероятно, это предел, с которым вы столкнулись. Также могут быть ограничения на процесс и на пользователя. Проверьте все это.