什么是TCP协议?
TCP 是面向连接的,保证高可靠连性(数据无丢失,数据不错位,数据不乱序,数据无重复)的传输协议。
TCP头
- 源端口和目的端口 各占2个字节,分别些人源端口号和目的端口号。
- 序号 占4个字节,范围是 【0 - 2^32-1 】 4284967296 个序号。序号增加到 2^32-1 ,下一个序号又回到0 ,序号使用 mod 2^32 运算。也叫做报文段序号。
- 确认号 占 4个字节 期望收到对方下一个报文段的第一个数据字节的序号,比如 B 正确收到了 A 发送过来的一个报文段。其报文序号字段值是501,而数据长度是 200 字节 ,(序号501-700),这个表名B正确收到了 A 发送的到序号700为止的数据,B期望收到的下一个序号是701 ,于是 B 再发送给A 的确认报文段中确认号置为 701。
- 数据偏移 占4位,指出的是 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。这个字段其实上也是指出 TCP 报文段的首部长度。 单位是4字节 ,4位能表示最大数是 15 ,首部最大长度即为 15*4字节 = 60 字节。
- 紧急 URG 当 URG = 1 时,表示紧急指针字段有效,表示报文段中有紧急数据, 应尽快发送,而不是按照原来的排队顺序发送。场景是,已经发送了一个很长的一个程序,需要远程主机上 运行,由于一些原因,要取消该程序运行,因此用户发送中断命令 Control+C,如果不使用紧急数据,那么这两个字符将存储在TCP的缓存末尾。只有在所有数据发送完毕之后,这两个字符才能交付到接收方程序上,浪费了很多时间。
- 确认ACK 仅当 ACK =1 是确认号字段才有效,当 ACK =0 是,确认好无效。TCP 规定,在连接建立后所有传输的报文都必须把 ACK 置1
- 推送PSH 当两个应用进程进行交互式通讯是,有时在一端的应用进程希望键入一个命令后立即就能收到对方的响应。在这种情况。TCP 就可以使用推送 push 操作。
- 复位 RST 当 RST = 1时,表明 TCP 连接中出现严重的差错(如 由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
- 同步 SYN 在连接建立时用来同步序号,当SYN =1 而ACK =0 时,表明这是一个连接请求报文段。对方如果同意建立连接,则应在影响的报文段使用 SYN = 1 和Ack =1 ,因此,SYN 置成 1 表示这是一个连接请求或者连接接受报文。
- 终止 FIN 用来释放一个连接,当 FIN = 1 时,表名此报文段的发送方的数据已经发送完毕,并要求释放运输连接。
- 窗口 占 2个字节, 窗口是 【0,2^16 -1】之间的整数,窗口指的是发送本报文段的乙方的接收窗口, 窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。 为啥要有这个限制,因为接收方的数据缓存空间是有限的。
- 校验和 占 2 个字节。校验和字段校验的范围包括首部和数据这两部分。
- 紧急指针 占 2个字节 紧急指针金在 URG =1 时才有意义,它指出本报文段的紧急数据的字节数 ,因此紧急指针指出了紧急数据的末尾在报文段中的位置,所有紧急数据都处理完时, TCP 就告诉应用程序恢复到正常操作值。
- 选项 长度可变, 最长可达到 40 字节,当没有使用选项时, TCP 首部的长度是 20 字节。
校验和计算
发送时:
1、把校验和字段设置为0;
2、把需要校验的数据看成以16位为单位的数字组成,依次进行二进制反码求和;
3、把得到的结果存入校验和字段中
def carry_around_add(a, b):
c = a + b
return (c & 0xffff) + (c >> 16)
def checksum2(msg):
s = 0
for i in range(0, len(msg), 2):
w = (ord(msg[i]) << 8) + ord(msg[i + 1])
s = carry_around_add(s, w)
return ~s & 0xffff
接收时
1、把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段;
2、检查计算出的校验和的结果是否为0;
3、如果等于0,说明被整除,校验和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。
def checksum(data): # calculate checksum
s = 0
n = len(data) % 2
for i in range(0, len(data) - n, 2):
s += ord(data[i]) + (ord(data[i + 1]) << 8)
if n:
s += ord(data[i + 1])
while (s >> 16):
s = (s & 0xFFFF) + (s >> 16)
s = ~s & 0xffff
return s
TCP 可靠传输
接收序号和确认序号,在途中有数据丢失的情况下,返回ACK序号进行重发。
TCP的特点
- 面向连接的传输层协议
- 每一条TCP连接只能有两个端点
- 提供可靠交付的服务
- 提供全双工通信
- 面向字节流
建立连接: TCP 三次握手
1. A 向 B 发出连接请求报文段,此时首部 SYN = 1 同时选择一初始序号 seq = x
2. B 接收连接请求报文段后,如果同意连接,则向 A 确认,确认报文段中 SYN 位 和 ACK 位都是 1 ,确认号 ack = x+1,同时也为自己初始一个序号 seq = y
3. A 收到 B的确认后, 还需要给 B 确认,确认报文段的 ACK =1 , 确认号 ack = y+1, 而自己的序号 seq = x+1
通过抓包可以看到三次握手建立连接如下:
断开连接:四次挥手
- A 向 B 发送连接释放报文端,并停止发送数据,主动关闭 TCP 连接,报文端首部 FIN 设置成1 ,序号 seq = u ,它等于前面已经传输过来的最后一个自己的序号+1
- B 接收连接释放报文后发送确认报文 ,确认号 ack = u+1, 而这个报文段自己的序号是v, 等于B前面已经传送状态的最后一个字节序号+1
- A 收到 B的确认信号之后,进入终止等待状态,等待B发送的连接释放报文B 发送连接释放报文,必须重复上次发送的确认号 ack = u+1 ,B 进入最后确认状态 等待 A 确认
- A 收到B的连接释放报文后,发送确认 ACK = 1, 确认好 ack = w+1 ,序号 seq = u+1
通过抓包可以看到,断开连接如下: