3.TCP协议
一、TCP协议特点和报文段格式
- 面向连接的传输层协议
- 每一条TCP连接只能有两个端点
- TCP提供可靠交付的服务,无差错,不丢失,不重复,按序到达
- 全双工通信 ->
发送缓冲:准备发送的数据&已发送但尚未收到确认的数据
接收缓存:按序到达但尚未被接受应用程序读取的数据&不按序到达的数据
- TCP面向字节流
重点(报文段格式)
序号:本报文段发送数据的第一个字节的序号
确认号:期望收到对方下一个报文段的第一个数据字节的序号,若确认号为N,则证明到序号N-1为止都已正确收到
数据偏移(首部长度):TCP报文段的数据起始处距离TCP报文段的起始处有多远,以4B为单位,即1个数值就是4B
窗口:允许对方发送的数据量(自己可以容纳的数据量)
六个字段:
二、TCP连接管路
- 连接建立
三次握手
- 数据传输
- 连接释放
四次握手
三、TCP可靠传输
可靠:接收方进程从缓存区中读出的字节流与发送方发出的字节流是完全一样的
TCP实现可靠传输的机制:
- 校验:与UDP校验一致
- 序号
- 确认
- 重传(TCP发送方在规定时间没有收到确认(或者冗余ACK)就要重传)
四、TCP流量控制(让发送方发慢点)
TCP利用滑动窗口实现流量控制
在通信过程中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小,即接收窗口rwnd(接收方设置确认报文段的窗口字段来将rwnd通知给发送方),发送方的发送窗口取接收窗口rwnd和拥塞窗口cwnd的最小值。
防止僵持(死锁)
五、TCP拥塞控制(防止过多数据注入网络)
出现拥塞的条件:对资源的需求的总和 > 可用资源
与流量控制的区别:
拥塞控制四种算法:
- 慢开始
- 拥塞避免
- 快重传
- 快恢复
接收窗口:接收方根据接受缓存设置的值,并告知给发送方,反映接收方容量
拥塞窗口:发送方根据自己估算的网络拥塞程度而设置的窗口值,反映网络当前容量
ssthresh:慢开始门限值
from matplotlib import pyplot as plt
from matplotlib.widgets import Button
from PIL import Image
import numpy as np
# matplotlib画图
def draw():
x = []
for i in range(len(cwnd_array)):
x.append(i+1)
axe.plot(x, cwnd_array)
fig.canvas.draw()
# dupACKcount++
def dup_ACK(event):
tcpcc.add_dup_ack()
draw()
print('dupACKcount = ', tcpcc.dupACKcount)
# timeout
def let_timeout(event):
tcpcc.timeout()
draw()
# new ACK
def new_ack(event):
tcpcc.new_ack()
draw()
# 画按钮
def draw_button():
global ack_btn, timeout_btn, new_ack_btn # must global
ack_point = plt.axes([0.3, 0.03, 0.1, 0.03])
ack_btn = Button(ack_point, "DUP ACK")
ack_btn.on_clicked(dup_ACK)
new_ack_point = plt.axes([0.45, 0.03, 0.1, 0.03])
new_ack_btn = Button(new_ack_point, "NEW ACK")
new_ack_btn.on_clicked(new_ack)
timeout_point = plt.axes([0.6, 0.03, 0.1, 0.03])
timeout_btn = Button(timeout_point, "TIMEOUT")
timeout_btn.on_clicked(let_timeout)
# TC拥塞控制类
class TCP_C_C:
def __init__(self):
self.cwnd = 1
self.ssthresh = 64
self.dupACKcount = 0
self.state = '慢启动' # 状态分为:慢启动、拥塞避免、快恢复
cwnd_array.append(self.cwnd)
# 增加一个ACK重复的
def add_dup_ack(self):
if self.state == '快恢复':
self.cwnd = self.cwnd + 1
else:
self.dupACKcount = self.dupACKcount + 1
if self.dupACKcount == 3:
self.ssthresh = self.cwnd / 2
self.cwnd = self.ssthresh + 3
self.state = '快恢复'
cwnd_array.append(self.cwnd)
# 超时
def timeout(self):
self.ssthresh = self.cwnd / 2
self.cwnd = 1
self.dupACKcount = 0
self.state = '慢启动' # 状态分为:慢启动、拥塞避免、快恢复
cwnd_array.append(self.cwnd)
# new ACK
def new_ack(self):
if self.state == '慢启动':
self.cwnd = self.cwnd * 2
self.dupACKcount = 0
if self.cwnd >= self.ssthresh:
self.state = '拥塞避免'
elif self.state == '拥塞避免':
self.cwnd = self.cwnd + 1
self.dupACKcount = 0
elif self.state == '快恢复':
self.cwnd = self.ssthresh
self.dupACKcount = 0
self.state = '拥塞避免'
cwnd_array.append(self.cwnd)
if __name__ == "__main__":
cwnd_array = [] # 纵坐标
tcpcc = TCP_C_C()
fig = plt.figure()
draw_button()
axe = fig.add_subplot(111)
axe.plot(cwnd_array)
plt.xlabel('Transmission round')
plt.ylabel('cwnd')
plt.grid()
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mTppw4Aw-1592742727926)(https://uploader.shimo.im/f/PG8K3zzeo7V6A1nN.gif)]