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

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

  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;
  11. };

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;
  4. };

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

Struct Socket详细分析(转)的更多相关文章

  1. linux内核中socket的创建过程源码分析(详细分析)

    1三个相关数据结构. 关于socket的创建,首先需要分析socket这个结构体,这是整个的核心. 104 struct socket { 105         socket_state       ...

  2. struct socket 结构详解

    Socket数据结构网络协议CC++     用户使用socket系统调用编写应用程序时,通过一个数字来表示一个socket,所有的操作都在该数字上进行,这个数字称为套接字描述符.在系统调用 的实现函 ...

  3. 海思uboot启动流程详细分析(三)【转】

    1. 前言 书接上文(u-boot启动流程分析(二)_平台相关部分),本文介绍u-boot启动流程中和具体版型(board)有关的部分,也即board_init_f/board_init_r所代表的. ...

  4. 内核中container_of宏的详细分析【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637597.html 内核中container_of宏的详细分析 16年2月28日09:00:37 内核中 ...

  5. Linux内核TCP MSS机制详细分析

    前言 上周Linux内核修复了4个CVE漏洞[1],其中的CVE-2019-11477感觉是一个很厉害的Dos漏洞,不过因为有其他事打断,所以进展的速度比较慢,这期间网上已经有相关的分析文章了.[2] ...

  6. PE头详细分析

    目录 PE头详细分析 0x00 前言 0x01 PE文件介绍 0x02 PE头详细分析 DOS头解析 NT头解析 标准PE头解析 可选PE头解析 可选PE头结构 基址 代码段地址 数据段地址 OEP程 ...

  7. PE节表详细分析

    目录 PE节表详细分析 0x00 前言 0x01 PE节表分析 节表结构 节表数量 节表名字 节表大小 节位置 节表属性 0x02 代码编写 PE节表详细分析 0x00 前言 上一篇文章我们学习了PE ...

  8. ZIP压缩算法详细分析及解压实例解释

    最近自己实现了一个ZIP压缩数据的解压程序,觉得有必要把ZIP压缩格式进行一下详细总结,数据压缩是一门通信原理和计算机科学都会涉及到的学科,在通信原理中,一般称为信源编码,在计算机科学里,一般称为数据 ...

  9. 1125MySQL Sending data导致查询很慢的问题详细分析

    -- 问题1 tablename使用主键索引反而比idx_ref_id慢的原因EXPLAIN SELECT SQL_NO_CACHE COUNT(id) FROM dbname.tbname FORC ...

随机推荐

  1. git clean解决 GIT error: The following untracked working tree files would be overwritten

    git clean用法:https://www.cnblogs.com/lsgxeva/p/8540476.html :

  2. Redis GEO地理位置信息,查看附近的人

    在之前的一篇文章<SpringBoot入门教程(五)Java基于MySQL实现附近的人>,我们介绍了Java基于MySQL实现查找附近的人的功能.今天就来研究研究"查找附近的人& ...

  3. Wamp Https 的 SSL认证 配置说明

    Wamp Https 的 SSL认证 配置说明版本 Apache2.2.11注:右下角图标的 重启 不能有效加载 配置文件 应退出后重新运行注:C:\wamp\bin\apache\Apache2.2 ...

  4. 数据库‘master’中拒绝CREATE DATABASE权限

    今天在创建数据库的时候,遇到了没有创建数据库权限的问题,后来百度了一下解决了该问题. 1.先用windows身份验证登录,在安全性下面的找到自己创建的登录名,双击,在弹出的对话框中为它赋予权限. 2. ...

  5. 将EntityFrameworkCore生成的SQL语句输出到控制台,使用hangfire

    将EntityFrameworkCore生成的SQL语句输出到控制台 参考文档如下 EF Core 日志记录要求使用一个或多个日志记录提供程序配置的 ILoggerFactory. 日志记录-EF C ...

  6. java jsp文件报错解决方法

    初次使用java开发 下载好代码之后,用maven编译都是ok的,第二天,打开项目一看,好的web项目的jsp文件提示错误,后面,查了下问题,是tomcat没有配置路径导致的问题,现在大致记录一下解决 ...

  7. systemd - CentOS 7进程守护&监控

    需求: 运行环境为CentOS 7系统,我们开发了一个程序,需要在开机时启动它,当程序进程crash或者开机之后,守护进程立即拉起进程. 解决方案: 使用CentOS 7中的init进程systemd ...

  8. python numPy模块 与numpy里的数据类型、数据类型对象dtype

    学习链接:http://www.runoob.com/numpy/numpy-tutorial.html 官方链接:https://numpy.org/devdocs/user/quickstart. ...

  9. 链表(Linked List)

    链表(Linked List) 一.介绍 链表是有序的列表,它在内存中存储方式(物理存储)如下: 小结: (1)链表是以节点的方式来存储,是链式存储. (2)每个节点包含 data 域:存储数据:ne ...

  10. Python小练习:批量删除多个文件夹内的相同文件

    应用场景: 下载的多个文件夹是压缩包,解压后每个文件夹都有某个网站的推广链接,想要批量的删除该文件 使用环境:win7,python3.6 代码: 1.直接用for循环 由于os.walk()方法自带 ...