• Struct Socket详细分析(转)


    原文地址:http://anders0913.iteye.com/blog/411986

        用户使用socket系统调用编写应用程序时,通过一个数字来表示一个socket,所有的操作都在该数字上进行,这个数字称为套接字描述符。在系统调用 的实现函数里,这个数字就会被映射成一个表示socket的结构体,该结构体保存了该socket的所有属性和数据。在内核的协议中实现中,关于表示 socket的结构体,是一个比较复杂的东西,下面一一介绍。
        struct socket。
        这是一个基本的BSD socket,我们调用socket系统调用创建的各种不同类型的socket,开始创建的都是它,到后面,各种不同类型的socket在它的基础上进行 各种扩展。struct socket是在虚拟文件系统上被创建出来的,可以把它看成一个文件,是可以被安全地扩展的。下面是其完整定义:

    C代码  收藏代码
    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所处的状态,是一个枚举变量,其类型定义如下:

    C代码  收藏代码
    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的定义如下:
       

    C代码  收藏代码
    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.     };  
    27.       

    协议栈中总共定义了三个strcut proto_ops类型的变量,分别是myinet_stream_ops, myinet_dgram_ops, myinet_sockraw_ops,对应流协议, 数据报和原始套接口协议的操作函数集。
        type是socket的类型,对应的取值如下:

    C代码  收藏代码
    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,  
    9. };  


        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更为精细的状态,其可能的取值如下:   

    C代码  收藏代码
    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.   
    14.    TCP_MAX_STATES  
    15. ;  


        这些取值从名字上看,似乎只使用于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也要用到它,所以把它单独归到一个结构体中,其定义如下:

    C代码  收藏代码
    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;  
    11. };  



        struct inet_sock。
        这是INET域专用的一个socket表示,它是在struct sock的基础上进行的扩展,在基本socket的属性已具备的基础上,struct inet_sock提供了INET域专有的一些属性,比如TTL,组播列表,IP地址,端口等,下面是其完整定义:

    C代码  收藏代码
    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协议的过滤设置,其定义如下:

    C代码  收藏代码
    1. struct raw_sock {  
    2.     struct inet_sock   inet;  
    3.     struct icmp_filter filter;  
    4. };  



        struct udp_sock
        这是UDP协议专用的一个socket表示,它是在struct inet_sock基础上的扩展,其定义如下:

    C代码  收藏代码
    1. struct udp_sock {  
    2.     struct inet_sock inet;  
    3.     int             pending;  
    4.     unsigned int    corkflag;  
    5.     __u16           encap_type;  
    6.     __u16           len;  
    7. };  



        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的基础上进行扩展。

  • 相关阅读:
    JAVA线程池管理及分布式HADOOP调度框架搭建
    技术人员如何创业《二》 合伙人的模式
    JavaScript中的运动数学函数(持续更新)
    JavaScript中的加号
    JavaScript 函数绑定 Function.prototype.bind
    基于C#的波形显示控件的实现[附完整源码下载]
    JavaScript中的声明提升
    JavaScript & HTML5 Canvas 概览 更新时间201404111805
    《编写高质量代码——Web前端开发修炼之道》读后随笔
    B树/B+树/二叉搜索树/AVL树/红黑树
  • 原文地址:https://www.cnblogs.com/wlei/p/2643539.html
Copyright © 2020-2023  润新知