socket与sock的联系
套接字究竟是什么
如果你知道Linux系统中进程间通信的方式,就应该知道套接字也是其中一种。但套接字特别之处在于它不仅可以用来实现同一台主机上进程间的通信,还可以用来实现主机间的进程间的通信。通信的双方各自打开一个套接字,套接字之间通过通信链路相连。
如果把两个套接字之间的‘连接’比喻成‘水管’,那么套接字就是‘水龙头’
Unix有一句格言:everything is a file,即‘万物皆文件’,套接字也不例外。那么如何把套接字和文件联系起来呢? 答案就是通过下面这张图。
其中task_struct表示一个进程,files_struct中的fd_array[]表示该进程打开的所有描述符,对于套接字来说,与其他类型文件的区别就是最终f_op指向的是socket_file_ops。不过,可以看到,这里的socket_file_ops只有一些通用的操作,并没有send和recv。特有的操作通过 socketcall() 区分的。
socket 和 sock
终于到今天的主角了。实际上,对每一个新创建的套接字,内核协议栈都会创建struct socket和struct sock两个数据结构。这两个结构就像孪生兄弟,struct socket面向用户空间,struct sock面向内核空间。
struct socketstruct socket简化版的结构如下:
<net.h>
struct socket {unsigned long flags;const struct proto_ops *ops;struct file *file;struct sock *sk;short type;
};
其中type表示协议,这是在创建套接字的时候的protocol参数确定的
int socket(int domain, int type, int protocol);
1
file指针指向上面那张图中的struct file结构,通过它,socket便与文件系统关联了起来。
sk指向孪生的兄弟sock结构。
socket结构中最重要的要数ops指针了,根据协议类型,它指向一种特定协议的实现。比如TCP的就是inet_stream_ops,ICMP、UDP协议对应inet_dgram_ops,RAWIP对应的是inet_sockraw_ops同样地,这些也都在创建套接字的时候就决定了。
struct proto_ops的简化版本的结构如下
<net.h>
struct proto_ops{int family;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 (*accept)(struct socket *sock, struct socket *newsock, int flags);int (*sendmsg)(struct socket *sock, struct msghdr *m, size_t total_len);
}
其中的接口名字是不是很熟悉?是的,它们和进行网络编程时调用的C库中函数名字是一样的。以sendmsg为例,真实的调用过程是这样
即当用户调用sendmsg时,内核会找到描述符fd对应的struct socket结构,然后调用sock->ops->sendmsg执行特定协议的发送。
那么,ops字段什么时候被赋值呢?答案是,在创建struct sock结构前。
struct sock_common {struct proto *skc_prot;
};
struct sock {struct sock_common __sk_common;struct sk_buff_head sk_receive_queue;struct sk_buff_head sk_write_queue;
};
其中最重要的字段就是skc_prot,它也是协议相关的。作为struct socket结构的孪生兄弟,struct sock结构也是在用户创建套接字时就创建的。
sock_alloc创建了struct socket结构,随后,根据用户传入的family,查询数组net_families,找到对应的函数指针,调用create.
net_families保存着内核启动时注册(通过sock_register)的 socket protocol handler,比如以下几种:
static const struct net_proto_family inet_family_ops = {.family = PF_INET,.create = inet_create,.owner = THIS_MODULE,
};
static const struct net_proto_family netlink_family_ops = {.family = PF_NETLINK,.create = netlink_create,.owner = THIS_MODULE, /* for consistency 8) */
};
static const struct net_proto_family packet_family_ops = {.family = PF_PACKET,.create = packet_create,.owner = THIS_MODULE,
};
static const struct net_proto_family unix_family_ops = {.family = PF_UNIX,.create = unix_create,.owner = THIS_MODULE,,
};
如果我们创建套接字时指定的family是PF_INET,那么此时我们就会调用inet_create
static int inet_create(struct net *net, struct socket *sock, int protocol,int kern)
{struct sock *sk;struct inet_protosw *answer;list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {err = 0;/* Check the non-wild match. */if (protocol == answer->protocol) {if (protocol != IPPROTO_IP)break;} else {/* Check for the two wild cases. */if (IPPROTO_IP == protocol) {protocol = answer->protocol;break;}if (IPPROTO_IP == answer->protocol)break;}err = -EPROTONOSUPPORT;}sock->ops = answer->ops;sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern);if (sk->sk_prot->init) {err = sk->sk_prot->init(sk);}
}
首先是从inetsw数组搜索匹配对应的协议,inetsw称为协议开关表,内核启动时,通过inet_register_protosw进行注册。比如下面几项都会被注册
inetsw中注册的每种协议都有ops和prot两个字段,前者与struct socket结构关联到一起,后者与struct sock关联到一起。在inet_create中,struct socket的ops字段和struct sock的sk_prot字段被赋值。
以我们创建的套接字类型是TCP为例,此时struct socket和struct sock的关系如下:
还是继续刚才sendmsg的过程,由于struct socket的ops指向inet_stream_ops,所以实际调用的就是inet_sendmsg
https://blog.csdn.net/chenmo187J3X1/article/details/83902713
socket与sock的联系相关推荐
- 套接字的秘密—socket与sock
那么如何把套接字和文件联系起来呢? 答案就是通过下面这张图. 其中task_struct表示一个进程,files_struct中的fd_array[]表示该进程打开的所有描述符,对于套接字来说,与其他 ...
- 网络栈主要结构介绍(socket、sock、sk_buff,etc)
1.socket (include\linux\Socket.h)该结构体socket 主要使用在BSD socket 层,是最上层的结构,在INET socket 层也会有涉及,但很少. /** I ...
- 解决 ERROR 2002 (HY000) Can‘t connect to local MySQL server through socket ‘tmpmysql.sock‘
遇到的问题是这样的~ 本机环境~WSL+WIN10 WSL2~Fedora35 MySQL~8.0.27 遇到的问题~ 每次重启机器就会遇到下面这个问题--------->>>> ...
- ERROR 2002 (HY000) Can‘t connect to local MySQL server through socket ‘varrunmysqldmysqld.sock‘
今天执行mysql操作的时候出现了错误:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run ...
- 解决Can not connect to local MySQL server through socket tmpmysql.sock (2)
转载路径:https://blog.csdn.net/guanripeng/article/details/79626250 连接mysql报错: [root@iZwz9di9z56eqb94oj0a ...
- [Python_7] Python Socket 编程
0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*-"&qu ...
- python socket编程
python 编写server的步骤: 1.第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family参数 ...
- Python Socket编程基础篇
Socket网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...
- python 之socket 网络编程
socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. socket起源于Un ...
- python的socket编程_Python Socket编程详细介绍
在使用Python做socket编程时,由于需要使用阻塞(默认)的方式来读取数据流,此时对于数据的结束每次都需要自己处理,太麻烦.并且网上也没找到太好的封装,所以就自己写了个简单的封装. 封装思路 1 ...
最新文章
- 软件测试培训教程:pytest与unittest区别
- Unity用UGUI做虚拟摇杆
- SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因...
- make: Nothing to be done for `everything'.的原因
- leetcode——面试题 17.10. 主要元素
- 【mysql基础知识】解决java写入数据库时中文乱码的问题
- php父子遍历,jQuery 遍历
- Learning opencv续不足(七)线图像的设计D
- java之家_java
- andriod连接mysql测试_android开发 MyEclipse下测试连接MySQL数据库
- 去年的今天我们举行了婚礼
- 关于google拼音输入法的坑爹问题-IE浏览器浏览网页蓝屏等问题
- 大三暑假前端实习日志
- ubuntu安装搜狗拼音输入法及安装后没有中文解决办法
- 3年开发了5个私人项目:自动化办公、网站、机器人、小程序...免费开源,拿走不谢~
- 计算机硬件评分,用于电脑硬件性能参考的Win8.1系统体验评分找回方法
- 海驾学车过程全揭秘——第六篇:辛苦的学车全过程
- 51单片机硬件设计-最小系统(一)
- NXP MPC574x LinFlexd配置和DMA配置
- Witt向量简介 §1.1:环上赋值基础
热门文章
- 使用ajax请求下载excel文件
- 【目标检测】39、一文看懂计算机视觉中的数据增强
- 【面试】剑指OFFER
- 学豆网学计算机,出题优学生版电脑版
- 如何使用SPSS进行斯皮尔曼相关性分析
- IT美女放弃高薪工作的创业之路
- php合并播放mp4文件_视频音频的分离教程(支持多种格式视频音频合并为MP4) 可导入字幕...
- Vue router 默认加载 views 文件夹下全部vue文件
- Godot Shader特效:用SCREE_TEXTURE实现简单的屏幕滤镜
- windows聚焦壁纸不更新_如何解决Win10聚焦锁屏壁纸不自动更新的问题