Posix API与网络协议栈

简介: Posix API与网络协议栈

Posix API 与网络协议栈

TCP协议的特点

  • 面向连接
  • 点对点:连接的只有两个端点
  • 可靠传输:无差错、不丢失、不重复,有序
  • 全双工通信:双向通信,两端设有发送缓存和接收缓存
  • 面向字节流

tcp 相关的 Posix API

  • 服务端: socket - bind - listen - accept - recv - send - close
  • 客户端: socket - connect - send - recv - close

查看网络相关状态命令:netstat -nat

1、TCP 报文段

tcp 首部

tcp 报文段分为 tcp 首部和 tcp 数据两部分

  • 源端口和目的端口
  • 序号 seq:本报文段发送的数据的第一个字节的序号。tcp面向字节流,为数据流中的每一个字节编上一个序号
  • 确认号 ack:期望收到对方的下一个报文段的数据的第一个字节的序号。确认号为n,表示序号 n-1 前的所有数据都已经正确收到。序号 + 有效荷载 = 确认号
  • 数据偏移:首部长度,单位4B
  • 窗口:允许对方发送的数据量,单位1B
  • 校验和:首部 + 数据

2、连接管理

每个 tcp 连接都有三个阶段:连接建立、数据传输和连接释放。

2.1、连接建立

2.1.1、posix API

  • socket():为文件系统分配fd,配置tcb(tcp control block)
  • bind():为tcp绑定本地的ip和端口。客户端bind(opt),不绑定则随机端口。
  • listen(): 把tcb状态置位 listen,参数backlog指的是全连接队列的长度。
  • connet(): 向服务端发送SYN报文,开始协议栈的三次握手,并等待三次握手的返回结果。
  • accept():阻塞,直至全连接队列非空。此时,从全连接队列中取一个tcb结点并为其分配1个 socket。

2.1.2、三次握手

tcp 建立三次握手的时候,内核做了哪些事情

服务端接收第一次握手,回复第二次握手的同时,把未建立完的 tcp 连接放入半连接队列里面。

第三次握手成功后,服务端收到 ACK 报文,从半连接队列中取出 tcb 结点放入全连接队列,发出通知,accept()收到信号后从全连接队列后取出1个 tcb 结点,并为其分配1个 socket 。

因此三次握手发生在客户端调用connect()后,服务端调用listen()accept()执行前。

tcp 三次握手

2.1.3、常见面试题

问题1、三次握手的原因

防止旧的重复连接引起连接混乱的问题(为什么不是两次握手)

  • 服务端收到已断开连接的 SYN 报文,服务器陷入忙等状态,
  • 客户端未收到 ACK 报文,而服务器端已处于ESTABLISHED状态,等待客户端发送数据,造成资源浪费

为什么不是四次握手?没必要,浪费资源。

问题2、DDos | SYN flood 攻击原理

  • 半连接队列:当客户端发送的SYN被服务端接收后,该连接加入syn队列,状态SYN_RCVD
  • 全连接队列:当客户端返回的ACK被服务端接收后,该连接加入accept队列

DDos | SYN flood 攻击原理:攻击方伪造 IP 发送大量的SYN报文到服务端,服务端不断重发 SYNACK 报文却无法得到响应,大量的连接处于SYN_RCVD状态。当半连接队列中的半连接数量足够多时,无法处理正常的连接请求,资源耗尽。

image.png

ddos | syn flood 攻击

解决:

  • 减少SYN + ACK 重试次数,避免大量的超时重发;
  • 利用 SYN Cookie 技术,在服务端接收到SYN后不立即分配连接资源,而是根据这个SYN计算出一个Cookie,连同第二次握手回复给客户端,在客户端回复ACK的时候带上这个Cookie值,服务端验证 Cookie 合法之后才分配连接资源。

问题3、双方同时发送 SYN 报文

  • 发完 SYN,两者的状态都变为SYN-SENT
  • 在各自收到对方的SYN后,两者状态都变为SYN-REVD
  • 回复对应的ACK + SYN,这个报文在对方接收之后,两者状态一起变为ESTABLISHED

同时发送 syn


问题4、已经建立连接的一方突然断开

TCP 的KeepAlive保持服务端与客户端的连接,一方不定期发送心跳探活包,另一方回复 ACK。若另一方断开连接,无法响应,返回RST,则释放当前连接。

区分 http 的keep-alive:短时间内连接可以复用。

2.2、数据传输

2.2.1、posix API

  • recv()fd对应的内核态tcbreadbuffer的数据拷贝到用户态
  • send() 将用户态的数据拷贝到fd对应的内核态tcbsendbuffer

recv send

2.2.2、tcp 分包与粘包问题

原因:tcp面向字节流,没有边界,不能通过send返回值判断。解决这一问题有两种方案:

  • 应用层协议首部增加数据报的长度 pktlen
    read(tcphdr, 2);
    read(tcphdr->length);
    while (cout < tcphdr->length) {
    size = read(tcphdr->length - count);
    count += size;
    }
  • 为每个包加上分隔符,如'/r/n'
    read(buffer, 1024);
    buffer[idx] = '/r/n';
    pktlen = &[idx + 2];

2.3、连接释放

2.3.1、posix API

close(): 将FIN报文放入sendbuffer中,回收fd

2.3.2、四次握手

tcp 四次握手

2.3.3、常见面试题

问题1、服务端出现大量close_wait状态

原因:客户端主动关闭连接(recv返回0),服务端忙于读写,未及时关闭连接close()

解决:业务数据处理与网络层处理异步分离

问题2、双方同时关闭连接

双方变化状态是一致的,即双方发送了FIN包后,收到了对方的FIN包,进入 CLOSING 状态。

closing 状态

  • 双方发送FIN报文后,进入FIN_WAIT_1状态
  • 接收到对方的FIN报文后,进入CLOSING状态,并向对方发送ACK
  • 接收到对方的ACK报文后,进入TIME-WAIT状态,等待2MSL后,关闭连接

同时发送 fin

问题3、主动断开为什么会有TIME_WAIT状态

避免由于最后一次握手时ACK包的丢失造成问题,原因如下:

  • 1、保证四次握手顺利完成
  • 假设第四次挥手的ACK丢失,此时主动断开方认为对端没有收到FIN报文,该连接没有正常断开,重发第三次挥手的FIN报文。
  • 2、保证旧的报文在网络中消失
    连接的socket 五元组信息相同,可看作是同一个连接。若已经失效的报文请求出现在本次连接中,则造成数据蹿链。

问题4、TIME_WAIT状态为什么是2MSL

MSLMaximum Segment Lifetime,报文最大生存时间

确保对端没有收到第四次ACK报文时重传的FIN报文可以到达主动断开方。(ACK+超时重传FIN)

问题5:四次握手的原因

TCP是全双工的连接,需要把两个方向上的数据传输都断开

问题6:服务器端能否主动断开连接?

可以,但是主动断开连接的一方会进入TIME_WAIT状态,该状态会持续 2MSL 的,造成服务器端的资源浪费。可以设置服务器的网络地址为可重用,可解决该问题。

2.4、tcp 状态转移图

tcp 状态转移图

3、可靠传输机制

  • 序号:保证数据有序提交给应用层
  • 确认:累计确认 + 延迟 ACK
  • 重传
  • 超时:计时器到期未收到确认则重传对应的报文
  • 冗余确认:当收到失序报文时向发送端发送冗余ACK

4、流量控制

4.1、高效发送的因素

如何让tcp高效的发送数据,主要考虑两个因素:

  • 对方还能接收多少 (流量控制)
  • 网络上还能发送多少(拥塞控制)

结论:发送窗口 swnd = min (rwnd, cwnd),这里我们先来介绍流量控制。

流量控制指的是点对点通信量的控制,匹配发送方的发送速率和接收方的读取速率,避免发送方发送速率过快,接收方来不及读出,导致接收方缓存区溢出。

方法:在确认报文中设置接收窗口rwnd的值来限制发送速率。对应 tcp 报文首部的窗口 window字段。先收缩窗口大小,再减少缓存。

传输层流量控制和数据链路层流量控制的区别

  • 数据链路层定义两个中间的相邻结点的流量控制,窗口大小固定
  • 传输层定义端到端用户间的流量控制,窗口大小动态变化

4.2、滑动窗口

tcp 采用选择重传 ARQ协议 + 累计确认

tcp_发送方滑动窗口

发送窗口有三个指针:

  • SND.WND:表示发送窗口的大小,大小是由接收方指定的
  • SND.UNA:指向已发送但未收到确认(发送窗口)第一个字节的序列号
  • SND.NXT:指向未发送但在可发送范围内(可用窗口)的第一个字节的序列号

3 个指针将滑动窗口分为 4 个部分

  • 已发送并收到ACK
  • 已发送未收到ACK,SND.UNA指向
  • 未发送但在接收方处理范围内,SND.NXT指向
  • 未发送超过接收方处理范围内,SND.UNA + SND.WND指向
可用窗口大小 =  SND.WND -(SND.NXT - SND.UNA) = SND.UNA + SND.WND - SND.NXT

接收方滑动窗口

tcp_接收方滑动窗口

接收窗口有两个指针

  • RCV.WND:表示接收窗口的大小,它会通告给发送方。
  • RCV.NXT:指向期望从发送方发送来的下一个数据字节(接收窗口)的序列号

两个指针将滑动窗口分成三个部分

  • 已接收数据并确认,等待应用进程读取
  • 未收到数据但可以接收,RCV.NXT 指向
  • 未收到数据且不可以接收,RCV.NXT + RCV.WND指向

5、拥塞控制

概念:全局性的过程,防止过多数据注入网络,使网络能够承担现有负荷。

方法:根据自己估算的网络拥塞程度设置拥塞窗口 cwnd来限制发送速率。

"如何判断网络拥塞?"

发送方没有在规定时间内接收到 ACK 应答报文,发生了超时重传,则认为网络出现了拥塞。

超时的计算:rtt(new) = 0.9 * rtt(old) + 0.1rtt

5.1、拥塞的控制算法

1、慢启动

tcp 刚建立好连接并开始发送数据时,cwnd = 1,执行慢启动

规则:发送方每收到1个 ACK,cwnd + 1(1个MSS: 最大报文段长度)

每经过一个 RTT,cwnd 加倍 ,cwnd指数增加。一直到达慢启动门限 ssthresh,改用拥塞避免算法。若 2cwnd > ssthresh,则下一个 RTT 时:cwnd = ssthresh

慢启动

2、拥塞避免

当拥塞窗口 cwnd 超过慢启动门限 ssthresh 就会进入拥塞避免算法。

规则:发送方每收到1个 ACK 时,cwnd + 1/cwnd。此时,每经过1个RTT,cwnd + 1

拥塞避免

随着拥塞窗口的线性增加,当网络出现丢包现象,触发了重传机制,进入拥塞发生算法。

3、拥塞发生算法

当网络出现拥塞,也就是会发生数据包重传,重传机制主要有两种,注意区分:

  • 超时重传:超时,慢启动
  • 快速重传:收到3个冗余ACK,快恢复
“为什么超时执行慢启动,而收到3个冗余ACK却执行快恢复”

收到3个冗余 ACK 时,说明网络虽然拥塞,但是至少还有 ACK 报文能够正确被交付。而当超时发生时,说明网络可能已经拥塞到连ACK报文都传输不了,发送方只能等待超时后重传数据,因此,超时发生时,网络拥塞更严重,发送方应该最大限度地一直数据发送量,cwnd重置为1。

超时重传

发生超时重传时

  • ssthresh 设为 cwnd/2
  • cwnd 重置为 1
  • 慢启动

超时重传

快速重传和快恢复

当接收方发现丢了一个中间包的时候,发送三次该包前一个包的 ACK,于是发送端就会快速重传,不必等待超时再重传。

  • cwnd = cwnd/2
  • ssthresh = cwnd;
  • 快速恢复算法

快速恢复算法

  • cwnd = ssthresh + 3 ( 有 3 个数据包被收到了);或cwnd = ssthresh
  • 重传丢失的数据包

快速重传和快恢复

完整的 tcp 拥塞控制算法如下:

tcp 拥塞控制算法

6、参考


相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
1月前
|
弹性计算 负载均衡 网络协议
这种情况可能是由于阿里云的API服务出现了短暂的故障或者网络波动导致的
【2月更文挑战第20天】这种情况可能是由于阿里云的API服务出现了短暂的故障或者网络波动导致的
70 1
|
2月前
|
分布式计算 API Linux
通义千问API:找出两篇文章的不同
本章我们将介绍如何利用大模型开发一个文档比对小工具,我们将用这个工具来给互联网上两篇内容相近但版本不同的文档找找茬,并且我们提供了一种批处理文档比对的方案
|
15天前
|
网络协议 Linux SDN
虚拟网络设备与Linux网络协议栈
在现代计算环境中,虚拟网络设备在实现灵活的网络配置和隔离方面发挥了至关重要的作用🔧,特别是在容器化和虚拟化技术广泛应用的今天🌐。而Linux网络协议栈则是操作系统处理网络通信的核心💻,它支持广泛的协议和网络服务🌍,确保数据正确地在网络中传输。本文将深入分析虚拟网络设备与Linux网络协议栈的关联,揭示它们如何共同工作以支持复杂的网络需求。
|
2月前
|
存储 网络协议 安全
POSIX API与网络协议栈
POSIX API与网络协议栈
36 0
|
2月前
|
机器学习/深度学习 人工智能 API
人工智能应用工程师技能提升系列2、——TensorFlow2——keras高级API训练神经网络模型
人工智能应用工程师技能提升系列2、——TensorFlow2——keras高级API训练神经网络模型
33 0
|
3月前
|
网络协议 Linux API
Posix API与网络协议栈
Posix API与网络协议栈
128 0
|
1月前
|
机器学习/深度学习 数据采集 人工智能
m基于深度学习网络的手势识别系统matlab仿真,包含GUI界面
m基于深度学习网络的手势识别系统matlab仿真,包含GUI界面
41 0
|
1月前
|
机器学习/深度学习 算法 计算机视觉
基于yolov2深度学习网络的火焰烟雾检测系统matlab仿真
基于yolov2深度学习网络的火焰烟雾检测系统matlab仿真
|
1月前
|
机器学习/深度学习 算法 计算机视觉
m基于深度学习网络的性别识别系统matlab仿真,带GUI界面
m基于深度学习网络的性别识别系统matlab仿真,带GUI界面
29 2
|
1月前
|
机器学习/深度学习 算法 计算机视觉
基于yolov2深度学习网络的视频手部检测算法matlab仿真
基于yolov2深度学习网络的视频手部检测算法matlab仿真