0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

讲一下TCP底层的收发过程

冬至子 来源:周末程序猿 作者:周末程序猿 2023-08-01 17:24 次阅读

我们继续探索高性能网络编程,但是我觉得在谈系统API之前可以先讲一些Linux底层的收发包过程,如下这是一个简单的socket编程代码:

int main() {
    ... 

    fd = socket(AF_INET, SOCKET_STREAM, 0);
    bind(fd, ...);
    listen(fd, ...);

    // 如何建立连接
    ...
    afd = accept(fd, ...);

    // 如何接收数据
    ...
    read(afd, ...);

    // 如何发送数据
    ...
    send(afd, ...);

    // 如何关闭连接
    ...
    close(fd);
    ...
}

第一部分:如何建立连接

图片

从上一篇文章我们介绍了网络协议,我们知道TCP/IP协议族划分了应用层、TCP传输层、IP网络层、链路层(以太层驱动)。

如上图看应用层,通常在网络编程中我们需要调用accept的API建立TCP连接,那TCP如何做的呢?

图片

从上图的流程可以看到:
(1)client端发起TCP握手,发送syn包;
(2)内核收到包以后先将当前连接的信息插入到网络的SYN队列;
(3)插入成功后会返回握手确认(SYN+ACK);
(4)client端如果继续完成TCP握手,回复ACK确认;
(5)内核会将TCP握手完成的包,先将对应的连接信息从SYN队列取出;
(6)将连接信息丢入到ACCEPT队列;
(7)应用层sever通过系统调用accept就能拿到这个连接,整个网络套接字连接完成;

那基于这个图,我想问问读者这里会有什么问题么?
细心的读者应该可以看出:
1、这里有两个队列,必然会有满的情况,那如果遇到这种情况内核是怎么处理的呢?

(1)如果SYN队列满了,内核就会丢弃连接;
(2)如果ACCEPT队列满了,那内核不会继续将SYN队列的连接丢到ACCEPT队列,如果SYN队列足够大,client端后续收发包就会超时;
(3)如果SYN队列满了,就会和(1)一样丢弃连接;

2、如何控制SYN队列和ACCEPT队列的大小?

(1)内核2.2版本之前通过listen的backlog可以设置SYN队列(半连接状态SYN_REVD)和ACCEPT队列(完全连接状态ESTABLISHED)的上限;
(2)内核2.2版本以后backlog只是表示ACCEPT队列上限,SYN队列的上限可以通过/proc/sys/net/ipv4/tcp_max_syn_backlog设置;

3、server端通过accept一直等,岂不是会卡住收包的线程?

在linux网络编程中我们都会追求高性能,accept如果卡住接收线程,性能会上不去,所以socket编程中就会有阻塞和非阻塞模式。
(1)阻塞模式下的accept就会卡住,当前线程什么事情都干不了;
(2)非阻塞模式下,可以通过轮询accept去处理其他的事情,如果返回EAGAIN,就是ACCEPT队列为空,如果返回连接信息,就是可以处理当前连接;

第二部分:接收数据

图片

(1)当网卡接收到报文并判断为TCP协议后,将会调用到内核的tcp_v4_rcv方法,如果数据按顺序收到S1数据包,则直接插入receive队列中;
(2)当收到了S3数据包,在第1步结束后,应该收到S2序号,但是报文是乱序进来的,则将S3插入out_of_order队列(这个队列存储乱序报文);
(3)接下来收到S2数据包,如第1步直接进入receive队列,由于此时out_of_order队列不像第1步是空的,所以引发了接来的第4步;
(4)每次向receive队列插入报文时都会检查out_of_order队列,如果遇到期待的序号S3,则从out_of_order队列摘除,写入到receive队列;
(5)现在应用程序开始调用recv方法;
(6)经过层层封装调用,接收TCP消息最终会走到tcp_recvmsg方法;
(7)现在需要拷贝数据从内核态到用户态,如果receive队列为空,会先检查SO_RCVLOWAT这个阀值(0表示收到指定的数据返回,1表示只要读取到数据就返回,系统默认是1),如果已经拷贝的字节数到现在还小于它,那么可能导致进程会休眠,等待拷贝更多的数据;
(8)将数据从内核态拷贝到用户态,recv返回拷贝数据的大小;
(9)为了选择降低网络包延时或者提升吞吐量,系统提供了tcp_low_latency参数,如果为0值,用户暂时没有读数据则数据包进入prequeue队列,提升吞吐量,否则不使用prequeue队列,进入tcp_v4_do_rcv,降低延时;

第三部分:发送数据

图片

(1)假设调用send方法来发送大于一个MSS(比如2K)的数据;
(2)内核调用tcp_sendmsg,实现复制数据,写入队列和组装tcp协议头;
(3)在调用tcp_sendmsg先需要在内核获取skb,将用户态数据拷贝到内核态,内核真正执行报文的发送,与send方法的调用并不是同步的,即send方法返回成功,也不一定把IP报文都发送到网络中了。因此,需要把用户需要发送的用户态内存中的数据,拷贝到内核态内存中,不依赖于用户态内存,也使得进程可以快速释放发送数据占用的用户态内存。但这个拷贝操作并不是简单的复制,而是把待发送数据,按照MSS来划分成多个尽量达到MSS大小的分片报文段,复制到内核中的sk_buff结构来存放;
(4)将数据拷贝到发送队列中tcp_write_queue
(5)调用tcp_push发送数据到IP层,这里主要滑动窗口,慢启动,拥塞窗口的控制和判断是否使用Nagle算法合并小报文(上一篇已经有介绍);
(6)组装IP报文头,通过经过iptables或者tcpdump等netfilter模块过滤,将数据交给邻居子系统(主要功能是查找需要发送的MAC地址,发送arp请求,封装MAC头等);
(7)调用网卡驱动程序将数据发送出去;

第四部分:关闭连接

关闭连接就是TCP挥手过程,我们都知道TCP连接是一种可靠的连接,那如何才能完整可靠的完成关闭连接呢?linux系统提供了两个函数:

  • close对应tcp_close方法,通过减少socket的引用次数实现关闭,仅当引用计数为0时才会触发tcp_close;
    图片
  • shutdown对应tcp_shutdown方法,不关心socket被引用次数,直接关闭对应的连接;
    图片

(1)shutdown可携带一个参数,取值有3个,分别意味着:只关闭读、只关闭写、同时关闭读写;

(2)若shutdown的是半打开的连接,则发出RST来关闭连接;
(3)若shutdown的是正常连接,那么关闭读其实与对端是没有关系的;
(4)若参数中有标志位为关闭写,那么下面做的事与close是一致的,发出FIN包,告诉对方本机不会再发消息了;

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 驱动器
    +关注

    关注

    52

    文章

    8090

    浏览量

    145782
  • 连接器
    +关注

    关注

    98

    文章

    14204

    浏览量

    135882
  • Linux系统
    +关注

    关注

    4

    文章

    590

    浏览量

    27307
  • RST
    RST
    +关注

    关注

    0

    文章

    31

    浏览量

    7375
  • TCP通信
    +关注

    关注

    0

    文章

    146

    浏览量

    4200
收藏 人收藏

    评论

    相关推荐

    一讲TCP三次握手和四次挥手

    如果你学过网络基础知识,那么你定对TCP三次握手不陌生。今天我想用通俗的话来给大家一讲TCP三次握手和四次挥手。毕竟,这个知识点在面试时
    的头像 发表于 02-03 10:43 2666次阅读
    <b class='flag-5'>讲</b><b class='flag-5'>一讲</b>的<b class='flag-5'>TCP</b>三次握手和四次挥手

    哪位高手能给一下预分频的作用 或者有资料的分享一下

    哪位高手能给一下预分频的作用或者有资料的分享一下先行谢过
    发表于 02-10 22:42

    网络子系统在链路层的收发过程剖析

    网络子系统在链路层的收发过程剖析
    发表于 08-15 17:58

    求大神给一下电机驱动原理

    求大神给一下电机驱动原理越详细越好,感谢
    发表于 02-01 21:02

    MCBSP的收发过程是如何运行的

    MCBSP_rrdy(hMcbsp)为0时,表明DRR中的数据已经被读取,x = MCBSP_read(hMcbsp)语句如何理解?整个MCBSP的收发过程是如何运行的,我理解反了?谢谢,请高手指导指导。
    发表于 05-25 08:44

    个嵌入式系统的开发过程有哪些步骤?

    以MVB为例,解答一下嵌入式系统的开发过程有哪些步骤?
    发表于 04-27 06:36

    求大神详细介绍一下FPGA嵌入式系统开发过程中的XBD文件设计

    求大神详细介绍一下FPGA嵌入式系统开发过程中的XBD文件设计
    发表于 05-06 08:19

    一下在单片机开发过程中使用过的几种调试方案

    边运行边修改参数呢?调试的方法有多种,在这就来分别谈一下我在开发过程中使用过的几种调试方案。这里的调试方案也是种交互方案,但此方案不是为了交互而设计,重在快速地搭建、方便地使用、高
    发表于 01-14 08:25

    nodemcu的开发过程是怎样的

    关于nodemcu的点点滴滴##### 网络协议之前,我觉得应该把nodemcu的开发过程梳理遍,再说下自己调试遇到的问题。- 因为自己也是刚接触lua和esp12,理解上可能会有很多错误,希望
    发表于 02-16 06:25

    简单叙述一下STM32CubeIDE的开发过程

    STM32的资源是怎样进行配置的?STM32CubeIDE的开发过程是怎样的?
    发表于 02-24 06:28

    资源约束产品开发过程仿真模型

    提出考虑资源约束的产品开发过程仿真模型。该模型考虑产品开发过程中的返工迭代以及资源约束,根据任务信息控制能力确定任务资源分配的优先级,相对于Cooper 提出的资源分
    发表于 04-16 11:36 16次下载

    掌握串口通信协议的收发过程

    现在我们要做个实验,将个字节从51单片机发送到电脑串口调试助手上。这个实验的目的是为了掌握串口通信协议的收发过程
    的头像 发表于 12-22 10:02 7.9w次阅读
    掌握串口通信协议的<b class='flag-5'>收发过程</b>

    锡膏厂家一下助焊剂的危害有哪些?

    会成本比较高,这是相对应的,所以大家焊接过程种还是要注意,下面佳金源锡膏厂家一下有哪些危害:助焊剂的危害有:般情况,如果技术工人接触到
    的头像 发表于 01-10 09:30 1609次阅读
    锡膏厂家<b class='flag-5'>讲</b><b class='flag-5'>一下</b>助焊剂的危害有哪些?

    Linux TCP底层收发过程讲解

    我们继续探索高性能网络编程,但是我觉得在谈系统API之前可以先讲些Linux底层收发过程
    发表于 08-08 15:42 399次阅读
    Linux <b class='flag-5'>TCP</b><b class='flag-5'>底层</b>的<b class='flag-5'>收发过程</b>讲解

    ASIC芯片开发过程

    电子发烧友网站提供《ASIC芯片开发过程.ppt》资料免费下载
    发表于 12-25 10:04 1次下载