【完结12章】基于C++从0到1手写Linux高性能网络编程框架
分享一套课程——基于C++从0到1手写Linux高性能网络编程框架,已完结12章,附源码+电子书。大家下载学习。
Socket 网络编程框架
Socket(套接字)是一个网络编程概念,描述了一个通信端点(Endpoint),用于建立网络连接(Connection)并传输数据。
Linux Kernel 提供了一套面向 Socket 的网络编程框架,并通过提供一组标准的 System call APIs,使得开发者可以在 Userspace 中便捷的开发各种 Network Applications,例如:基于 HTTP 协议的 Web 服务器、基于 SMTP 协议的邮件服务器、基于 FTP 协议的文件服务器等等。
Linux Socket 网络编程框架主要由 3 大模块组成:
1、BSD Socket APIs
2、Socket Abstraction Layer
3、VFS Layer
TCP通信的实现过程
TCP通信的实现过程主要包括三个阶段:建立连接、数据传输和连接释放。
建立连接
在TCP通信开始之前,发送方和接收方需要先建立连接,以便在传输数据时能够互相识别。
a. 三次握手
发送方首先向接收方发送一个SYN(同步)包,用于请求建立连接。接收方收到SYN包后,回复一个ACK(确认)包,表示接收到请求。同时,接收方也向发送方发送一个SYN-ACK包,表示接收方准备好了建立连接。发送方收到SYN-ACK包后,回复一个ACK包,表示连接建立成功。
这个过程被称为“三次握手”,是为了确保双方都能正确地识别对方并建立连接。
b. 建立连接后的数据传输
连接建立后,发送方可以向接收方发送数据,数据会按照TCP协议进行分组、封装、校验和传输。接收方会根据TCP协议对数据进行解封、校验和重组,确保数据的正确性。
TIME_WAIT状态存在原因有两点:
其一是可靠的中止tcp连接;
其二是保证让延迟的tcp报文有足够的时间被识别;
客户端在关闭连接阶段需要处理收到重复的结束报文,然后回复最后的ACK给服务端,否则客户端在收到服务端的FIN就直接回复ACK,这样后续服务端重传的FIN包都会被回复RESET报文,这时服务端认为是错误报文,这就是第一点存在的原因;
那么第二点是为了不让同一个tcp端口被多次打开或者是断开以后马上被一个新的连接接管,这样存在数据安全和处理异常等问题,让tcp最大时间坚持2MSL也是为了确保重发和延时的tcp包在这段时间内被丢弃(使用端口复用采用socket选项SO_REUSEADDR);
tcp超时重传和拥塞控制
tcp服务必须能够重传超时时间内未收到的tcp报文段。
为此,tcp模块为每一个tcp报文都维护一个重传定时器,linux两个重传相关的内核参数:
/proc/sys/net/ipv4/tcp_retries1和/proc/sys/net/ipv4/tcp_retries2
前者表示tcp最少执行重传次数,默认为3;
后者表示tcp最多执行重传次数,默认为15;
tcp服务有重传必然就会导致拥塞,那么接下来介绍网络底层如何进行拥塞控制?
拥塞控制包括四个部分:慢启动,拥塞避免,快速重传和快速恢复;
在此之前还需要介绍窗口概念:RNWD(接收窗口,指前面tcp报文中的对端发送的win窗口),CWND(拥塞窗口,是系统定义的一个状态变量大小),SWND(发送窗口,是RNWD和CWND之间的较小值);
在tcp模块刚开始发送数据阶段并不知道网络的实际情况,需要试探性地增加CWND,这一过程称为慢启动,CWND初始值设置为2-4个MSS;然后发送端每次收到接受端的一个确认,就按照公式:
CWND += min(N, MSS)
其中N是此次确认中包含的之前未确认的字节数;
如果随着CWND不断累加,不加控制会造成网络拥塞,那么需要进行拥塞避免算法,界定慢启动和拥塞避免过程通过慢启动门限(ssthresh)控制,当CWND超过ssthresh则进入拥塞避免阶段;
拥塞避免阶段控制CWND是每个RTT时间都计算(如果RTT时间内收到多少确认包),公式:
CWND += SMSS*SMSS/CWND
这样就保障了CWND缓慢增长,直到传输超时或者tcp重传定时器溢出,就需要重新调整ssthresh,再次进入慢启动阶段,那么ssthresh计算公式:
ssthresh = max(FlightSize/2, 2MSS)
其中FlightSize已经发送但是还未收到确认的字节数;
另外一种情况:在接受端接收到重复的确认报文段的时候,tcp模块如何处理?
如果发送端收到3个重复的确认报文,认为拥塞发生,启动快速重传和快速恢复,先计算ssthresh;
然后通过CWND = ssthresh + 3 * SMSS计算出CWND,再次每收到1个重复确认时,设置CWND += SMSS,最后当收到新数据的确认时,直接设置CWND = ssthresh,这样快速重传和快速恢复完成,又再次进入拥塞避免阶段。
网络协议栈的集成
网络协议栈是实现网络通信的核心部分,包括IP协议、TCP/UDP协议、路由、ARP等。为了实现高性能网络应用,可以考虑以下几点:
1)、使用硬件加速技术:一些网络设备支持硬件加速功能,例如卸载协议栈的一部分功能到网络设备中,利用硬件加速处理数据包。
2)、优化协议栈参数:通过调整协议栈的各种参数来优化性能,包括接收和发送缓冲区的大小、超时时间、滑动窗口等。
3)、选择合适的协议栈:根据应用的需求选择合适的协议栈,例如使用高性能的协议栈(如DPDK)。
5、性能调优和测试
在构建网络驱动程序后,需要进行性能调优和测试,以确保驱动程序能够达到预期的性能要求。可以通过以下几点来进行性能调优和测试:
1)、使用性能分析工具:例如perf、ftrace等工具来分析性能瓶颈和优化性能。
2)、进行基准测试:通过搭建测试环境,模拟实际网络负载,并对驱动程序进行基准测试,评估其性能。
3)、进行系统优化:根据测试结果进行系统优化,包括内核参数的调整、硬件资源的优化、中断处理的优化等。
构建Linux内核网络驱动程序是实现高性能网络应用的关键步骤。在构建过程中,需要进行硬件设备的初始化和配置、中断处理、网络收发处理、网络协议栈的集成等工作,并进行性能调优和测试,以确保驱动程序能够达到预期的性能要求。通过以上步骤的综合优化,可以构建高性能的Linux内核网络驱动程序,提升网络应用的性能和吞吐量。
![QQ截图20231221144903.png](https://static.golangjob.cn/231221/f2d07852f0b8e252100082b5ebea6744.png)
有疑问加站长微信联系(非本文作者)
![](https://static.golangjob.cn/static/img/footer.png?imageView2/2/w/280)