套接口学习(一)实现
套接口这个概念最先由4.2BSD(1983)引入。如今已经成为一个通用的网络应用程序编程接口。受到全部操作系统的支持。套接口层位于应用程序和 协议栈之间,相应用程序屏蔽了与协议相关实现的详细细节。
通常,应用程序中调用库函数。而库函数通过系统调用进入套接口层,Linux的套接口层实现提供了一组专门的套接口系统调用。分别在相应的库函数名之上加上"sys_"前缀。此外为了体现一切皆文件的理念。Linux也同意标准I/O系统调用通过一个套接口文件描写叙述符来读写其相应套接口上的网络连接。就像通过文件描写叙述符訪问一个已经打开的普通文件一样。
套接口在创建时。即与一个文件及一个文件描写叙述符绑定,此后全部对该套接口的操作都是通过与其绑定的文件描写叙述符进行的,包含专门的套接口系统调用。页包含标准的I/O系统调用对套接口的操作,与套接口绑定的文件类型为套接口文件。
套接口层的调用涉及下面文件:
include/linux/net.h 定义套接口层相关的结构、宏和函数原型
include/net/sock.h 定义主要的传输控制块结构、宏和函数原型
net/socket.c 实现套接口层的系统调用
net/ipv4/af_inet.c 网络层和传输层接口
socket结构
struct socket {socket_state state;kmemcheck_bitfield_begin(type);short type;kmemcheck_bitfield_end(type);unsigned long flags;/** Please keep fasync_list & wait fields in the same cache line*/struct fasync_struct *fasync_list;wait_queue_head_t wait;struct file *file;struct sock *sk;const struct proto_ops *ops;
};
state
用于表示所在套接口所处的状态标志。该标志有些状态仅仅对TCP套接口有意义,由于仅仅有TCP是面向连接的协议
typedef enum {
SS_FREE = 0, /* not allocated */
SS_UNCONNECTED, /* unconnected to any socket */
SS_CONNECTING, /* in process of connecting */
SS_CONNECTED, /* connected to socket */
SS_DISCONNECTING /* in process of disconnecting */
} socket_state;
type
套接口类型
enum sock_type {
SOCK_STREAM = 1, 基于连接的套接口
SOCK_DGRAM = 2, 基于数据报的套接口
SOCK_RAW = 3, 原始套接口
SOCK_RDM = 4, 可靠传送报文套接口
SOCK_SEQPACKET = 5, 顺序分组套接口
SOCK_DCCP = 6, 数据报拥塞控制协议套接口
SOCK_PACKET = 10,混杂模式套接口
};
flags
一组标志位
#define SOCK_ASYNC_NOSPACE 0 该套接口发送队列是否已满
#define SOCK_ASYNC_WAITDATA 1 应用程序通过recv调用时。是否在等待数据的接收
#define SOCK_NOSPACE 2 非异步情况下该套接口的发送队列是否已满
#define SOCK_PASSCRED 3 是否设置了SOCK_PASSCRED选项
#define SOCK_PASSSEC 4 是否设置了SOCK_PASSSEC
struct fasync_struct *fasync_list
存在了异步通知的队列
wait_queue_head_t wait
等待该套接口的进程队列
struct file *file
指向了与该套接口绑定的file结构的指针
struct sock *sk;
与该套接口关联的传输控制块
const struct proto_ops *ops;
用来将套接口层的系统调用映射到对应传输层协议实现
PF_INET协议族定义了三种prote_ops结构实例
TCP inet_stream_ops
UDP inet_dgram_ops
RAW inet_sockraw_ops
proto_ops结构
整个proto_ops结构能够看作是一张套接口系统调用到传输层函数的跳转表,当中的某些操作会继续通过proto结构跳转表,进入详细的传输层或网络层的处理。
既然proto_ops结构完毕的是从与协议无关的套接口层到协议相关的传输层的转接,而proto结构又将传输层映射到网络层,那么可想而知每一个传输层的协议都须要定义一个特定的proto_ops实例和proto实例。在ipv4协议族中,一个传输层协议相应一个inet_protosw结构,inet_protosw结构包括了proto_ops结构和proto结构。
套接口文件系统
每一种文件都有各自的文件类型,如设备文件包含字符设备和块设备文件等。而与套接口关联的文件类型为套接口文件。
套接口文件系统类型
为了能使套接口与文件描写叙述符关联,并支持特殊套接口层的i节点的分配和释放,系统中添加了sockfs文件系统sock_fs_type,通过sockfs文件系统的getsb接口和超级块操作集合中的alloc_inode和destroy_inode,能够分配和释放与套接口文件相关的i节点。能够通过/proc/filesystems文件查看操作系统支持的文件系统。
static const struct super_operations sockfs_ops = {.alloc_inode = sock_alloc_inode,.destroy_inode =sock_destroy_inode,.statfs = simple_statfs,
};static int sockfs_get_sb(struct file_system_type *fs_type,int flags, const char *dev_name, void *data,struct vfsmount *mnt)
{return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC,mnt);
}static struct vfsmount *sock_mnt __read_mostly;static struct file_system_type sock_fs_type = {.name = "sockfs",.get_sb = sockfs_get_sb,.kill_sb = kill_anon_super,
};
套接口文件的inode
套接口文件系统的i节点和套接口是一一相应的,因此套接口文件系统的i节点的分配时比較特殊的。分配的并非一个单纯的i节点。而是i节点和socket结构的组合体,即socket_alloc结构。这样能够使套接口的分配及与之绑定的套接口文件i节点的分配同一时候进行。在应用层訪问套接口要通过文件描写叙述符,这样能够高速通过文件描写叙述符定位与之绑定的套接口。
struct socket_alloc {struct socket socket;struct inode vfs_inode;
};
static struct inode *sock_alloc_inode(struct super_block *sb)
{struct socket_alloc *ei;ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);if (!ei)return NULL;init_waitqueue_head(&ei->socket.wait);ei->socket.fasync_list = NULL;ei->socket.state = SS_UNCONNECTED;ei->socket.flags = 0;ei->socket.ops = NULL;ei->socket.sk = NULL;ei->socket.file = NULL;return &ei->vfs_inode;
}static void sock_destroy_inode(struct inode *inode)
{kmem_cache_free(sock_inode_cachep,container_of(inode, struct socket_alloc, vfs_inode));
}
套接口文件
套接口有一套独立的系统调用。包含建立套接口、连接和IO操作等,因为在建立套接口后返回的是文件描写叙述符,因此也能够通过标准的文件IO操作进行对套接口的读写,比如用send()进行数据的发送,而其实也能够通过write系统调用而达到相同的效果。这是因为在创建套接口文件时,使file结构中的f_op指向了socket_file_ops。
通过socket_file_ops。能够看到套接口文件支持那些系统调用
static const struct file_operations socket_file_ops = {.owner = THIS_MODULE,.llseek = no_llseek,.aio_read = sock_aio_read,.aio_write = sock_aio_write,.poll = sock_poll,.unlocked_ioctl = sock_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl = compat_sock_ioctl,
#endif.mmap = sock_mmap,.open = sock_no_open, /* special open code to disallow open via /proc */.release = sock_close,.fasync = sock_fasync,.sendpage = sock_sendpage,.splice_write = generic_splice_sendpage,.splice_read = sock_splice_read,
};
套接口文件与套接口的绑定
应用层是通过文件描写叙述符来訪问套接口的。因此在调用socket系统调用创建套接口时。在创建后会调用sock_map_fd()绑定套接口和文件描写叙述符
static int sock_attach_fd(struct socket *sock, struct file *file, int flags)
{struct dentry *dentry;struct qstr name = { .name = "" };dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);if (unlikely(!dentry))return -ENOMEM;dentry->d_op = &sockfs_dentry_operations;/** We dont want to push this dentry into global dentry hash table.* We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED* This permits a working /proc/$pid/fd/XXX on sockets*/dentry->d_flags &= ~DCACHE_UNHASHED;d_instantiate(dentry, SOCK_INODE(sock));sock->file = file;init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE,&socket_file_ops);SOCK_INODE(sock)->i_fop = &socket_file_ops;file->f_flags = O_RDWR | (flags & O_NONBLOCK);file->f_pos = 0;file->private_data = sock;return 0;
}int sock_map_fd(struct socket *sock, int flags)
{struct file *newfile;int fd = sock_alloc_fd(&newfile, flags);if (likely(fd >= 0)) {int err = sock_attach_fd(sock, newfile, flags);if (unlikely(err < 0)) {put_filp(newfile);put_unused_fd(fd);return err;}fd_install(fd, newfile);}return fd;
}
进程、文件描写叙述符和套接口
在task_struct结构中,files指向file_struct结构,该结构的主要功能是管理fd_array指针数组指向的描写叙述符,每个file结构描写叙述一个打开的文件。
套接口层的初始化
static int __init sock_init(void)
{/** Initialize sock SLAB cache.*/sk_init();/** Initialize skbuff SLAB cache*/skb_init();/** Initialize the protocols module.*/init_inodecache();register_filesystem(&sock_fs_type);sock_mnt = kern_mount(&sock_fs_type);/* The real protocol initialization is performed in later initcalls.*/#ifdef CONFIG_NETFILTERnetfilter_init();
#endifreturn 0;
}
转载于:https://www.cnblogs.com/lxjshuju/p/6953033.html
套接口学习(一)实现相关推荐
- 网络编程学习笔记(套接口超时)
有三种方法给套接口上的I/O操作设置 超时: 1.调用 alarm,在到达指定时间 时产生 SIGALRM信号,可能与进程中其他已有的alarm调用 冲突 2.使用select阻塞在等待I/O上,se ...
- 网络编程学习笔记(TCP套接口选项)
其套接口级别为IPPROTO_TCP TCP_KEEPALIVE: 指定TCP开始发送保持存活探测分节前以秒为单位的连接空闲时间.此选项在SO_KEEPALIVE套接口选项打开时才有效 TCP_MAX ...
- 网络编程学习笔记(ICMPv6和IPv6套接口选项)
ICMPv6套接口选项级别为IPPROTO_ICMPV6 ICMP6_FILTER: 获取和设置一个icmp6_filter结构,这指明256个可能的ICMPv6消息类型中哪一个传递给在原始套接口上的 ...
- 网络编程学习笔记(IPv4套接口选项)
这些选项级别为IPPROTO_IP IP_HDRINCL: 如果此选项给一个原始IP套接口,必须为所有发判定以此原始套接口上的数据报构造自己的IP头部.一般情况下,内核为发送到原始套接口上的数据报构造 ...
- 网络编程学习笔记(基本套接口选项)
SO_BROADCAST套接口选项: 此选项使能或禁止进程发送广播消息的能力.只有数据报套接口支持广播,并且还必须是在支持广播消息的网络上(例如以太网.令牌网).不能在一个点对点链路上进行广播. SO ...
- Linux Socket学习--套接口的类型和协议
我们首先来说一下PF_INET和AF_INET,虽然标准提倡在指定demain参数的时候,优先使用PF_INET,但是大量已经编写的c代码遵循旧的协议.目前情况是AF_UNIX=PF_UNIX,AF_ ...
- Linux Socket学习--为套接口绑定地址
当我们使用socket函数创建一个套接口之后,这个套接口就处于无名状态,虽然之前我们提到即使没有地址,套接口也能使用,但是这个只限于套接口对在同一个Linux内核中,如果位于两台不同的主机的套接口需要 ...
- 【学习总结】-Apsara Clouder专项技能认证:实现调用API接口学习总结
Apsara Clouder专项技能认证:实现调用API接口-学习总结 API的概念: API的特点: API的分类: 为什么要使用API 阿里云API市场 API请求与认证 Web API协议 HT ...
- 阿里云Apsara Clouder专项技能认证-实现调用API接口-学习笔记
Apsara Clouder专项技能认证-实现调用API接口-学习笔记 阿里云的一个小认证,闲来无事,考一下 一.API简介 API的概念 API(Application Programming In ...
最新文章
- IOS UIScrollView (转)
- java面试题 并发_Java 并发面试题(一)
- 安卓App的启动过程、安卓布局分类及布局和页面的关系
- 从Linus Torvalds一封发飙的电邮开始谈设备树究竟是棵什么树?
- 大佬是如何实现本地通讯的?
- 使用jsp:include嵌入页面的两种方式
- activiti processEngineLifecycleListener使用
- 感受McAfee.Secure.Internet.Gateway
- macos下刻录系统盘
- 顺着IP地址他们能找到我家吗?
- Android ListView优化总结
- python判断素数的函数_python判断是否为素数
- 关于延拓定理的一点注解
- html语言实现两数相加,HTML(2)
- 后端程序员必会:并发情况下redis-lua保证原子操作
- 解压jar包修改配置文件,解压、修改、压缩、运行
- Jmeter解决上传附件中文名乱码问题
- mos管的rc吸收电路计算_RC吸收计算应用
- cmake中如何添加fPIC编译选项
- Kubesphere流水线集成(Git、Maven、Docker、K8S)
热门文章
- xMedia来了!支付宝客户端的智能化“武器”
- android 恢复出厂设置 时间,Android 恢复出厂设置后,时间不能恢复为:2013年1月1日...
- 游戏角色口型老是对不上?这里有一个高效解决方案
- eclipse是否免费
- mysql如何获取当前时间
- 如何使用logminer查看日志内容
- RMAN的一些术语解释
- 在11g中alter system set recyclebin = off 报错 recyclebin 参数在11g和10g中的区别
- 小程序直播间报错:{“errmsg“:“the current room status does not allow this operation rid:“,“errcode“:300023}
- 软件稳定性测试的测试点