TCP/IP协议栈在Linux内核中的运行时序分析

调研要求

  1. 在深入理解Linux内核任务调度(中断处理、softirg、tasklet、wq、内核线程等)机制的基础上,分析梳理send和recv过程中TCP/IP协议栈相关的运行任务实体及相互协作的时序分析。

  2. 编译、部署、运行、测评、原理、源代码分析、跟踪调试等

  3. 应该包括时序图

1. TCP/IP协议栈总览

1.1 网络架构

Linux网络协议栈的架构如下图所示。该图展示了如何实现Internet模型,在最上面的是用户空

间中实现的应用层,而中间为内核空间中实现的网络子系统,底部为物理设备,提供了对网络

的连接能力。在网络协议栈内部流动的是套接口缓冲区(SKB),用于在协议栈的底层、上层以

及应用层之间传递报文数据。

网络协议栈顶部是系统调用接口,为用户空间中的应用程序提供一种访问内核网络子系统的接

口。下面是一个协议无关层,它提供了一种通用方法来使用传输层协议。然后是传输层的具体

协议,包括TCP、UDP。在传输层下面是网络层,之后是邻居子系统,再下面是网络设备接

口,提供了与各个设备驱动通信的通用接口。最底层是设备驱动程序。

1.2 系统调用接口:从两个角度进行描述:

(1)当用户进行网络调用时,通过系统调用接口多路复用到内核中。这最终作为 sys_socketcall(./net/socket.c)中的调用,然后进一步解复用到其预期目标的调用。

(2)使用正常的文件操作进行网络I/O。例如,典型的读写操作可以在网络socket(由文件描述符表示,就像普通文件)一样执行。因此,虽然存在一些特定于网络的操作(调用socket创建socket,调用connect将socket连接到目的地等等),但还是有一些适用于网络对象的标准文件操作,就像常规文件一样。最后系统调用接口提供了在用户空间应用程序和内核之间传输控制的手段。

协议无关接口:socket层是协议无关接口,其提供一组通用功能,以支持各种不同的协议。socket层不仅支持典型的TCP和UDP协议,还支持IP,原始以太网和其他传输协议,如流控制传输协议(SCTP)。

网络协议:网络协议部分定义了可用的特定网络协议(如TCP,UDP等)。

设备无关接口:协议层下面是另一个无关的接口层,将协议连接到具有不同功能的各种硬件设备的驱动程序。该层提供了一组通用的功能,由较低级别的网络设备驱动程序使用,以允许它们使用较高级协议栈进行操作。

设备驱动程序:网络栈的底部是管理物理网络设备的设备驱动程序。该层的设备示例包括串行接口上的SLIP驱动程序或以太网设备上的以太网驱动程序。

2. Socket简介

Linux中使用socket结构描述套接口,代表一条通信链路的一端,用来存储与该链路有关的所使用的协议的状态信息(包括源地址和目标地址),到达的连接队列

数据缓存和可选标志等等

使用socket结构描述套接口示意图如下所示:

其中最关键的成员是sk和ops,sk指向与该套接口相关的传输控制块,ops指向特定的传输协

议的操作集。

下图详细展示了socket结构体中的sk和ops字段,以TCP为例:

常见API

  • socket()

    • 原型:int socket (int domain, int type, int protocol)

    • 功能描述:初始化创建socket对象,通常是第一个调用的socket函数。 成功时,返回非负数的socket描述符;失败是返回-1。socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用socket()函数时,socket执行体将建立一个socket,为一个socket数据结构分配存储空间。

  • bind()

    • 原型:int bind(int sockfd, const struct sockaddr* myaddr, socklen_t addrlen)

    • 功能描述:将创建的socket绑定到指定的IP地址和端口上,通常是第二个调用的socket函数。返回值:0代表成功,-1代表出错。当socket函数返回一个描述符时,只是存在于其协议族的空间中,并没有分配一个具体的协议地址(这里指IPv4/IPv6和端口号的组合),bind函数可以将一组固定的地址绑定到sockfd上。通常服务器在启动的时候都会绑定一个众所周知的协议地址,用于提供服务,客户就可以通过它来接连服务器;而客户端可以指定IP或端口也可以都不指定,未分配则系统自动分配。

  • listen()

    • 原型:int listen(int sockfd, int backlog)

    • 功能描述:listen()函数仅被TCP类型的服务器程序调用,实现监听服务。当socket()创建socket时,被假设为主动式套接字,也就是说它是一个将调用connect()发起连接请求的客户端套接字;函数listen()将套接口转换为被动式套接字,指示内核接受向此套接字的连接请求,调用此系统调用后tcp 状态机由close转换到listen。

  • accept()

    • 原型: int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen)

    • 功能描述:accept()函数仅被TCP类型的服务器程序调用,从已完成连接队列返回下一个建立成功的连接,如果已完成连接队列为空,线程进入阻塞态睡眠状态。成功时返回套接字描述符,错误时返回-1。如果accpet()执行成功,返回由内核自动生成的一个全新socket描述符,用它引用与客户端的TCP连接。通常我们把accept()第一个参数成为监听套接字,把accept()功能返回值成为已连接套接字。

  • connect()

    • 原型: int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)

    • 功能描述:connect()通常由TCP类型客户端调用,用来与服务器建立一个TCP连接,实际是发起3次握手过程,连接成功返回0,连接失败返回1。

  • send()

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值