写在前面:今天中秋佳节,首先祝大家佳节快乐,身体健康,恭喜发财。吃也吃了,喝也喝了,玩也玩了,干点正事吧。

说一下写这个系列的目的,随着对物联网开发的深入,越来越觉得自己网络基础知识的薄弱,虽然开发过程中不需要对网络基础有很深入的了解照样能进行,但有一些问题仍然是不知其因,所以这个系列打算从最基本的网络知识展开记录,也是一边学习一边整理笔记。欢迎大家共同学习,QQ:993650814.

Linux 网络编程 全解(一)--------网络基础协议

Linux 网络编程 全解(二)--------套接字socket


正文:

一、TCP通信时序

先贴一张TCP通信时序图,如下:

1、TCP 三次握手

Linux 网络编程 全解(一)--------网络基础协议 中已经讲了TCP的报文格式,其中报文中的SYN标志位就表示连接请求的标志,FIN位表示关闭连接的标志。上述例子中,是由client端发起连接请求,server端响应请求,最后client发起主动关闭连接的。

(1)、client发送段1,带有连接请求标志SYN,序号是1000,每发一个数据字节,这个序号要加 1,这样在接收端可以根据序号排出数据包的正确顺序,也可以发现丢包的情况,另外,规定 SYN 位和 FIN 位也要占一个序号,这次虽然没发数据,但是由于发了 SYN 位,因此下次再发送应该用序号 1001。 mss 表示最大段尺寸。

(2)、服务器端回应客户端, 是三次握手中的第 2 个报文段,同时带 ACK 标志和 SYN 标志。它表示对刚才客户端SYN 的回应;服务器发出段 2,也带有 SYN 位,同时置 ACK 位表示确认,确认序号是 1001,表示“我成功接收了序号为1001之前的数据,请你下次发送序号为 1001 的段”,也就是应答了客户端的连接请求,同时也给客户端发出一个连接请求,同时声明最大尺寸为 1024。

(3)、客户必须再次回应服务器端一个 ACK 报文,这是报文段 3。客户端发出段 3,对服务器的连接请求进行应答,确认序号是 8001。在这个过程中,客户端和服务器分别给对方发了连接请求,也应答了对方的连接请求,其中服务器的请求和应答在一个段中发出,因此一共有三个段用于建立连接,称为“三方握手(three-way-handshake)”。在建立连接的同时,双方协商
了一些信息,例如双方发送序号的初始值、 最大段尺寸等。

2、数据传输:

(1)、客户端发出段 4,包含从序号 1001 开始的 20 个字节数据。

(2)、服务器发出段 5,确认序号为 1021,对序号为 1001-1020 的数据表示确认收到,同时请求发送序号 1021开始的数据,服务器在应答的同时也向客户端发送从序号 8001 开始的 10 个字节数据。

(3)、客户端发出段 6,对服务器发来的序号为 8001-8010 的数据表示确认收到,请求发送序号 8011 开始的数据。

在数据传输过程中, ACK 和确认序号是非常重要的,应用程序交给 TCP 协议发送的数据会暂存在 TCP 层的发送缓冲区中,发出数据包给对方之后,只有收到对方应答的 ACK 段才知道该数据包确实发到了对方,可以从发送缓冲区中释放掉了,如果因为网络故障丢失了数据包或者丢失了对方发回的 ACK 段,经过等待超时后 TCP 协议自动将发送缓冲区中的数据包重发。

3、TCP四次挥手:

由于 TCP 连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个 FIN 来终止这个方向的连接。收到一个 FIN 只意味着这一方向上没有数据流动。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

(1)、客户端发出段7,FIN位表示关闭连接的请求。

(2)、服务器发出段8,应答客户端发出关闭连接的请求。

(3)、服务器发出段9,包含FIN位,向客户端发出关闭连接的请求。

(4)、服务器发出段10,应答服务器关闭连接的请求。

半关闭状态介绍:在TCP四次挥手的过程中可以看出,客户端发出的段7中包含有FIN标志位,服务器端回应ACK之后并没有立马发送FIN标志位,此时客户端处就处在半关闭状态,此时服务器可以向客户端发送数据,但客户端只能发送ACK信号不能再向服务器发送数据了。

半关闭状态关闭的不是套接字,而是缓冲区(可参考Linux 网络编程 全解(二)--------套接字socket 中的套接字通信原理图来查看原理),所以即使半关闭状态下,也能发送ACK信号,只是不能发送数据了。

二、滑动窗口(Sliding Window)

滑动窗口也叫流量控制,在通信过程中,如果发送端发送的速度过快,接收端如果收到数据后处理的速度很慢,而接收缓冲区的大小是固定的,这样就会丢失数据。TCP通过滑动窗口机制解决这一问题,先看一下原理图:

上述通信过程解析如下:

1、三次握手:发送端发起连接,声明发送的最大数据长度1480Bytes,初始序号是0,窗口大小是4K(表示接我的收缓冲区的还有4K的空闲大小,你发送的数据不要超过4K)。接收端应答请求连接,声明最大尺寸1024,初始序号8000,窗口大小6K。

2、发送端发送4~9,每个段带1K的数据,发送端根据接收端的窗口知道接收端的缓冲区已经满了,因此停止发送。

3、接收端的应用程序提走2K数据,发出段10,在应答已接收6K的数据同时,声明窗口大小为2K。

4.、接收端的应用程序又提走 2K 数据,接收缓冲区有 4K 空闲,接收端发出段 11,重新声明窗口大小为 4K。
5、发送端发出段 12-13,每个段带 2K 数据,段 13 同时还包含 FIN 位。
6、接收端应答接收到的 2K 数据(6145-8192),再加上 FIN 位占一个序号 8193,因此应答序号是 8194,连接处于
半关闭状态,接收端同时声明窗口大小为 2K。
7、接收端的应用程序提走 2K 数据,接收端重新声明窗口大小为 4K。
8、接收端的应用程序提走剩下的 2K 数据,接收缓冲区全空,接收端重新声明窗口大小为 6K。
9、接收端的应用程序在提走全部数据后,决定关闭连接,发出段 17 包含 FIN 位,发送端应答,连接完全关闭。
上图在接收端用小方块表示 1K 数据,实心的小方块表示已接收到的数据,虚线框表示接收缓冲区,因此套在虚线框中的空心小方块表示窗口大小,从图中可以看出,随着应用程序提走数据,虚线框是向右滑动的,因此称为滑动窗口。

从这个例子还可以看出,发送端是一 K 一 K 地发送数据,而接收端的应用程序可以两 K 两 K 地提走数据,当然也有可能一次提走 3K 或 6K 数据,或者一次只提走几个字节的数据。也就是说,应用程序所看到的数据是一个整体,或说是一个流(stream),在底层通讯中这些数据可能被拆成很多数据包来发送,但是一个数据包有多少字节对应用程序是不可见的,因此 TCP 协议是面向流的协议。而 UDP 是面向消息的协议,每个 UDP 段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据,这一点和 TCP 是很不同的。

标签: none

相关文章推荐

添加新评论,含*的栏目为必填