确认号 占 4个字节 期望收到对方下一个报文段的第一个数据字节的序号,比如 B 正确收到了 A 发送过来的一个报文段。其报文序号字段值是501,而数据长度是 200 字节 ,(序号501-700),这个表名B正确收到了 A 发送的到序号700为止的数据,B期望收到的下一个序号是701 ,于是 B 再发送给A 的确认报文段中确认号置为 701。
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,说明被整除,校验和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。
代码语言:javascript
复制
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 确认