短暂端口混乱(加上一些 Erlang)

短暂端口混乱(加上一些 Erlang)

因此,我对临时端口系统的理解是,有一个由四个值组成的元组来标识每个连接:{源 IP、源端口、目标 IP、目标端口},其中源端口是系统上的临时端口之一。一个连接不能具有与任何其他连接相同的元组,因此如果您从您的机器同时与另一台机器上的同一端口建立大量连接,则您只能建立与可用临时端口数量相同的连接,因为这是唯一可以更改的参数。这一切对我来说都很有意义(但如果我有任何错误,请纠正我)。

但是,从理论上讲,如果您使用两个不同的源 IP 地址,那么您可能建立的连接数将增加一倍。我决定测试一下,因此我在 Erlang 中编写了一个客户端/服务器测试,该测试会建立并保持尽可能多的连接。仅使用一个 IP 地址,我的连接数上限约为 52k。我使用的 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]).

答案1

无论您监听的 IP 地址数量是多少,您的操作系统都有 IPv4 连接的最大数量限制。这可能是您遇到的限制。每个进程和每个用户也可能有限制。检查所有这些。

相关内容