日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

socket buffer套接字缓存

發布時間:2023/12/20 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 socket buffer套接字缓存 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近公司在開發機器人與服務器調度端的通信時需要使用socket,因此找到了該文章作為深刻理解socket內部運作。

Linux網絡核心數據結構是套接字緩存(socket buffer),簡稱skb。它代表一個要發送或處理的報文,并貫穿于整個協議棧。

1、?? ?套接字緩存
skb由兩部分組成:
(1)?? ?報文數據:它保存了實際在網絡中傳輸的數據;
(2)?? ?管理數據:供內核處理報文的額外數據,這些數據構成了協議之間交換的控制信息。
當應用程序向一個socket傳輸數據之后,該socket將創建相應的套接字緩存,并將用戶數據拷貝到緩存中。當報文在各協議層傳達輸的過程中,每一導的報文頭將插入到用戶數據之前。skb為報文頭申請了足夠的空間,所以避免了由于插入報文頭而對報文進行多次拷貝。用戶數據只拷貝了兩次:一是從用戶空間拷貝到內核;二是報文數據從內核傳送到網絡適配器。
1.1、sk_buff

套接字緩存結構:


[cpp]?view plaincopy
  • struct?sk_buff?{??
  • ????/*?These?two?members?must?be?first.?*/??
  • ????struct?sk_buff????????*next;????
  • ????struct?sk_buff????????*prev;??
  • ??
  • ????struct?sk_buff_head????*list;????
  • ????struct?sock????????*sk;??????????//指向創建報文的socket??
  • ????struct?timeval????????stamp;??//此報文收到時的時間??
  • ????struct?net_device????*dev;??????????//收到此報文的網絡設備???
  • ????struct?net_device????*input_dev;??
  • ????struct?net_device????*real_dev;??
  • ??
  • ????//TCP報頭??
  • ????union?{????
  • ????????struct?tcphdr????*th;???//tcp頭??
  • ????????struct?udphdr????*uh;??//udp頭??
  • ????????struct?icmphdr????*icmph;??
  • ????????struct?igmphdr????*igmph;??
  • ????????struct?iphdr????*ipiph;??
  • ????????struct?ipv6hdr????*ipv6h;??
  • ????????unsigned?char????*raw;??
  • ????}?h;??
  • ????//IP報頭??
  • ????union?{??
  • ????????struct?iphdr????*iph;??
  • ????????struct?ipv6hdr????*ipv6h;??
  • ????????struct?arphdr????*arph;??
  • ????????unsigned?char????*raw;??
  • ????}?nh;??
  • ????//鏈路層幀頭??
  • ????union?{??
  • ??????????unsigned?char?????*raw;??
  • ????}?mac;??
  • ??
  • ????struct??dst_entry????*dst;??//此報文的路由,路由確定后賦此值??
  • ????struct????sec_path????*sp;??
  • ??
  • ????/*?
  • ?????*?This?is?the?control?buffer.?It?is?free?to?use?for?every?
  • ?????*?layer.?Please?put?your?private?variables?there.?If?you?
  • ?????*?want?to?keep?them?across?layers?you?have?to?do?a?skb_clone()?
  • ?????*?first.?This?is?owned?by?whoever?has?the?skb?queued?ATM.?
  • ?????*/??
  • ????char????????????cb[40];??
  • ??????
  • ????//此報文的長度,這是指網絡報文在不同協議層中的長度,包括頭部和數據。在協議棧的不同層,這個長度是不同的。???
  • ????unsigned?int????????len,??
  • ????????????????data_len,??
  • ????????????????mac_len,??
  • ????????????????csum;??
  • ????unsigned?char????????local_df,??
  • ????????????????cloned,??
  • ????????????????pkt_type,?//網絡報文的類型,常見的有PACKET_HOST,代表發給本機的報文;還有PACKET_OUTGOING,代表本機發出的報文。???
  • ????????????????ip_summed;??
  • ????__u32????????????priority;??
  • ???????
  • ????unsigned?short????????protocol,//鏈路層協議??
  • ????????????????security;??
  • ??
  • ????void????????????(*destructor)(struct?sk_buff?*skb);??
  • #ifdef?CONFIG_NETFILTER??
  • ????????unsigned?long????????nfmark;??
  • ????__u32????????????nfcache;??
  • ????__u32????????????nfctinfo;??
  • ????struct?nf_conntrack????*nfct;??
  • #ifdef?CONFIG_NETFILTER_DEBUG??
  • ????????unsigned?int????????nf_debug;??
  • #endif??
  • #ifdef?CONFIG_BRIDGE_NETFILTER??
  • ????struct?nf_bridge_info????*nf_bridge;??
  • #endif??
  • #endif?/*?CONFIG_NETFILTER?*/??
  • #if?defined(CONFIG_HIPPI)??
  • ????union?{??
  • ????????__u32????????ifield;??
  • ????}?private;??
  • #endif??
  • #ifdef?CONFIG_NET_SCHED??
  • ???????__u32????????????tc_index;????????/*?traffic?control?index?*/??
  • #ifdef?CONFIG_NET_CLS_ACT??
  • ????__u32???????????tc_verd;???????????????/*?traffic?control?verdict?*/??
  • ????__u32???????????tc_classid;????????????/*?traffic?control?classid?*/??
  • #endif??
  • ??
  • #endif??
  • ??
  • ??
  • ????/*?These?elements?must?be?at?the?end,?see?alloc_skb()?for?details.??*/??
  • ??
  • ???????//此報文存儲區的長度,這個長度是16字節對齊的,一般要比報文的長度大??
  • ????unsigned?int????????truesize;??
  • ????atomic_t????????users;??
  • ????/*head和end指向報文數據的整個單元.head與data之間的空間稱為headroom,tail與end之間的空間稱為tailroom.?
  • ????*/??
  • ????unsigned?char????????*head,??
  • ????????????????*data,??
  • ????????????????*tail,??
  • ????????????????*end;??
  • };??
  • 1.2、與sk_buff相關的函數
    與sk_buff相關的函數涉及到網絡報文存儲結構和控制結構的分配、復制、釋放,以及控制結構里的各指針的操作,還有各種標志的檢查。重要的函數說明如下:?

    struct sk_buff *alloc_skb(unsigned int size,int gfp_mask )?
    分配大小為size的存儲空間存放網絡報文,同時分配它的控制結構。size的值是16字節對齊的,gfp_mask是內存分配的優先級。常見的內存分配優先級有GFP_ATOMIC,代表分配過程不能被中斷,一般用于中斷上下文中分配內存;GFP_KERNEL,代表分配過程可以被中斷,相應的分配請求被放到等待隊列中。分配成功之后,因為還沒有存放具體的網絡報文,所以sk_buff的 data,tail指針都指向存儲空間的起始地址,len的大小為0,而且 is_clone和cloned兩個標記的值都是0。?

    struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask )?
    從控制結構skb中 clone出一個新的控制結構,它們都指向同一個網絡報文。clone成功之后,將新的控制結構和原來的控制結構的 is_clone,cloned兩個標記都置位。同時還增加網絡報文的引用計數(這個引用計數存放在存儲空間的結束地址的內存中,由函數atomic_t *skb_datarefp(struct sk_buff *skb)訪問,引用計數記錄了這個存儲空間有多少個控制結構)。由于存在多個控制結構指向同一個存儲空間的情況,所以在修改存儲空間里面的內容時,先要確定這個存儲空間的引用計數為1,或者用下面的拷貝函數復制一個新的存儲空間,然后才可以修改它里面的內容。?

    struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask )?
    復制控制結構skb和它所指的存儲空間的內容。復制成功之后,新的控制結構和存儲空間與原來的控制結構和存儲空間相對獨立。所以新的控制結構里的is_clone,cloned兩個標記都是0,而且新的存儲空間的引用計數是1。
    ?
    void kfree_skb(struct sk_buff *skb)
    釋放控制結構skb和它所指的存儲空間。由于一個存儲空間可以有多個控制結構,所以只有在存儲空間的引用計數為1的情況下才釋放存儲空間,一般情況下,只釋放控制結構skb。?

    unsigned char *skb_put(struct sk_buff *skb, unsigned int len )?
    將tail指針下移,并增加skb的 len值。data和 tail之間的空間就是可以存放網絡報文的空間。這個操作增加了可以存儲網絡報文的空間,但是增加不能使tail的值大于end的值,skb的 len值大于truesize的值。?

    unsigned char *skb_push(struct sk_buff *skb, unsigned int len )?
    將data指針上移,并增加skb的 len值。這個操作在存儲空間的頭部增加了一段可以存儲網絡報文的空間,上一個操作在存儲空間的尾部增加了一段可以存儲網絡報文的空間。但是增加不能使data的值小于head的值,skb的 len值大于truesize的值。?

    unsigned char * skb_pull(struct sk_buff *skb, unsigned int len )?
    將data指針下移,并減小skb的 len值。這個操作使data指針指向下一層網絡報文的頭部。?

    void skb_reserve(struct sk_buff *skb, unsigned int len )?
    將data指針和tail指針同時下移。這個操作在存儲空間的頭部預留 len長度的空隙。
    ?
    void skb_trim(struct sk_buff *skb, unsigned int len )?
    將網絡報文的長度縮減到 len。這個操作丟棄了網絡報文尾部的填充值。?

    int skb_cloned(struct sk_buff *skb )?
    判斷skb是否是一個 clone的控制結構。如果是clone的,它的cloned標記是1,而且它指向的存儲空間的引用計數大于1。

    2、?? ?套接字緩存隊列(Socket-Buffer Queues)
    2.1、sk_buff_head
    在網絡協議棧的實現中,有時需要把許多網絡報文放到一個隊列中做異步處
    理。LINUX 為此定義了相關的數據結構 sk_buff_head。這是一個雙向鏈表的
    頭,它把sk_buff鏈接成一個雙向鏈表。


    ? [cpp]?view plaincopy
  • //套接字緩存隊列頭??
  • struct?sk_buff_head?{??
  • ????/*?These?two?members?must?be?first.?*/??
  • ????struct?sk_buff????*next;??
  • ????struct?sk_buff????*prev;??
  • ??
  • ????__u32????????qlen;?//隊列的長度,即隊列中報文的數量??
  • ????spinlock_t????lock;??
  • };??
  • 2.2、與 sk_buff_head相關的函數
    void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk )?
    將newsk加到鏈表 list的頭部。?

    void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
    將newsk加到鏈表 list的尾部。?

    struct sk_buff *skb_dequeue(struct sk_buff_head *list )?
    從鏈表 list的頭部取下一個 sk_buff。?

    struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list )?
    從鏈表 list的尾部取下一個 sk_buff。
    ?
    skb_insert(struct sk_buff *old, struct sk_buff *newsk )?
    將newsk加到old所在的鏈表上,并且 newsk在old的前面。
    ?
    void skb_append(struct sk_buff *old, struct sk_buff *newsk )?
    將newsk加到old所在的鏈表上,并且 newsk在old的后面。
    ?
    void skb_unlink(struct sk_buff *skb )?
    將skb從它所在的鏈表上取下。?
    以上的鏈表操作都是先關中斷的。這在中斷上下文中是不需要的,所以另外有一套與上面函數同名但是有前綴“__”的函數供運行在中斷上下文中的函數調用。

    總結

    以上是生活随笔為你收集整理的socket buffer套接字缓存的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。