Struct Socket详细分析(转)
原文地址:http://anders0913.iteye.com/blog/411986
用户使用socket系统调用编写应用程序时,通过一个数字来表示一个socket,所有的操作都在该数字上进行,这个数字称为套接字描述符。在系统调用 的实现函数里,这个数字就会被映射成一个表示socket的结构体,该结构体保存了该socket的所有属性和数据。在内核的协议中实现中,关于表示 socket的结构体,是一个比较复杂的东西,下面一一介绍。
struct socket。
这是一个基本的BSD socket,我们调用socket系统调用创建的各种不同类型的socket,开始创建的都是它,到后面,各种不同类型的socket在它的基础上进行 各种扩展。struct socket是在虚拟文件系统上被创建出来的,可以把它看成一个文件,是可以被安全地扩展的。下面是其完整定义:
- struct socket {
- socket_state state;
- unsigned long flags;
- const struct proto_ops *ops;
- struct fasync_struct *fasync_list;
- struct file *file;
- struct sock *sk;
- wait_queue_head_t wait;
- short type;
- };
state用于表示socket所处的状态,是一个枚举变量,其类型定义如下:
- typedef enum {
- SS_FREE = 0, //该socket还未分配
- SS_UNCONNECTED, //未连向任何socket
- SS_CONNECTING, //正在连接过程中
- SS_CONNECTED, //已连向一个socket
- SS_DISCONNECTING //正在断开连接的过程中
- }socket_state;
该成员只对TCP socket有用,因为只有tcp是面向连接的协议,udp跟raw不需要维护socket状态。
flags是一组标志位,在内核中并没有发现被使用。
ops是协议相关的一组操作集,结构体struct proto_ops的定义如下:
- struct proto_ops {
- int family;
- struct module *owner;
- int (*release)(struct socket *sock);
- int (*bind)(struct socket *sock, struct sockaddr *myaddr, int sockaddr_len);
- int (*connect)(struct socket *sock, struct sockaddr *vaddr, int sockaddr_len, int flags);
- int (*socketpair)(struct socket *sock1, struct socket *sock2);
- int (*accept)(struct socket *sock,struct socket *newsock, int flags);
- int (*getname)(struct socket *sock, struct sockaddr *addr,int *sockaddr_len, int peer);
- unsigned int (*poll)(struct file *file, struct socket *sock,
- struct poll_table_struct *wait);
- int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg);
- int (*listen)(struct socket *sock, int len);
- int (*shutdown)(struct socket *sock, int flags);
- int (*setsockopt)(struct socket *sock, int level,
- int optname, char __user *optval, int optlen);
- int (*getsockopt)(struct socket *sock, int level,
- int optname, char __user *optval, int __user *optlen);
- int (*sendmsg)(struct kiocb *iocb, struct socket *sock,
- struct msghdr *m, size_t total_len);
- int (*recvmsg)(struct kiocb *iocb, struct socket *sock,
- struct msghdr *m, size_t total_len, int flags);
- int (*mmap)(struct file *file, struct socket *sock,struct vm_area_struct * vma);
- ssize_t (*sendpage)(struct socket *sock, struct page *page,
- int offset, size_t size, int flags);
- };
协议栈中总共定义了三个strcut proto_ops类型的变量,分别是myinet_stream_ops, myinet_dgram_ops, myinet_sockraw_ops,对应流协议, 数据报和原始套接口协议的操作函数集。
type是socket的类型,对应的取值如下:
- enum sock_type {
- SOCK_DGRAM = 1,
- SOCK_STREAM = 2,
- SOCK_RAW = 3,
- SOCK_RDM = 4,
- SOCK_SEQPACKET = 5,
- SOCK_DCCP = 6,
- 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更为精细的状态,其可能的取值如下:
- enum {
- TCP_ESTABLISHED = 1,
- TCP_SYN_SENT,
- TCP_SYN_RECV,
- TCP_FIN_WAIT1,
- TCP_FIN_WAIT2,
- TCP_TIME_WAIT,
- TCP_CLOSE,
- TCP_CLOSE_WAIT,
- TCP_LAST_ACK,
- TCP_LISTEN,
- TCP_CLOSING,
- TCP_MAX_STATES
- ;
这些取值从名字上看,似乎只使用于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也要用到它,所以把它单独归到一个结构体中,其定义如下:
- struct sock_common {
- unsigned short skc_family;
- volatile unsigned char skc_state;
- unsigned char skc_reuse;
- int skc_bound_dev_if;
- struct hlist_node skc_node;
- struct hlist_node skc_bind_node;
- atomic_t skc_refcnt;
- unsigned int skc_hash;
- struct proto *skc_prot;
- };
struct inet_sock。
这是INET域专用的一个socket表示,它是在struct sock的基础上进行的扩展,在基本socket的属性已具备的基础上,struct inet_sock提供了INET域专有的一些属性,比如TTL,组播列表,IP地址,端口等,下面是其完整定义:
- struct inet_sock {
- struct sock sk;
- #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct ipv6_pinfo *pinet6;
- #endif
- __u32 daddr; //IPv4的目的地址。
- __u32 rcv_saddr; //IPv4的本地接收地址。
- __u16 dport; //目的端口。
- __u16 num; //本地端口(主机字节序)。
- __u32 saddr; //发送地址。
- __s16 uc_ttl; //单播的ttl。
- __u16 cmsg_flags;
- struct ip_options *opt;
- __u16 sport; //源端口。
- __u16 id; //单调递增的一个值,用于赋给iphdr的id域。
- __u8 tos; //服务类型。
- __u8 mc_ttl; //组播的ttl
- __u8 pmtudisc;
- __u8 recverr:1,
- is_icsk:1,
- freebind:1,
- hdrincl:1, //是否自己构建ip首部(用于raw协议)
- mc_loop:1; //组播是否发向回路。
- int mc_index; //组播使用的本地设备接口的索引。
- __u32 mc_addr; //组播源地址。
- struct ip_mc_socklist *mc_list; //组播组列表。
- struct {
- unsigned int flags;
- unsigned int fragsize;
- struct ip_options *opt;
- struct rtable *rt;
- int length;
- u32 addr;
- struct flowi fl;
- } cork;
- };
struct raw_sock
这是RAW协议专用的一个socket的表示,它是在struct inet_sock基础上的扩展,因为RAW协议要处理ICMP协议的过滤设置,其定义如下:
- struct raw_sock {
- struct inet_sock inet;
- struct icmp_filter filter;
- };
struct udp_sock
这是UDP协议专用的一个socket表示,它是在struct inet_sock基础上的扩展,其定义如下:
- struct udp_sock {
- struct inet_sock inet;
- int pending;
- unsigned int corkflag;
- __u16 encap_type;
- __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的基础上进行扩展。
Struct Socket详细分析(转)的更多相关文章
- linux内核中socket的创建过程源码分析(详细分析)
1三个相关数据结构. 关于socket的创建,首先需要分析socket这个结构体,这是整个的核心. 104 struct socket { 105 socket_state ...
- struct socket 结构详解
Socket数据结构网络协议CC++ 用户使用socket系统调用编写应用程序时,通过一个数字来表示一个socket,所有的操作都在该数字上进行,这个数字称为套接字描述符.在系统调用 的实现函 ...
- 海思uboot启动流程详细分析(三)【转】
1. 前言 书接上文(u-boot启动流程分析(二)_平台相关部分),本文介绍u-boot启动流程中和具体版型(board)有关的部分,也即board_init_f/board_init_r所代表的. ...
- 内核中container_of宏的详细分析【转】
转自:http://blog.chinaunix.net/uid-30254565-id-5637597.html 内核中container_of宏的详细分析 16年2月28日09:00:37 内核中 ...
- Linux内核TCP MSS机制详细分析
前言 上周Linux内核修复了4个CVE漏洞[1],其中的CVE-2019-11477感觉是一个很厉害的Dos漏洞,不过因为有其他事打断,所以进展的速度比较慢,这期间网上已经有相关的分析文章了.[2] ...
- PE头详细分析
目录 PE头详细分析 0x00 前言 0x01 PE文件介绍 0x02 PE头详细分析 DOS头解析 NT头解析 标准PE头解析 可选PE头解析 可选PE头结构 基址 代码段地址 数据段地址 OEP程 ...
- PE节表详细分析
目录 PE节表详细分析 0x00 前言 0x01 PE节表分析 节表结构 节表数量 节表名字 节表大小 节位置 节表属性 0x02 代码编写 PE节表详细分析 0x00 前言 上一篇文章我们学习了PE ...
- ZIP压缩算法详细分析及解压实例解释
最近自己实现了一个ZIP压缩数据的解压程序,觉得有必要把ZIP压缩格式进行一下详细总结,数据压缩是一门通信原理和计算机科学都会涉及到的学科,在通信原理中,一般称为信源编码,在计算机科学里,一般称为数据 ...
- 1125MySQL Sending data导致查询很慢的问题详细分析
-- 问题1 tablename使用主键索引反而比idx_ref_id慢的原因EXPLAIN SELECT SQL_NO_CACHE COUNT(id) FROM dbname.tbname FORC ...
随机推荐
- Docker下安装kafka
先看一下有哪些选择 额,没有官方的,但是可以根据stars来找一个,大多数人都选择第一个,我们看一下GitHub就知道了. 第一个:https://github.com/wurstmeister/ka ...
- SpringCloud 基础
目录 SpringCloud 基础 一.概述 二.服务发现组件 Eureka 1. 介绍 2. 搭建 Maven 父工程 3. 创建 Eureka 集群 4. 创建服务提供方集群 5. 创建服务消费方 ...
- @Valid参数验证 BindingResult result 的使用
1.首先导入依赖包bean-validator.jar2.在实体类上面写一些相关的验证信息:可以搜索更多的一些验证方式,这只是一部分 可以参考:点击打开链接http://blog.csdn.net/c ...
- Java的常用API之System类简介
Syetem类 java.lang.System类中提供了大量的静态方法,可以获取与系统相关的信息或系统级操作,在System类的API文档中,常用的方法有: public static long c ...
- Java的常用API之Date类简介
Data类 java.util.Date:表示日期和时间的类类Date 表示特定的瞬间,精确到毫秒.毫秒:千分之一秒 1000毫秒=1秒 把日期转换成毫秒: 当前的日期:2019-07-18 时间原点 ...
- 100道MySQL常见面试题总结
原文链接:https://juejin.im/post/5d351303f265da1bd30596f9 前言 本文主要受众为开发人员,所以不涉及到MySQL的服务部署等操作,且内容较多,大家准备好耐 ...
- @interface __ annotation 子类可以继承到父类上的注解吗--有结论了
博客分类: Java/J2se 作者:赵磊 博客:http://elf8848.iteye.com 不了解注解基础知识的请先看<JDK 5 Annotation\注解\注释\自定义注解> ...
- Net操作RabbitMQ
原文:Net操作RabbitMQ 文章目录 1 安装 2 管理界面 3 RabbitMQ的基本概念 4 RabbitMQ的六种工作模式 4.1 简单模式 4.2 工作模式 4.3 发布/订阅模式 4. ...
- python基础知识(一)
Python基础知识 计算基础知识 1.cpu 人类的大脑 运算和处理问题 2.内存 临时存储数据 断电就消失了 3.硬盘 永久存储数据 4.操作系统 调度硬件设备之间数据交互 python的应用和历 ...
- AMD规范中模块id的命名规则
AMD 即 Asynchronous Module Definition, 中文是“ 异步模块定义”的意思. AMD 规范制定了定义模块的规则,这样模块和模块的依赖可以被异步加载. AMD 规范只定义 ...