tcp的65535个连接之迷
前言
在上篇《post真的安全么》的最后有提到一个问题,其实这是个既简单又复杂的问题。
机器连接数
记得以前一台机器只能建立65535个连接的这种想法一直长时间占据着思维方式,为什么会有这种想法呢,估计最早起源于学校的port的short(16位65535)吧。
一台机器connect同一IP,port的最大连接数
嗯,既然一台机器只能最大建立65535个连接,那当然” 为什么一台机器connect同一个IP,port的tcp连接数不能超过65535个”这个问题的答案是对的,没有为什么。
真的是这样的么。
TCP连接的唯一性
前面提到的所有的问题,其实都可以归结为一个问题,就是TCP连接的唯一性,是靠系统内部的什么来保证的。其实以前我已经说过,TCP连接在内部是由一个四元组来形成,即(src_ip,src_port,dst_ip,dst_port),当然其实是这4个值的简单的hash值来决定的。侯捷说,源码之前,了无私密。所以我们简单的如下看下去(采用linux内核2.6.16)
如下所示:
inet_hashtables.h
static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
const u32 saddr, const u16 sport,
const u32 daddr, const u16 dport,
const int dif)
{
struct sock *sk;
local_bh_disable();
sk = __inet_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif);
local_bh_enable();
return sk;
}
static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
const u32 saddr, const u16 sport,
const u32 daddr, const u16 hnum,
const int dif)
{
struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr,
hnum, dif);
return sk ? : inet_lookup_listener(hashinfo, daddr, hnum, dif);
}
static inline struct sock *
__inet_lookup_established(struct inet_hashinfo *hashinfo,
const u32 saddr, const u16 sport,
const u32 daddr, const u16 hnum,
const int dif)
{
INET_ADDR_COOKIE(acookie, saddr, daddr)
const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
struct sock *sk;
const struct hlist_node *node;
/* Optimize here for direct hit, only listening connections can
* have wildcards anyways.
*/
unsigned int hash = inet_ehashfn(daddr, hnum, saddr, sport);
struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash);
prefetch(head->chain.first);
read_lock(&head->lock);
sk_for_each(sk, node, &head->chain) {
if (INET_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
goto hit; /* You sunk my battleship! */
}
/* Must check for a TIME_WAIT'er before going to listener hash. */
sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
goto hit;
}
sk = NULL;
out:
read_unlock(&head->lock);
return sk;
hit:
sock_hold(sk);
goto out;
}
其中:sock是socket的一个内部结构,从__inet_lookup_established的名字可以看出,这个是查找建立的socket连接的函数,好,我们继续看下去:
inet_sock.h
static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport,
const __u32 faddr, const __u16 fport)
{
unsigned int h = (laddr ^ lport) ^ (faddr ^ fport);
h ^= h >> 16;
h ^= h >> 8;
return h;
}
static inline int inet_sk_ehashfn(const struct sock *sk)
{
const struct inet_sock *inet = inet_sk(sk);
const __u32 laddr = inet->rcv_saddr;
const __u16 lport = inet->num;
const __u32 faddr = inet->daddr;
const __u16 fport = inet->dport;
return inet_ehashfn(laddr, lport, faddr, fport);
}
从上面的代码里面明显可以看出,inet_ehashfn函数就是计算hash值的方法,也证明了socket其实是4元组组成的论据。
有了上面的源码,现在回到问题
问题一:机器的连接数
所以一台机器的TCP连接数是不只65535的,为什么,因为4元组的组合至少是无限的,机器的连接数,取决于机器的内存,机器的CPU等等这些因素。
问题二:一台机器connect同一IP,port的最大连接数
那为什么同一台机器连接同一ip,port的最大连接数是63335呢,是因为在4元组(src_ip,src_port,dst_ip,dst_port)中,src_ip, dst_ip, dst_port是都是固定的,只有src_port可以变化,所以根据short,所以才是65535.
作者:OUZI(connoryan)
出处:http://www.cnblogs.com/ouzi/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。