socket()
内核版本:3.10.0-514.16.1.el7.x86_64
1 |
|
(1).接口说明:
按照顺序可传入如下参数:
- PF_INEAT
- SOCK_STREAM,SOCK_DGRAM,SOCK_RAW
- IPPROTO_TCP,IPPROTO_UDP,IPPROTO_IP
返回值说明
- EAFNOSUPPORT 不支持地址类型
- EMFILE 进程文件表溢出
- ENFILE 核心内存不足无法建立新的socket
- EINVAL 参数domain/type/protocol不合法
- EACCES 权限不允许
- ENOBUFS/ENOMEM 内存不足
- EPROTONOSUPPORT domain指定的类型不支持参数type或者protocol
(2).内核调用栈
(3).结构体说明
struct socket
面向用户态的结构体
基于虚拟文件系统创建
创建socket时最先创建的结构体
struct sock
网络层socket
struct inet_sock
INET域socket表示
提供INET域的一些属性,TTL、 组播、 地址 、端口
struct raw_socket、struct udp—sock、 struct inet_connection_sock
是对struct inet_sock的扩展
struct raw_socket要处理ICMP
struct udp_sock udp协议socket
struct inet_connection_sock面向连接socket
struct tcp_sock TCP协议socket ,对inet_connection_sock扩展,增加了滑动窗口等拥塞控制属性
struct inet_timewait_sock网络层超时控制使用
struct tcp_timewait_sock TCP协议超时控制使用
(4).struct socket创建源码分析
(4.1).sock_alloc函数
1 | static struct socket *sock_alloc(void) |
- 一起申请两块内存struct socket和struct inode
- 两块内存用struct socket_alloc联系起来
- inode是linux用来刻画一个存放在内存中的文件的
- socket是一种网络文件类型,可以通过文件描述符使用read和write等文件操作函数操作socket
- 有了inode就支持了虚拟文件系统的操作
(4.2).sock_alloc->new_inode_pseudo->alloc_inode
1 | struct inode *new_inode_pseudo(struct super_block *sb) |
- alloc_inode获取内存有两种方式 1.通过自己alloc_inode分配 2.从高速缓存中分配
(4.3).alloc_inode -> sock_alloc_inode
1 | static struct inode *sock_alloc_inode(struct super_block *sb) |
- socket结构体最终会调用上述函数申请内存
- 该函数会在sock_init中被注册和挂载到系统上
(4.4).sock_init 中sock_allok_inode挂载过程
1 | err = register_filesystem(&sock_fs_type); |
- sock_init -> register mount -> sock_fs_type->sockfs_mount->sockfs_ops->sock_alloc_node
(4.5).pf->create 即TCP/IP协议族的创建函数inet_create初始化步骤
(4.5.1).PF_INET协议族的create函数inet_create会被组册
1 | (void)sock_register(&inet_family_ops); |
(4.5.2).注册过程
1 | int sock_register(const struct net_proto_family *ops) |
- 协议族选项ops会根基协议族类型PF_INET被放置到net_families系统全局变量中
(4.5.3).__sock_create使用过程
1 | socket.c/__sock_create |
- 根据socket传输过来的协议族PF_INET查找全局变量net_families获取ops
- 通过ops->create调用inet_create根据具体协议创建网络层socket struct sock
(4.6).inet_create都干了什么?
1 | static int inet_create(struct net *net, struct socket *sock, int protocol, |
- 设置socket状态SS_UNCONNECTED
- 根据协议类型找到具体的协议类型操作集合,例如协议处理函数tcp_proc和inet层处理函数集合inet_stream_ops
- socket->ops 获得协议操作集合inet_stream_ops
- 申请sock,并把tcp_proc赋值给它 sk->sk_prot = sk->sk_prot_creator=tcp_proc
- 把申请的sock和inet_sock进行初始化
- sk->sk_prot->init(sk) 调用tcp_proc深度初始化TCP相关信息
尽管流程主要干了上述的事情,仍需要深入探究的问题是:
a. inet_protosw inet_protosw初始化过程如何?
b. inet_sock和sock是什么关系?
c. 从inet_protosw获取的prot和ops哪些结构体上会记录使用?
(4.6.1).inet_protosw初始化过程如何?
1 | static struct inet_protosw inetsw_array[] = |
- inet_init 会把inet_protosw方式inet_sw中
- inet_protosw很重要,其含有协议的具体操作函数tcp_close,tcp_v4_connect,tcp_recvmsg等
- inet_protosw,内还包含inet层操作函数 inet_bind,inet_accept,inet_bind,inet_listen等
(4.6.2). inet_sock和sock是什么关系?
1 | struct sock *sk_alloc(struct net *net, int family, gfp_t priority, |
从上述sk_alloc -> sk_prot_alloc -> obj_size
1 | struct proto tcp_prot = { |
- struct tcp_sock 包含strcut inet_sock 包含 struct sock
- 上述结构体为互相包含的关系
- 实际上在申请sock时候,申请内存大小为tcp_sock大小,也就是说三个结构体共同诞生了
(4.6.3). 从inet_protosw获取的prot和ops哪些结构体上会记录使用?
struct socket会在inet_create函数中获取到ops
sock->ops = answer->ops;
struct sock在sk_allloc函数中获取pro
sk->sk_prot = sk->sk_prot_creator = prot;
(5).socket与文件系统
socket与文件系统关联通过sock_map_fd完成
其步骤如下:
1:获取fd get_unused_fd_flags
该函数从当前进程管理的files获取可用的fd
2:申请file sock_alloc_file
将struct socket放到file的private_data管理 file->private_data = sock
3:将file根据当前fd安装到current->files中
files有一个指针fdt
fdt->fd是一个类型为file指针的数组,数组下标为fd
rcu_assign_pointer(fdt->fd[fd], file); 将file安装fd为数组下标放到current->files管理