資源描述:
《Linux內(nèi)核網(wǎng)絡(luò)協(xié)議棧5-socket端口管理》由會員上傳分享,免費在線閱讀,更多相關(guān)內(nèi)容在工程資料-天天文庫。
1、Linux內(nèi)核網(wǎng)絡(luò)協(xié)議棧5—socket端口管理作者:zhuyoong一.前情回顧上一節(jié)《socket地址綁定》中提到,應(yīng)用程序傳遞過來的端口在內(nèi)核中需耍檢查端口是否可用:1.if(sk->sk_pr>get_port(sk,snum)){2.inet?>saddr=inercv_saddr=0;3?err=-EADDRINUSE;4.gotoout_release_sock;5?}按照前面的例子來分析,這里是調(diào)用了tcp_prot結(jié)構(gòu)變量屮的get_prot函數(shù)指針,該函數(shù)位于net/ipv4/lnet_connection_s
2、ock.c中;這個函數(shù)比較長,也是我們今天要分析的重點;二.端口的管理1、端口管理數(shù)據(jù)結(jié)構(gòu)Linux內(nèi)核將所冇socket使用時的端口通過一個哈希表來管理,該哈希表存放在全局變量tcp_hashinfo中,通過tcp_prot變量的h成員引用,該成員是一個聯(lián)合類型;對于tcp套接字類型,其引用存放在h?hashinfo成員中;卜?面是tcp_hashinfo的結(jié)構(gòu)體類型:1.structinet_hashinfo{2?structinet_ehash_bucket*ehash;3?rwlock_t*ehash_locks;4?un
3、signedintehash_size;5?Aunsignedintehash_locks_mask;O?7?structinet_bind_hashbucket*bhash;//管理端口的哈希農(nóng)8?unsignedintbhash_size;//端口哈希表的大小9?10.structhlist_headlistening_hash[INET_LHTABLE_SIZE];rwlock_tlhashlockcachelinealigne12?atomic_tlhash_users;wait_queue_head_tlhash_wai
4、t;14.structkmem_cache*bind_bucket_cachep;//哈希表結(jié)構(gòu)高速緩存15.}端口管理相關(guān)的,目前可以只關(guān)注加注釋的這三個成員,其中bhash為已經(jīng)哈希表結(jié)構(gòu),bhash_size為哈希表的大??;所有哈希表中的節(jié)點內(nèi)存都是在bindbucketcachep高速緩存中分配;卜而看一下inetbindhashbucket結(jié)構(gòu)體:1?structinet_bind_hashbucket{2?spinlock_tlock;3?structhlist__headchain;4?};5?structhlist
5、_head{6?structhlist_.node*first;7?};8.structhlist_node{9?structhlist_node*next,**pprev;10.};inet_bind_hashbucket是哈希桶結(jié)構(gòu),lock成員是用于操作時對桶進(jìn)行?加鎖,chain成員是相同哈希值的節(jié)點的鏈表;示意圖如下:next2、默認(rèn)端口的分配當(dāng)應(yīng)用程序沒有指定端口時(如socket客戶端連接到服務(wù)端時,會由內(nèi)核從可用端口中分配一個給該socket);看看卜?面的代碼(參見net/ipv4/Inct_conncction
6、_sock?c:inct_csk_gct_port()函數(shù)):1.if(!snum){2.intremaining,rover,low,high;3?4.get_local_port_range(&low,&high);5.remaining=(high-low)+1;6.rover=net_random()%remaining+low;7?8.do{9.head=&hashinfo?>bhash[inet_bhashfn(rover,hashinfo?>bhashsize)];10lock);
7、11.inet_bind_bucket_for_each(tb,node,&head?>chain)12.if(tb->ib_net==net&&tb->port==rover)13.gotonext;14.break;15.next:16.spin_unlock(&head?>lock);17.if(++rover>high)18?rover=low;19?}while(--remaining>0);20?21?ret=1;22?if(remaining<=0)23.gotofail;24?25?snum=rover;26?}這
8、里,隨機(jī)端口的范圍是32768^61000;上面代碼的邏輯如下:1)從[32768,61000]中隨機(jī)取一個端口rover;2)計算該端口的hash值,然后從全局變量tcp_hashinfo的哈希表bhash中取出相同哈希值的鏈表head;3)遍丿