天天看點

Struct Socket詳細分析(轉)

    使用者使用socket系統調用編寫應用程式時,通過一個數字來表示一個socket,所有的操作都在該數字上進行,這個數字稱為套接字描述符。在系統調用 的實作函數裡,這個數字就會被映射成一個表示socket的結構體,該結構體儲存了該socket的所有屬性和資料。在核心的協定中實作中,關于表示 socket的結構體,是一個比較複雜的東西,下面一一介紹。 

    struct socket。 

    這是一個基本的BSD socket,我們調用socket系統調用建立的各種不同類型的socket,開始建立的都是它,到後面,各種不同類型的socket在它的基礎上進行 各種擴充。struct socket是在虛拟檔案系統上被建立出來的,可以把它看成一個檔案,是可以被安全地擴充的。下面是其完整定義:

  1. struct socket {  
  2.     socket_state            state;  
  3.     unsigned long           flags;  
  4.     const struct proto_ops *ops;  
  5.     struct fasync_struct    *fasync_list;  
  6.     struct file             *file;  
  7.     struct sock             *sk;  
  8.     wait_queue_head_t       wait;  
  9.     short                   type;  
  10. };  

    state用于表示socket所處的狀态,是一個枚舉變量,其類型定義如下:

  1. typedef enum {  
  2.     SS_FREE = 0,            //該socket還未配置設定  
  3.     SS_UNCONNECTED,         //未連向任何socket  
  4.     SS_CONNECTING,          //正在連接配接過程中  
  5.     SS_CONNECTED,           //已連向一個socket  
  6.     SS_DISCONNECTING        //正在斷開連接配接的過程中  
  7. }socket_state;  

    該成員隻對TCP socket有用,因為隻有tcp是面向連接配接的協定,udp跟raw不需要維護socket狀态。 

    flags是一組标志位,在核心中并沒有發現被使用。 

    ops是協定相關的一組操作集,結構體struct proto_ops的定義如下: 

  1. struct proto_ops {  
  2.         int     family;  
  3.         struct module   *owner;  
  4.         int (*release)(struct socket *sock);  
  5.         int (*bind)(struct socket *sock, struct sockaddr *myaddr, int sockaddr_len);  
  6.         int (*connect)(struct socket *sock, struct sockaddr *vaddr, int sockaddr_len, int flags);  
  7.         int (*socketpair)(struct socket *sock1, struct socket *sock2);  
  8.         int (*accept)(struct socket *sock,struct socket *newsock, int flags);  
  9.         int (*getname)(struct socket *sock, struct sockaddr *addr,int *sockaddr_len, int peer);  
  10.         unsigned int (*poll)(struct file *file, struct socket *sock,  
  11.                         struct poll_table_struct *wait);  
  12.         int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg);  
  13.         int (*listen)(struct socket *sock, int len);  
  14.         int (*shutdown)(struct socket *sock, int flags);  
  15.         int (*setsockopt)(struct socket *sock, int level,  
  16.                         int optname, char __user *optval, int optlen);  
  17.         int (*getsockopt)(struct socket *sock, int level,  
  18.                         int optname, char __user *optval, int __user *optlen);  
  19.         int (*sendmsg)(struct kiocb *iocb, struct socket *sock,  
  20.                         struct msghdr *m, size_t total_len);  
  21.         int (*recvmsg)(struct kiocb *iocb, struct socket *sock,  
  22.                         struct msghdr *m, size_t total_len, int flags);  
  23.         int (*mmap)(struct file *file, struct socket *sock,struct vm_area_struct * vma);  
  24.         ssize_t (*sendpage)(struct socket *sock, struct page *page,  
  25.                         int offset, size_t size, int flags);  
  26.     };  

協定棧中總共定義了三個strcut proto_ops類型的變量,分别是myinet_stream_ops, myinet_dgram_ops, myinet_sockraw_ops,對應流協定, 資料報和原始套接口協定的操作函數集。 

    type是socket的類型,對應的取值如下:

  1. enum sock_type {  
  2.     SOCK_DGRAM = 1,  
  3.     SOCK_STREAM = 2,  
  4.     SOCK_RAW    = 3,  
  5.     SOCK_RDM    = 4,  
  6.     SOCK_SEQPACKET = 5,  
  7.     SOCK_DCCP   = 6,  
  8.     SOCK_PACKET = 10,  

    sk是網絡層對于socket的表示,結構體struct sock比較龐大,這裡不詳細列出,隻介紹一些重要的成員, 

    sk_prot和sk_prot_creator,這兩個成員指向特定的協定處理函數集,其類型是結構體struct proto,該結構體也是跟struct proto_ops相似的一組協定操作函數集。這兩者之間的概念似乎有些混淆,可以這麼了解,struct proto_ops的成員操作struct socket層次上的資料,處理完了,再由它們調用成員sk->sk_prot的函數,操作struct sock層次上的資料。即它們之間存在着層次上的差異。struct proto類型的變量在協定棧中總共也有三個,分别是mytcp_prot,myudp_prot,myraw_prot,對應TCP, UDP和RAW協定。 

    sk_state表示socket目前的連接配接狀态,是一個比struct socket的state更為精細的狀态,其可能的取值如下:    

  1. enum {  
  2.    TCP_ESTABLISHED = 1,  
  3.    TCP_SYN_SENT,  
  4.    TCP_SYN_RECV,  
  5.    TCP_FIN_WAIT1,  
  6.    TCP_FIN_WAIT2,  
  7.    TCP_TIME_WAIT,  
  8.    TCP_CLOSE,  
  9.    TCP_CLOSE_WAIT,  
  10.    TCP_LAST_ACK,  
  11.    TCP_LISTEN,  
  12.    TCP_CLOSING,  
  13.    TCP_MAX_STATES  
  14. ;  

    這些取值從名字上看,似乎隻使用于TCP協定,但事實上,UDP和RAW也借用了其中一些值,在一個socket建立之初,其取值都是 TCP_CLOSE,一個UDP socket connect完成後,将這個值改為TCP_ESTABLISHED,最後,關閉sockt前置回TCP_CLOSE,RAW也一樣。 

    sk_rcvbuf和sk_sndbuf分别表示接收和發送緩沖區的大小。sk_receive_queue和sk_write_queue分别為接收緩 沖隊列和發送緩沖隊列,隊列裡排列的是套接字緩沖區struct sk_buff,隊列中的struct sk_buff的位元組數總和不能超過緩沖區大小的設定。 

接着上一篇,繼續介紹struct sock。 

    sk_rmem_alloc, sk_wmem_alloc和sk_omem_alloc分别表示接收緩沖隊列,發送緩沖隊列及其它緩沖隊列中已經配置設定的位元組數,用于跟蹤緩沖區的使用情況。 

    struct sock有一個struct sock_common成員,因為struct inet_timewait_sock也要用到它,是以把它單獨歸到一個結構體中,其定義如下:

  1. struct sock_common {  
  2.     unsigned short      skc_family;  
  3.     volatile unsigned char skc_state;  
  4.     unsigned char       skc_reuse;  
  5.     int         skc_bound_dev_if;  
  6.     struct hlist_node   skc_node;  
  7.     struct hlist_node   skc_bind_node;  
  8.     atomic_t        skc_refcnt;  
  9.     unsigned int        skc_hash;  
  10.     struct proto        *skc_prot;  

    struct inet_sock。 

    這是INET域專用的一個socket表示,它是在struct sock的基礎上進行的擴充,在基本socket的屬性已具備的基礎上,struct inet_sock提供了INET域專有的一些屬性,比如TTL,多點傳播清單,IP位址,端口等,下面是其完整定義:

  1. struct inet_sock {  
  2.             struct sock     sk;  
  3. #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)  
  4.             struct ipv6_pinfo   *pinet6;  
  5. #endif  
  6.             __u32           daddr;          //IPv4的目的位址。  
  7.             __u32           rcv_saddr;      //IPv4的本地接收位址。  
  8.             __u16           dport;          //目的端口。  
  9.             __u16           num;            //本地端口(主機位元組序)。  
  10.             __u32           saddr;          //發送位址。  
  11.             __s16           uc_ttl;         //單點傳播的ttl。  
  12.             __u16           cmsg_flags;  
  13.             struct ip_options   *opt;  
  14.             __u16           sport;          //源端口。  
  15.             __u16           id;             //單調遞增的一個值,用于賦給iphdr的id域。  
  16.             __u8            tos;            //服務類型。  
  17.             __u8            mc_ttl;         //多點傳播的ttl  
  18.             __u8            pmtudisc;  
  19.             __u8            recverr:1,  
  20.                             is_icsk:1,  
  21.                             freebind:1,  
  22.                             hdrincl:1,      //是否自己建構ip首部(用于raw協定)  
  23.                             mc_loop:1;      //多點傳播是否發向回路。  
  24.             int             mc_index;       //多點傳播使用的本地裝置接口的索引。  
  25.             __u32           mc_addr;        //多點傳播源位址。  
  26.             struct ip_mc_socklist   *mc_list;   //多點傳播組清單。  
  27.             struct {  
  28.                 unsigned int        flags;  
  29.                 unsigned int        fragsize;  
  30.                 struct ip_options   *opt;  
  31.                 struct rtable       *rt;  
  32.                 int                 length;  
  33.                 u32                 addr;  
  34.                 struct flowi        fl;  
  35.             } cork;  
  36.         };  

    struct raw_sock 

    這是RAW協定專用的一個socket的表示,它是在struct inet_sock基礎上的擴充,因為RAW協定要處理ICMP協定的過濾設定,其定義如下:

  1. struct raw_sock {  
  2.     struct inet_sock   inet;  
  3.     struct icmp_filter filter;  

    struct udp_sock 

    這是UDP協定專用的一個socket表示,它是在struct inet_sock基礎上的擴充,其定義如下:

  1. struct udp_sock {  
  2.     struct inet_sock inet;  
  3.     int             pending;  
  4.     unsigned int    corkflag;  
  5.     __u16           encap_type;  
  6.     __u16           len;  

    struct inet_connection_sock 

    看完上面兩個,我們覺得第三個應該就是struct tcp_sock了,但事實上,struct tcp_sock并不直接從struct inet_sock上擴充,而是從struct inet_connection_sock基礎上進行擴充,struct inet_connection_sock是所有面向連接配接的socket的表示,關于該socket,及下面所有tcp相關的socket,我們在分析 tcp實作時再詳細介紹,這裡隻列出它們的關系。 

    strcut tcp_sock 

    這是TCP協定專用的一個socket表示,它是在struct inet_connection_sock基礎進行擴充,主要是增加了滑動視窗協定,避免擁塞算法等一些TCP專有屬性。 

    struct inet_timewait_sock 

    struct tcp_timewait_sock 

    在struct inet_timewait_sock的基礎上進行擴充。 

    struct inet_request_sock 

    struct tcp_request_sock 

    在struct inet_request_sock的基礎上進行擴充。

------------------越是喧嚣的世界,越需要甯靜的思考------------------

合抱之木,生于毫末;九層之台,起于壘土;千裡之行,始于足下。

積土成山,風雨興焉;積水成淵,蛟龍生焉;積善成德,而神明自得,聖心備焉。故不積跬步,無以至千裡;不積小流,無以成江海。骐骥一躍,不能十步;驽馬十駕,功在不舍。锲而舍之,朽木不折;锲而不舍,金石可镂。蚓無爪牙之利,筋骨之強,上食埃土,下飲黃泉,用心一也。蟹六跪而二螯,非蛇鳝之穴無可寄托者,用心躁也。