趣谈 Linux 操作系统
刘超
前网易杭州研究院云计算技术部首席架构师
85459 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 72 讲
趣谈 Linux 操作系统
15
15
1.0x
00:00/00:00
登录|注册

44 | Socket内核数据结构:如何成立特大项目合作部?

UDP的实现
跟着代码走读
TCP的三次握手协议
系统调用规律
数据结构和流程
tcp_v4_connect
ops->connect
move_addr_to_kernel
sockfd_lookup_light
ops->accept
sock_alloc
sockfd_lookup_light
sys_accept4
ops->listen
somaxconn
sockfd_lookup_light
ops->bind
move_addr_to_kernel
sockfd_lookup_light
family、type、protocol
sock_create
family、type、protocol
sock_create
调用流程
内容:TCP和UDP场景下的调用流程、Socket系统调用、解析socket函数、解析bind函数、解析listen函数、解析accept函数、解析connect函数、总结时刻、课堂练习
主题:Socket系统调用规律
标题:一篇文章搞懂Socket系统调用规律
课堂练习
总结时刻
解析connect函数
解析accept函数
解析listen函数
解析bind函数
解析socket函数
Socket系统调用
参考文章
Socket系统调用规律
一篇文章搞懂Socket系统调用规律

该思维导图由 AI 生成,仅供参考

上一节我们讲了 Socket 在 TCP 和 UDP 场景下的调用流程。这一节,我们就沿着这个流程到内核里面一探究竟,看看在内核里面,都创建了哪些数据结构,做了哪些事情。

解析 socket 函数

我们从 Socket 系统调用开始。
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
int retval;
struct socket *sock;
int flags;
......
if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
retval = sock_create(family, type, protocol, &sock);
......
retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
......
return retval;
}
这里面的代码比较容易看懂,Socket 系统调用会调用 sock_create 创建一个 struct socket 结构,然后通过 sock_map_fd 和文件描述符对应起来。
在创建 Socket 的时候,有三个参数。
一个是 family,表示地址族。不是所有的 Socket 都要通过 IP 进行通信,还有其他的通信方式。例如,下面的定义中,domain sockets 就是通过本地文件进行通信的,不需要 IP 地址。只不过,通过 IP 地址只是最常用的模式,所以我们这里着重分析这种模式。
#define AF_UNIX 1/* Unix domain sockets */
#define AF_INET 2/* Internet IP Protocol */
第二个参数是 type,也即 Socket 的类型。类型是比较少的。
第三个参数是 protocol,是协议。协议数目是比较多的,也就是说,多个协议会属于同一种类型。
常用的 Socket 类型有三种,分别是 SOCK_STREAM、SOCK_DGRAM 和 SOCK_RAW。
enum sock_type {
SOCK_STREAM = 1,
SOCK_DGRAM = 2,
SOCK_RAW = 3,
......
}
SOCK_STREAM 是面向数据流的,协议 IPPROTO_TCP 属于这种类型。SOCK_DGRAM 是面向数据报的,协议 IPPROTO_UDP 属于这种类型。如果在内核里面看的话,IPPROTO_ICMP 也属于这种类型。SOCK_RAW 是原始的 IP 包,IPPROTO_IP 属于这种类型。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入剖析了Socket系统调用的内部实现细节,包括创建Socket、监听和接受连接的过程。通过介绍Socket系统调用的代码实现和相关参数含义,详细讲解了创建Socket时涉及的地址族、类型和协议,以及对应的数据结构和初始化过程。特别关注了SOCK_STREAM类型和IPPROTO_TCP协议的创建过程,以及在内核中对应的数据结构和函数调用。此外,还介绍了bind、listen和accept等函数的实现细节,包括在内核中的具体调用过程和相关数据结构的操作。通过对关键代码的解析,读者可以深入了解Socket系统调用的内部实现细节,包括TCP连接的建立和监听过程。总体而言,本文对Socket系统调用的内部工作原理进行了深入剖析,为读者提供了深入理解网络编程底层原理的重要参考资料。对于对网络编程底层原理感兴趣的读者来说,本文是一份重要的参考资料。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《趣谈 Linux 操作系统》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(12)

  • 最新
  • 精选
  • 莫名
    看了一遍,然后花了一天把源码又过了一遍,很有收货,对socket的理解不再浮于表面。

    作者回复: 赞

    2019-08-09
    13
  • kkxue
    原来得先看总结图,再看内容。。

    作者回复: 对的,这是一个好方法

    2019-07-14
    5
  • W.jyao
    老师,能解释下listenfd和acceptfd的端口为什么一样吗?

    作者回复: 一个服务端口当然一样呀。只不过两个socket数据结构而已

    2019-07-08
    3
  • 无心之福
    开头的那个代码的 逗号加的不对吧?

    作者回复: 对的,看一下SYSCALL_DEFINE3这个宏的定义就理解了

    2019-08-19
    2
    1
  • book尾汁
    调用accept的时候,会新建一个socket,以及其对应的struct file,然后会从icsk_accept_queue 取出一个req,将其sk赋值给新建的socket->sk,这样就可以读取到请求的数据了,不理解的是后面讲到接收数据包时tcp层有三个队列,会根据内核低延时 高吞吐量的等策略以及socket当时的状态来决定放入哪个队列,这里的socket是怎么选出来的啊,数据包是先发送到处于监听队列的socket然后由其将数据分发到其通过accept生成的sokcet上吗,如果是直接由通过accept生成的socket来处理,怎么分辨出来到底该给哪个socket呢,根据数据包的源地址与端口吗?

    作者回复: 监听的端口号

    2020-05-03
    2
  • 飞翔
    syn到底是个什么东西呀?是个integer还是char类型

    作者回复: 详见网络包的格式,TCP头里面有syn

    2019-07-08
    3
  • 二星球
    老师好,同一个TCP链接上先后发送2次rpc请求,后发送的请求其结果先返回,先发送的请求结果后返回,这样有没有问题呢,系统能区分各自的返回结果么,靠什么机制保证的呢?一直没有想明白

    作者回复: RPC是应用层的,需要应用层自己保证请求和结果的对应。

    2019-07-08
    2
  • 奔跑的码仔
    struct tcp_sock继承自struct inet_connection_sock inet_conn,inet_connection_sock继承自struct inet_sock,struct inet_sock继承自struct sock; 1.上述四个结构的关系具有十足的面向对象的特征,struct是基类,通过层层继承,实现了类的复用; 2.内核中网络相关的很多函数,参数往往都是struct sock,函数内部依照不同的业务逻辑,将struct sock转换为不同的业务结构; 这样做的好处: 1.简化接口的设计复杂度; 2.使用基类作为参数,十分类似于面向对象中的多态特性,能够有效的增强接口的稳定性、提升扩展性。
    2019-10-11
    15
  • 谛听
    socket: 根据参数创建相应socket bind: 绑定IP、端口 listen: 建立两个队列,改变状态为TCP_LISTEN accept: 从完成三次握手的队列中取出一个socket,没有的话让出cpu connect: 三次握手
    2019-11-24
    6
  • Geek_ty
    老师您好,我在认真阅读了文章和代码后还是存在一个疑惑:icsk_accept_queue是全连接队列当然没有问题,但是服务端LISTEN状态下,调用tcp_v4_conn_request()时inet_csk_reqsk_queue_hash_add()函数也是增加了该队列的长度。但是实际上应该修改的时半连接队列才对。我反复看了几遍源码,没有发现在什么地方有保存syn队列,也没有syn队列的相关操作,都是对icsk_accept_queue的操作,这让我十分困惑,还请老师帮忙解答。
    2020-08-08
    1
收起评论
显示
设置
留言
12
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部