tcp的65535個連接之迷


前言

上篇《post真的安全么》的最后有提到一個問題,其實這是個既簡單又復雜的問題。

機器連接數

記得以前一台機器只能建立65535個連接的這種想法一直長時間占據着思維方式,為什么會有這種想法呢,估計最早起源於學校的portshort1665535)吧。

一台機器connect同一IP,port的最大連接數

嗯,既然一台機器只能最大建立65535個連接,那當然 為什么一台機器connect同一個IPporttcp連接數不能超過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;

}

 

其中:socksocket的一個內部結構,從__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的最大連接數

那為什么同一台機器連接同一ipport的最大連接數是63335呢,是因為在4元組(src_ip,src_port,dst_ip,dst_port)中,src_ip, dst_ip, dst_port是都是固定的,只有src_port可以變化,所以根據short,所以才是65535.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM