从零构建自己的TCP/IP协议(二)

这是第二篇,主要讲三次握手,四次挥手,滑动窗口,拥塞控制

回顾

上次我们从0构建了一个粗糙的初步可用的协议,叫做PCT协议(文章链接在这里)。

这个协议从0和1的二进制世界,抽象一步到了网卡的层面,所以我们获得了MAC地址,之后再进一步,于是有了IP地址,最后我们在IP的基础上完成了可以跨主机传输的PCT协议,如果你还没有看,建议先去看一下上篇 :)。

回顾一下,如果我们的ip地址是192.168.1.1, 端口号是 1, 目标的ip地址是 192.168.1.2, 端口号是 2。那么PCT协议将会发送这样的包:

111(开始)
00000000 11101000(长度)
01110010 01101111 01110101 01110100 01100101 01110010(来源MAC地址)
01110000 01101000 01101111 01101110 01100101 01110010(目标MAC地址)
11000000 10101000 00000001 00000001(来源ip地址)
11000000 10101000 00000001 00000010(目标ip地址)
00000001(来源的端口号)
00000010(目标的端口号)
00000001(发送的包的序号是1)
00000000(已经确认的包的序号是0,表示啥都没有嘛)
01101000 01100101 01101100 01101100 01101111(字符串"hello")
000(结束)

为什么是三次握手和四次挥手?

“你知道TCP/IP吗?三次握手和四次挥手是什么?”这是面试中很常见的一个问题,我第一次听说这个词语的时候很奇怪,为什么是三次?为什么是四次?

我们来看一下,我们要创建一个可靠的协议,什么是可靠?100%保证送达吗?不是,现实世界里我们根本做不到无论何时何地100%送达,比如古代的飞鸽传书,鸽子可能跑去和异性约会,也可能被人烤了。例如我们打电话对方可能占线,也可能上网上着上着光缆被人挖断了。那怎么定义可靠呢?我们只能说在99%的情况下,只要能送达,我一定送达,要是送不到,我就告诉你送不到。嗯,这是我自己定义的可靠,当然,可靠系数越高越好。

话说回来,为什么刚好是三次和四次呢?

可以想到,假设我们在一栋墙的两边,只能透过小纸条传递信息,我怎么确定你一定收到了呢?那当然是有人告诉我你收到了,这就好解决了,有人告诉我你收到了我就觉得你收到了。有人告诉我要给你转账一百元我就给你转账一百元。。。感觉似乎不太对,最好的方法还是你亲自写纸条告诉我你收到了,因为可以通过笔迹来确认。

那问题就来了,我给你发送一条信息,你告诉我你收到了,我告诉你我收到了你的收到了,你告诉我你收到了我收到了你收到了,你。。。

这样设计协议肯定不行,如果这样我们根本没有时间传输真正有用的信息,而是一直在确认互相收到了。我们能不能把这些信息合在一起呢?我们把协议改一改(看第五条,首尾包裹的部分先忽略):

  • 首先是来源地址的端口号,8个bit来表示
  • 然后是目标地址的端口号,8个bit来表示
  • 然后是这个包的序号,8个bit来表示
  • 然后是确认收到的包的序号,8个bit来表示
  • 然后是这个包的类型,8个bit来表示

我们加入了包的类型,具体定义一下包的类型有哪几种:

  • 0x01 请求进行通信
  • 0x02 同意进行通信
  • 0x03 请求对方关闭通信
  • 0x04 通知对方我方已经关闭
  • 0x05 确认收到了某个包
  • 0x06 包中带有具体传输的内容

这样我们就可以这样干:

A: B啊,我要和你通信可以吗?这个包序号为1
B: 可以啊,通信吧,收到了你序号为1的包,我这个包的序号为1
A: 好啊,那我开始传内容了,并且我还收到了你序号为1的包,我这个包的序号为2
...

瞧,对话的第三回我们就可以确认双方都可以通信了,并且开始带上真正的内容了,让我们来发个hello试试,当然了,第一篇中的MAC地址等头部我们继续忽略,下同。继续之前的假设,A的IP地址为 192.168.1.1,端口号是1,B的IP地址为 192.168.1.2,端口号是2。

这是第一句:“B啊,我要和你通信”,其中带有的信息有:我要和B请求通信,我之前还没收到过B的包,我这个包的序号为1。

11000000 10101000 00000001 00000001(来源ip地址)
11000000 10101000 00000001 00000010(目标ip地址)
00000001(来源的端口号)
00000010(目标的端口号)
00000001(发送的包的序号是1)
00000000(已经确认的包的序号是0,表示啥都没有嘛)
00000001(请求进行通信)

然后是B的回复:“通信吧,我这个包的序号是1,我收到了你的序号为1的包”

11000000 10101000 00000001 00000010(来源ip地址)
11000000 10101000 00000001 00000001(目标ip地址)
00000010(来源的端口号)
00000001(目标的端口号)
00000001(发送的包的序号是1)
00000001(已经确认的包的序号是1)
00000010(同意进行通信)

然后就是第三句:“好啊,那我开始传输内容了,我这个包的序号为2,我收到了你序号为1的包”

11000000 10101000 00000001 00000001(来源ip地址)
11000000 10101000 00000001 00000010(目标ip地址)
00000001(来源的端口号)
00000010(目标的端口号)
00000010(发送的包的序号是2)
00000001(已经确认的包的序号是1)
00000110(包中带有具体传输的内容)
01101000 01100101 01101100 01101100 01101111(字符串"hello")

四次挥手,这次我就不把具体的报文写出来了,而是谈谈为什么是四次。其实不是四次,三次也可以。

假设客户端主动要求断开连接,那对话就是:

```
A: B啊,我请求断开连接,并且我收到了你的上一个包,序号是n。我这个包的序号是m。

top Created with Sketch.