原文地址: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. 给电脑提升权限---- 切换为administrator

    在装系统的时候我们都会在安装的时候进行创建用户这一操作,安装软件的时候总会出现权限不足的情况, 个人建议:如果你要是比较会使用电脑的话,可以体验一下超级管理员这一角色, 就是安装好了之后,切换为超级管 ...

  2. bootstrap使用笔记

    本文翻译自[http://getbootstrap.com/2.3.2/scaffolding.html#gridSystem] 1.需要在H5的文档声明中使用: 2.如下一个简单的两列布局,先添加一 ...

  3. SQL分类之DDL:操作数据库表

    DDL:操作数据库表 1.操作数据库:CRUD 1.C(Create):创建 创建数据库: create database 数据库名称 创建数据库,判断不存在,再创建: create database ...

  4. zabbix4.0 本地安装详解及步骤

    安装前说明下,下面安装过程中涉及selinux部分仅供参考,可能会导致启动服务时产生各种报错,作者也是在折腾了无数日夜后报错不断而放弃治疗,直接永久关闭了selinux(啊,没有selinux的日子真 ...

  5. 华为 S5700 交换机 批量修改端口方法

    常常在配置交换机端口的时候需要将多个端口设置为相同的配置,当时各端口逐一去配置不仅慢,而且容易出错,这个时候就需要对端口进行批量设置,不仅快捷,而且避免了反复输出容易出错的情况.不同系列.不同版本交换 ...

  6. java基础 接口静态方法

    /** * 从java8开始,接口当中允许定义静态方法 * 格式: * public static 返回值类型 方法名称(参数列表){ * 方法体 * } * 提示:就是将abstract或者defa ...

  7. Excel导出,添加有效性

    #region  添加有效性 DataTable dt = LAbll.LogisticsAccounts(DeptId); //查数据 if (dt.Rows.Count < 20) //有效 ...

  8. 用python完成排序算法

    排序算法总结 冒泡排序 相邻两个元素,两两循环比较,每趟筛选出一个最大或者最小的元素(有序区在后面) def bubble_sort(data): # 第一层循环:循环一次,代表一趟,并筛选出一个最大 ...

  9. 使用EF Core+CodeFirst建立ASP.NET Core MVC项目

    本篇随笔介绍如何使用.NET Core+EF Core创建Web应用程序 首先借用官网的话简单介绍一下ASP.NET Core ASP.NET Core 是一个跨平台的高性能开源框架,用于生成基于云且 ...

  10. jQuery常用方法(五)

    一.jQuery中常用方法相关方法参数说明:a.无参,获取值b.参数param,设置值c.参数function(index,oldVal){}回调函数[返回我们所要使用的新值]    回调函数的两个参 ...