精华内容
下载资源
问答
  • 保证五元组的全局唯一性看起来是个重体力劳动,以IPv4网络为例,仅仅考虑TCP和UDP,一个五元组空间包括两个32位IPv4地址,两个16位端口以及一个协议,总共232×2+16×2+12^{32\times 2+16\times 2+1}232×2+16×2+1...

    在互联网上一个五元组标识一个应用程序到远端的另一个应用程序的连接。要保证端到端的可达性,显然在全局范围内,五元组必须是唯一的。

    保证五元组的全局唯一性看起来是个重体力劳动,以IPv4网络为例,仅仅考虑TCP和UDP,一个五元组空间包括两个32位IPv4地址,两个16位端口以及一个协议,总共232×2+16×2+12^{32\times 2+16\times 2+1}种组合。穷尽这么大一个空间来寻找一个没有被使用的元组绝对是重体力劳动。

    然而在分布式的互联网环境,五元组的全局唯一性其实非常容易保证,互联网算力分布在世界的各个角落,这个五元组的唯一性是由全世界所有的计算机一起保证的:

    • 每个计算机的IP地址是不同的,这就卸载了穷举2322^{32}种可能性的算力。
    • 访问目标如果不同,又将卸载穷举2322^{32}种可能性的算力。
    • 最终,我们可能只需要在万数量级的端口范畴计算就可以了。

    但是互联网上的主机并不是完全分布对等的,这完全是因为NAT的存在!

    NAT的存在,将已经是分布在每台计算机的保证五元组唯一的计算重新集中了起来!

    由于互联网计算机的分布式特性,五元组的唯一性是在连接初始时就可以保证的,当一个五元组经过任何一台中间设备时,该设备完全可以保证这个五元组的唯一性。

    但如果一台设备对数据包的五元组做了NAT,由于该NAT设备并没有全局的五元组信息库,因此它在做NAT时不得不通过精心的计算以确保NAT过后五元组唯一性仍然可以保证。当然,它也仅仅保证经由本机的连接的五元组唯一性。

    对于Linux内核Netfilter实现的NAT而言,五元组唯一性是通过 get_unique_tuple 函数实现的,我不会在这里分析该函数的实现,它大致说的是:

    • 对于SNAT,尽量使用保存的已知tuple,因为大概率它们访问的目标是不同的,这会大大卸载算力。( 【第一步】 )
    • 万不得已再穷举tuple命名空间,但依然有很多trick优化,盲搜多次,然后放弃。
    • get_unique_tuple不会穷尽整个命名空间,盲搜失败后便停止,NAT的失败并非意味着tuple命名空间的枯竭。

    但以上的过程依然是个重体力劳动,特别是在流量很大的情况下。

    有人可能会有疑问,我只配置了一条NAT规则,仅仅有针对性的转换特定流的一个源IP地址,这个怎么可能对全局产生影响呢?

    很多人都会有这种疑问,其实这个很容易解释:

    • NAT只有开启和关闭之说,与规则如何无关。

    只要开启了NAT,所有的数据流必须要同等对待。在真正匹配到NAT规则之前,系统对规则和匹配情况并不知情,事实上,五元组的唯一性完全是NAT自身来保证的。因此只要是开启了NAT,必须对每一条流施加get_unique_tuple这个重体力劳动!

    即便一条流没有匹配到任何NAT规则,它依然要执行nf_nat_alloc_null_binding来将所有流纳入到一个全局的tuple命名空间,这为NAT真正执行get_unique_tuple时提供了优化:

    • 在执行SNAT的HOOK点,将tuple加入到一个nf_nat_bysource链表,为上述 【第一步】 提供依据。

    曾经有一个问题,当NAT的HOOK函数注册的时候,之前的conntrack并没有被纳入NAT全局的tuple命名空间,也并没有加入到nf_nat_bysource链表,会不会有问题呢?我跟别人解答这个问题,答案是:

    • 不会有问题,只是损失些性能罢了。如果一个流进入nf_nat_fn时和已记录5-tuple有冲突,那么该流不会同时是NEW且!nf_nat_initialized,早就命中了不是吗?

    然而真的是这样吗?非也!

    我想表达的是,nf_nat_alloc_null_binding这个函数是必须的,同时它可能会默默改变你的连接的源端口,信吗?

    我不想过多的解释细节,如果你懂nf_conntrack和NAT的细节,应该知道我下面的脚本再说什么。

    给出测试拓扑环境:

    • 客户端 192.168.56.101:12345 连接服务器 192.168.56.102:80

    首先,我们设置以下的iptables规则,仅仅TRACK到达80端口的连接,同时添加一条无关的NAT规则,以注册conntrack HOOK(由于conntrack HOOK的延迟注册,需要实际添加一条NAT规则):

    *raw
    -A PREROUTING -p udp -j NOTRACK
    -A PREROUTING -p tcp -m tcp ! --sport 80 -j NOTRACK
    -A OUTPUT -p tcp -m tcp ! --dport 80 -j NOTRACK
    -A OUTPUT -p udp -j NOTRACK
    *nat
    -A OUTPUT -d 2.3.4.5/32 -p udp -j DNAT --to-destination 5.4.3.2
    

    其次,我给出一个python程序,一个TCP客户端,bind特定的地址端口,连接特定的地址端口:

    #!/usr/bin/python3
    
    import socket
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('192.168.56.101', 12345))
    
    server_address = ('192.168.56.102', 80)
    sock.connect(server_address)
    sock.close();
    

    最后,我给出一个stap脚本,它的意思是:

    • 在python新建连接被conntrack记录前什么也不做。
    • 在python新建连接被NEW后模拟创建一个“与之reply方向冲突”的conntrack项,在实际中这完全是可能的。
    • 观察python新建连接发出的包,其端口号竟然变了!

    脚本如下:

    #!/usr/bin/stap -g
    
    %{
    #include <net/netfilter/nf_conntrack.h>
    %}
    
    probe module("nf_nat").function("__nf_nat_alloc_null_binding")
    {
    	if ($manip == 1) {
    		// 在OUTPUT NAT执行时,模拟一个完全正常的可能发生的conntrack item插入
    		system("conntrack -I --protonum 6 --timeout 100 --reply-src 192.168.56.102 --reply-dst 192.168.56.101 --state SYN_SENT --reply-port-dst 12345 --reply-port-src 80 --src 1.1.1.1 --dst 192.168.56.102");
    		// 防止stap同步问题,延迟一会儿再整
    		mdelay(100);
    	}
    }
    
    // 打印一些看似无关紧要的信息,但确实给出了tuple冲突的结果
    probe module("nf_conntrack").function("nf_conntrack_tuple_taken").return
    {
    	printf("nf_conntrack_tuple_taken   ret:%d\n", $return);
    }
    
    %{
    struct nf_conn *thief = NULL;
    %}
    
    function alertit(stp_ct:long)
    %{
    	struct nf_conn *ct = (struct nf_conn *)STAP_ARG_stp_ct;
    	struct nf_conntrack_tuple *tuple;
    	unsigned short port;
    
    	tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
    	port = ntohs((unsigned short)tuple->dst.u.all);
    	if (port == 80 && thief == NULL) {
    		STAP_PRINTF("The thief coming!\n");
    		thief = ct;
    	}
    %}
    
    probe module("nf_conntrack").function("nf_conntrack_hash_check_insert")
    {
    	alertit($ct);
    }
    
    function run_away(stp_tuple:long, stp_ct:long)
    %{
    	struct nf_conntrack_tuple *tuple = (struct nf_conntrack_tuple *)STAP_ARG_stp_tuple;
    	struct nf_conn *ct = (struct nf_conn *)STAP_ARG_stp_ct;
    	struct nf_conntrack_tuple *t;
    
    	if (thief) {
    		t = &thief->tuplehash[IP_CT_DIR_REPLY].tuple;
    		//t->dst.u.all = 100; // 这两条注释本来是想破坏掉这个conntrack项的
    		//t->src.u.all = 100;
    		thief = NULL;
    		STAP_PRINTF("The thief ran away...\n");
    	}
    %}
    
    probe module("nf_conntrack").function("nf_conntrack_alter_reply")
    {
    	run_away($newreply, $ct);
    }
    

    执行stap脚本,然后执行client.py,但是我们看一下tcpdump抓包:

    21:18:50.098848 IP 192.168.56.101.35010 > 192.168.56.102.80: Flags [S], seq 1990086505, win 64240, options [mss 1460,sackOK,TS val 814885365 ecr 0,nop,wscale 7], length 0
    21:18:50.098872 IP 192.168.56.102.80 > 192.168.56.101.35010: Flags [S.], seq 1199002250, ack 1990086506, win 65160, options [mss 1460,sackOK,TS val 2915891341 ecr 814885365,nop,wscale 7], length 0
    21:18:50.099064 IP 192.168.56.101.35010 > 192.168.56.102.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 814885466 ecr 2915891341], length 0
    

    可以看到,端口已经不是12345了,它变成了35010,这一切都是在 get_unique_tuple 中,此处不细聊。

    一个真实的场景就是,在192.168.56.101.12345 > 192.168.56.102.80发起, conntrack初始NEW之后,confirm之前 有一个conntrack项被创建,或者是直接恶意插入的,或者某个流是真的命中了一条NAT规则:

    src 1.1.1.1:12345 dst 192.168.56.102:80 --> src 192.168.56.101:12345 dst 192.168.56.102:80
    

    那么原始测试流的源端口将会被偷偷地,默默地改变!

    关于nf_nat_alloc_null_binding,我已经单独写了一篇文章,这其实是我一直都想说的话题:
    https://blog.csdn.net/dog250/article/details/112691374


    下图展示一个nf_conntrack/NAT的宏观场面,我把重体力劳动都用浅红色底色表示:

    在这里插入图片描述

    现在我们看到一些相对耗时的重体力劳动,如果要优化性能,避开这些位置,或者优化这些位置均可。

    nf_conntrack已经在这些方面有所工作了,比方说如果没有一条NAT规则被添加,那么就干脆不注册conntrack HOOK(这并不完美,因为其它的模块只要注册了conntrack HOOK,NAT依然是数据包的必经之路)。

    不管怎么说,认清conntrack & NAT的性能瓶颈到底在哪儿是必要的,如果你的机器连接数达到了几十万上百万,你看看你的conntrack hash表的大小是不是很小,遍历一次冲突链表的开销会不会很大,这些情况有时候并不是nf_conntrack本身的问题,可能仅仅是你的配置问题。必要的时候,想办法把不相关的流量NOTRACK掉也是一种优化方案,比方说,对于那些频繁的又没有NAT,status filter等需求的短连接,NOTRACK将会避开get_unique_tuple以及spin lock从而大大提高单机性能。


    浙江温州皮鞋湿,下雨进水不会胖。

    展开全文
  • 保证五元组的全局唯一性看起来是个重体力劳动,以IPv4网络为例,仅仅考虑TCP和UDP,一个五元组空间包括两个32位IPv4地址,两个16位端口以及一个协议,总共2 32 × 2 + 16 × 2 + 1 2^{32\times 2+16\times 2+1}232×...

    在互联网上一个五元组标识一个应用程序到远端的另一个应用程序的连接。要保证端到端的可达性,显然在全局范围内,五元组必须是唯一的。

    保证五元组的全局唯一性看起来是个重体力劳动,以IPv4网络为例,仅仅考虑TCP和UDP,一个五元组空间包括两个32位IPv4地址,两个16位端口以及一个协议,总共2 32 × 2 + 16 × 2 + 1 2^{32\times 2+16\times 2+1}232×2+16×2+1种组合。穷尽这么大一个空间来寻找一个没有被使用的元组绝对是重体力劳动。

    然而在分布式的互联网环境,五元组的全局唯一性其实非常容易保证,互联网算力分布在世界的各个角落,这个五元组的唯一性是由全世界所有的计算机一起保证的:

    每个计算机的IP地址是不同的,这就卸载了穷举2 32 2^{32}232种可能性的算力。

    访问目标如果不同,又将卸载穷举2 32 2^{32}232种可能性的算力。

    最终,我们可能只需要在万数量级的端口范畴计算就可以了。

    但是互联网上的主机并不是完全分布对等的,这完全是因为NAT的存在!

    NAT的存在,将已经是分布在每台计算机的保证五元组唯一的计算重新集中了起来!

    由于互联网计算机的分布式特性,五元组的唯一性是在连接初始时就可以保证的,当一个五元组经过任何一台中间设备时,该设备完全可以保证这个五元组的唯一性。

    但如果一台设备对数据包的五元组做了NAT,由于该NAT设备并没有全局的五元组信息库,因此它在做NAT时不得不通过精心的计算以确保NAT过后五元组唯一性仍然可以保证。当然,它也仅仅保证经由本机的连接的五元组唯一性。

    对于Linux内核Netfilter实现的NAT而言,五元组唯一性是通过 get_unique_tuple 函数实现的,我不会在这里分析该函数的实现,它大致说的是:

    对于SNAT,尽量使用保存的已知tuple,因为大概率它们访问的目标是不同的,这会大大卸载算力。( 【第一步】 )

    万不得已再穷举tuple命名空间,但依然有很多trick优化,盲搜多次,然后放弃。

    get_unique_tuple不会穷尽整个命名空间,盲搜失败后便停止,NAT的失败并非意味着tuple命名空间的枯竭。

    但以上的过程依然是个重体力劳动,特别是在流量很大的情况下。

    有人可能会有疑问,我只配置了一条NAT规则,仅仅有针对性的转换特定流的一个源IP地址,这个怎么可能对全局产生影响呢?

    很多人都会有这种疑问,其实这个很容易解释:

    NAT只有开启和关闭之说,与规则如何无关。

    只要开启了NAT,所有的数据流必须要同等对待。在真正匹配到NAT规则之前,系统对规则和匹配情况并不知情,事实上,五元组的唯一性完全是NAT自身来保证的。因此只要是开启了NAT,必须对每一条流施加get_unique_tuple这个重体力劳动!

    即便一条流没有匹配到任何NAT规则,它依然要执行nf_nat_alloc_null_binding来将所有流纳入到一个全局的tuple命名空间,这为NAT真正执行get_unique_tuple时提供了优化:

    在执行SNAT的HOOK点,将tuple加入到一个nf_nat_bysource链表,为上述 【第一步】 提供依据。

    曾经有一个问题,当NAT的HOOK函数注册的时候,之前的conntrack并没有被纳入NAT全局的tuple命名空间,也并没有加入到nf_nat_bysource链表,会不会有问题呢?我跟别人解答这个问题,答案是:

    不会有问题,只是损失些性能罢了。如果一个流进入nf_nat_fn时和已记录5-tuple有冲突,那么该流不会同时是NEW且!nf_nat_initialized,早就命中了不是吗?

    然而真的是这样吗?非也!

    我想表达的是,nf_nat_alloc_null_binding这个函数是必须的,同时它可能会默默改变你的连接的源端口,信吗?

    我不想过多的解释细节,如果你懂nf_conntrack和NAT的细节,应该知道我下面的脚本再说什么。

    给出测试拓扑环境:

    客户端 192.168.56.101:12345 连接服务器 192.168.56.102:80

    首先,我们设置以下的iptables规则,仅仅TRACK到达80端口的连接,同时添加一条无关的NAT规则,以注册conntrack HOOK(由于conntrack HOOK的延迟注册,需要实际添加一条NAT规则):

    *raw

    -A PREROUTING -p udp -j NOTRACK

    -A PREROUTING -p tcp -m tcp ! --sport 80 -j NOTRACK

    -A OUTPUT -p tcp -m tcp ! --dport 80 -j NOTRACK

    -A OUTPUT -p udp -j NOTRACK

    *nat

    -A OUTPUT -d 2.3.4.5/32 -p udp -j DNAT --to-destination 5.4.3.2

    其次,我给出一个python程序,一个TCP客户端,bind特定的地址端口,连接特定的地址端口:

    #!/usr/bin/python3

    import socket

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    sock.bind(('192.168.56.101', 12345))

    server_address = ('192.168.56.102', 80)

    sock.connect(server_address)

    sock.close();

    最后,我给出一个stap脚本,它的意思是:

    在python新建连接被conntrack记录前什么也不做。

    在python新建连接被NEW后模拟创建一个“与之reply方向冲突”的conntrack项,在实际中这完全是可能的。

    观察python新建连接发出的包,其端口号竟然变了!

    脚本如下:

    #!/usr/bin/stap -g

    %{

    #include

    %}

    probe module("nf_nat").function("__nf_nat_alloc_null_binding")

    {

    if ($manip == 1) {

    // 在OUTPUT NAT执行时,模拟一个完全正常的可能发生的conntrack item插入

    system("conntrack -I --protonum 6 --timeout 100 --reply-src 192.168.56.102 --reply-dst 192.168.56.101 --state SYN_SENT --reply-port-dst 12345 --reply-port-src 80 --src 1.1.1.1 --dst 192.168.56.102");

    // 防止stap同步问题,延迟一会儿再整

    mdelay(100);

    }

    }

    // 打印一些看似无关紧要的信息,但确实给出了tuple冲突的结果

    probe module("nf_conntrack").function("nf_conntrack_tuple_taken").return

    {

    printf("nf_conntrack_tuple_taken ret:%d\n", $return);

    }

    %{

    struct nf_conn *thief = NULL;

    %}

    function alertit(stp_ct:long)

    %{

    struct nf_conn *ct = (struct nf_conn *)STAP_ARG_stp_ct;

    struct nf_conntrack_tuple *tuple;

    unsigned short port;

    tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;

    port = ntohs((unsigned short)tuple->dst.u.all);

    if (port == 80 && thief == NULL) {

    STAP_PRINTF("The thief coming!\n");

    thief = ct;

    }

    %}

    probe module("nf_conntrack").function("nf_conntrack_hash_check_insert")

    {

    alertit($ct);

    }

    function run_away(stp_tuple:long, stp_ct:long)

    %{

    struct nf_conntrack_tuple *tuple = (struct nf_conntrack_tuple *)STAP_ARG_stp_tuple;

    struct nf_conn *ct = (struct nf_conn *)STAP_ARG_stp_ct;

    struct nf_conntrack_tuple *t;

    if (thief) {

    t = &thief->tuplehash[IP_CT_DIR_REPLY].tuple;

    //t->dst.u.all = 100; // 这两条注释本来是想破坏掉这个conntrack项的

    //t->src.u.all = 100;

    thief = NULL;

    STAP_PRINTF("The thief ran away...\n");

    }

    %}

    probe module("nf_conntrack").function("nf_conntrack_alter_reply")

    {

    run_away($newreply, $ct);

    }

    执行stap脚本,然后执行client.py,但是我们看一下tcpdump抓包:

    21:18:50.098848 IP 192.168.56.101.35010 > 192.168.56.102.80: Flags [S], seq 1990086505, win 64240, options [mss 1460,sackOK,TS val 814885365 ecr 0,nop,wscale 7], length 0

    21:18:50.098872 IP 192.168.56.102.80 > 192.168.56.101.35010: Flags [S.], seq 1199002250, ack 1990086506, win 65160, options [mss 1460,sackOK,TS val 2915891341 ecr 814885365,nop,wscale 7], length 0

    21:18:50.099064 IP 192.168.56.101.35010 > 192.168.56.102.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 814885466 ecr 2915891341], length 0

    可以看到,端口已经不是12345了,它变成了35010,这一切都是在 get_unique_tuple 中,此处不细聊。

    一个真实的场景就是,在192.168.56.101.12345 > 192.168.56.102.80发起, conntrack初始NEW之后,confirm之前 有一个conntrack项被创建,或者是直接恶意插入的,或者某个流是真的命中了一条NAT规则:

    src 1.1.1.1:12345 dst 192.168.56.102:80 --> src 192.168.56.101:12345 dst 192.168.56.102:80

    那么原始测试流的源端口将会被偷偷地,默默地改变!

    关于nf_nat_alloc_null_binding,我已经单独写了一篇文章,这其实是我一直都想说的话题:

    https://blog.csdn.net/dog250/article/details/112691374

    下图展示一个nf_conntrack/NAT的宏观场面,我把重体力劳动都用浅红色底色表示:

    865f6183a248951d394481bbff01e04f.png

    现在我们看到一些相对耗时的重体力劳动,如果要优化性能,避开这些位置,或者优化这些位置均可。

    nf_conntrack已经在这些方面有所工作了,比方说如果没有一条NAT规则被添加,那么就干脆不注册conntrack HOOK(这并不完美,因为其它的模块只要注册了conntrack HOOK,NAT依然是数据包的必经之路)。

    不管怎么说,认清conntrack & NAT的性能瓶颈到底在哪儿是必要的,如果你的机器连接数达到了几十万上百万,你看看你的conntrack hash表的大小是不是很小,遍历一次冲突链表的开销会不会很大,这些情况有时候并不是nf_conntrack本身的问题,可能仅仅是你的配置问题。必要的时候,想办法把不相关的流量NOTRACK掉也是一种优化方案,比方说,对于那些频繁的又没有NAT,status filter等需求的短连接,NOTRACK将会避开get_unique_tuple以及spin lock从而大大提高单机性能。

    浙江温州皮鞋湿,下雨进水不会胖。

    展开全文
  • 关于socket一些总结

    千次阅读 2014-01-24 16:50:27
    在linux下socket是用一个文件描述符来表示,对于linux来说从某个socket读数据和从某个文件读数据是一样的; linux下文件描述符的范围是1024,也就是有个... socket可以用一个五元组来标识: 例如:地址为A的主机欲用tc
          在linux下socket是用一个文件描述符来表示,对于linux来说从某个socket读数据和从某个文件读数据是一样的;linux下文件描述符的范围是1024,也就是每个用户进行所能使用的最大的文件描述符的数量不能超过此值,但是这个值可以进行修改,在服务器程序中,该值可以修改为10w、20w甚至更大的值。

          socket可以用一个五元组来标识:<源地址,源端口,目的地址,目的端口,使用的协议>
    例如:地址为A的主机欲用tcp协议从端口3256向地址为B的主机的5432端口发送消息,那用一个socket来表示上述数据传输就是:
    <A,3256,B,5432,tcp>
          对于socket来说,五元组中的任何一个元素发生变化都表示一个新的socket。这5个元素分为三类:地址、端口和协议。其中:
          地址:
          一般都是指ip地址,例如常用的IPV4的ip地址形式为:210.45.0.12;一个地址就标识了一台主机,如果在通信程序中知道了对方的地址,你就知道往哪台机子上发送了。但是现在还不知道发给那台机子上的哪个程序。
          端口:
          端口的数据类型是unsigned short,为16位,因此端口的使用范围为0~65535,其中0~1024之间的端口为特殊用途,用户可以使用的端口范围需在1024~65535之间,端口标识了一个服务或者是应用程序。
          因此知道了一个地址+端口,就知道了向哪台机子的哪个程序发送数据。但是,现在还不知道跟对方通信是采用哪种协议,就像两个人要说话,但是还不知道该用英文说还是中文说。
          协议:

          协议是指通信双方使用的通信协议,例如tcp、udp之类。协议就表明了双方采用什么方式进行通信。

          因此,知道:地址+端口+协议,就知道了向哪个机子的哪个程序使用哪个协议进行通信。


          为什么使用客户端测试服务器时,一台客户端主机的socket连接只能到6万多个,而服务器却可以接受10w、20万的连接(这里所说的连接就是socket)

    例如:

    使用一台服务器S和3个测试客户端C1、C2、C3进行测试,具体情况为:
    服务器程序S运行的主机地址为:192.168.4.220,监听端口为1883。
    测试客户端程序C1运行的主机地址为:192.168.4.221
    测试客户端程序C2运行的主机地址为:192.168.4.222
    测试客户端程序C3运行的主机地址为:192.168.4.223
    此时在测试客户端程序C1、C2、C3中一直创建新连接到服务器程序S,但是每个机子的测试客户端连接数只能到6w多个,这个跟机子的情况有关,有的可以连到6.4万,有的更少;而此时服务器却支持了近20W个连接。

    服务器程序S运行的主机地址为:192.168.4.220,监听端口为1883。
    测试客户端程序C1运行的主机地址为:192.168.4.221
    测试客户端程序C2运行的主机地址为:192.168.4.222
    测试客户端程序C3运行的主机地址为:192.168.4.223
    此时在测试客户端程序C1、C2、C3中一直创建新连接到服务器程序S,但是每个机子的测试客户端连接数只能到6w多个,这个跟机子的情况有关,有的可以连到6.4万,有的更少;而此时服务器却支持了近20W个连接。


    答案是:
    对于server:
          根据前面的描述,server将会为这三台测试机中的每个连接都创建一个socket进行通信,每个socket就是一个五元组:
          server程序中为C1建立的socket连接为(1025~1078之间的端口被其他程序占用了):
    第一组
    <192.168.4.221, 1078, 192.168.4.220, 1883>
    <192.168.4.221, 1079, 192.168.4.220, 1883>
    ......
    <192.168.4.221, 65535, 192.168.4.220, 1883>

          server程序中为C2建立的socket连接为(1025~1973)之间的端口被其他程序占用了):
    第二组
    <192.168.4.222, 1973, 192.168.4.220, 1883>
    <192.168.4.222, 1974, 192.168.4.220, 1883>
    ......
    <192.168.4.222, 65535, 192.168.4.220, 1883>

          server程序中为C3建立的socket连接为(1025~1623)之间的端口被其他程序占用了):
    第三组
    <192.168.4.223, 1623, 192.168.4.220, 1883>
    <192.168.4.223, 1624, 192.168.4.220, 1883>
    ......
    <192.168.4.223, 65535, 192.168.4.220, 1883>

          上述socket所对应的五元组中,每一组内部的五元组中,都是端口发生了变化,但是其他元素:源地址、目的地址、目的端口、协议都没有变化;

          这三组之间进行对比时,则变化的是源地址,其他元素:源端口、目的地址、目的端口、协议都没有变化(源端口可能不会全部重合,但是大部分都是一样的);

          由于五元组中任何一个成员发生了变化,也就是对应了一个全新的socket。
    在server中,只需要为每个五元组socket产生一个文件描述符来标识进行区分即可,此时只要将所在机子的文件描述符限制值改大,只要超过20W,就可以让其支持这么多的socket连接了,

    对于测试客户端:
    以第一组为例:
          其产生的socket所对应的五元组为:
    <192.168.4.221, 1078, 192.168.4.220, 1883>
    <192.168.4.221, 1079, 192.168.4.220, 1883>
    ......
    <192.168.4.221, 65535, 192.168.4.220, 1883>
          可以看到源地址、目的地址、目的端口、协议这4项是固定的,没有办法改变,所以它此时只能变化一个元素:源端口号!
          由于linux操作系统中port的范围有限,只能用1024~65535之间的,如果这之间的端口号再被别的程序占用一些,能用的就更少了,因此它只能支持6w左右的连接。
    展开全文
  • 3.2 完整数据内容 1、wireshark有三个数据包显示窗口: ...会话数据是两个网络设备之间通信行为汇总,也称流数据,会话数据最常见是标准五元组数据: 源ip地址、源端口、目的ip地址、目的端口、传输协...

    3.2 完整数据内容

    1、wireshark有三个数据包显示窗口:

    数据包列表

    数据包结构

    原始数据包

    2、进行数据包分析时,常用到以下三种技术:

    包过滤

    模式匹配

    协议字段分析

    3.3 提取内容数据

    包字符串数据

    3.4 会话数据

    会话数据是两个网络设备之间通信行为的汇总,也称流数据,会话数据最常见的是标准五元组数据:

    源ip地址、源端口、目的ip地址、目的端口、传输协议

    会话流分析技术:

    会话/流列举

    导出数据流

    文件及数据挖掘

    3.5 统计数据

    3.6元数据

    元数据又称中介数据、中继数据,是用于描述数据的数据,主要是描述数据属性的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。

    3.7日志数据

    物理设备日志

    网络设备日志

    操作系统日志

    应用程序日志

    3.8 告警数据

    展开全文
  • 网络流主要根据五元组、主机地址、包大小来分类。在网络中存在各种各样包,如果按照上述分类方法,对每一种包都分配一个计数器来储存,虽然测量准确,那么存放计数器空间开销会非常大。所以使用哈希方法,...
  • 用“源IP地址”,“目的IP地址”,“源端口号”,“目的端口号”,协议号(IP协议协议号为4,TCP协议号为6)这样一个五元组来标识一个通信,通信双方在发送消息时,消息头部会带着这样的五元组 3.端口范围...
  • 在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过 netstat -n查看); 端口号范围划分 0 - 1023: 知名端口号, HTTP, FTP, SSH等这些广为
  • poj 3378 Crazy Thairs

    2016-05-31 17:39:00
    给一个长度为n序列ai,定义五元组(i,j,k,l,m)满足: 1<=i<j<k<l<m<=n; ai<aj<ak<al<am; 问序列中有多少个满足条件的五元组。 数据范围:1 <= n <= 50000, 0 <= ...
  • 1.1 什么叫五元组? 在TCP/IP协议中,用源IP、源端口号、目的IP、目的端口号、协议号这样一个五元组来标识一个通信。 1.2 如何查看某个端口? 可以通过netstat -n查看 在Windows中:netstat -ano | finder "想要...
  • 在TCP/IP协议中,用五元组来标识一个通信。 五元组: 协议号(TCP/UDP),源IP,源端口号,目的IP,目的端口号, TCP 172.20.100.33 2001 172.20.100.32 80 ip地址: 标识网络上唯一一台设备。 port端口号: 标识...
  • 五元组:源IP地址,目的IP地址、源端口号,目的端口号、协议号 七元组:源IP地址,目的IP地址、源端口号,目的端口号、协议号、服务类型及接口索引 端口号分类 端口号最多有65536个,范围是0~65535,可以分为三类...
  • 传输层协议:TCP,UDP

    2019-07-20 16:41:54
    TCP/IP协议使用五元组来标识一个通信(使用netstat -n查看);五元组:“源IP”,“源端口号”,“目的IP”,“目的端口号”,“协议号” 端口号范围划分:0-1023:知名端口号,HTTP(80)/FTP(21)/SSH(22)/...
  • s6-3 通信模型

    2021-05-07 07:27:24
    传输层作用范围通信5元组一些已...远方端点五元组 协议、 本地IP地址、本地端口号、 远端IP地址、远端端口号通信5元组 源IP 源端口 目的IP 目的端口 协议  传输层PDU不仅仅送达主机,而且送达端点 ...
  • 第六章关系数据理论

    2020-05-18 20:55:19
     一个关系模式应当是一个五元组。  R(U,D,DOM,F)  R:关系名,表名  U:表示一组属性  D:为属性组属性中的取值范围  DOM:为属性到域的映射  F:为属性组的数据依赖   由于D,.
  • Bzoj4504: K个串

    2018-06-21 00:49:00
    题解: 我们考虑到查询区间类不同数目个数在线做法是主席树维护,然后我们可以维护...即维护每个右端点里面最大值 然后优先队列维护五元组 找出第K大 时间复杂度是(n+k)logn #include <bits/stdc++.h> ...
  • 题解 :很显然 我们直接无法处理前K大和 但是我们可以采取分裂方式 维护以一个端点为定点 左边表示这一段和 很容易我们想到主席树 永久化标记来维护每个点到右端区间和 然后用堆维护一个五元组 表示 是...
  • 在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信。 0 - 1023: 知名端口号, HTTP, FTP, SSH等这些广为使用应用层协议, 他们端口号都是固定....
  • 深信服复习笔记三 基础题目: 1.最大传输单元(MTU)用来通知对方所能...3.防火墙:传统防火墙(包过滤防火墙)判断信息(五元组)工作范围(网络层,传输层) 4.防火墙部署模式:路由模式 透明模式 虚拟网线模式 混合模式 旁
  • 网络-------TCP/UDP

    2020-06-09 23:55:28
    五元组:源IP \ 源端口 \ 目的IP \ 目的端口 \ 协议号 端口号(标识应用程序): Windows查看端口号: nestat - ano | findstr “想查打的端口号” 会显示进程pid Linux查看端口: nestat - ano | grep “想查打的端口号...
  • 传输层

    2021-04-04 20:06:39
    在TCP/IP协议中,用 “源IP”,“源端口号”,“目的IP”,“目的端口号”,“协议号”这样一个五元组来标识一个通信(可以通过 netstat -n查看); 端口号范围划分 0 - 1023:知名端口号,HTTP,FTP,SSH等这些广为...
  • 在TCP/IP协议中, 用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过netstat -n查看); 端口号范围划分 0 - 1023: 知名端口号, HTTP, FTP, SSH等这些广为...
  • 端口号

    2019-04-13 21:13:31
    在Tcp/IP协议中用“源IP”,“源端口号”,“目的IP”,“目的端口号”,“协议号”这样的五元组来标识一个通信(可以通过 netstat -n 查看) 端口号划分范围 1-1023:知名端口号,HTTP,FTP,SSH等这些广为使用...
  • 传输层——UDP详解

    2019-03-15 14:16:12
    在TCP/IP协议中,用“源IP”,“源端口号”,”目的IP“,”目的端口号“,”协议号“这样一个五元组来标识一个通信(可以通过netstat -n查看) 端口号范围划分 0-1023:知名端口号,HTTP,FTP,SSH等这些广为使用...
  • 在TCP/IP协议中,用"源IP","源端口号","目的端口号","协议号"这样一个五元组来标识一个通信(可以通过netstat -n查看); 端口号范围划分 0 - 1023:知名端口号,HTTP,FTP,SSH等这些广为使用应用层协议,...
  • 在TCP/IP协议中,用“源端口号”,“目的端口号”,“源IP”,“目的IP”,“协议号”这样一个五元组来标识一个通信 2.端口号范围划分 0~1023:知名端口号,HTTP、FTP、SSH等这些广为使用应用层协议,他们端口号...
  • 网络基础——传输层

    2018-05-28 17:49:06
    这样一个五元组来标识一个通信 端口号划分范围 ·0——1023:知名端口号窗口号都是固定并众所周知 ·1024——65535:操作系统动态分配端口号 知名端口号 ·ssh服务器:使用22端口 ·f...

空空如也

空空如也

1 2 3
收藏数 48
精华内容 19
热门标签
关键字:

五元组的范围