源/目的端口号:表示数据是从哪个进程来,到哪个进程去;
32位序号/32位确认号:后面详细讲;
4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最大长度是15 * 4 = 60
6位标志位:
URG:紧急指针是否有效
ACK:确认号是否有效
PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段
SYN:请求建立连接;我们把携带SYN标识的称为同步报文段
FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段
16位校验和:发送端填充,CRC校验。接收端校验不通过,则认为数据有问题。此处的检验和不光包含TCP首部,也包含TCP数据部分
16位紧急指针:标识哪部分数据是紧急数据
TCP对数据传输提供的管控机制,主要体现在两个方面:安全和效率。
这些机制和多线程的设计原则类似:保证数据传输安全的前提下,尽可能的提高传输效率
TCP将每个字节的数据都进行了编号。即为序列号
每一个ACK都带有对应的确认序列号,意思是告诉发送者,我已经收到了哪些数据;下一次你从哪里开始发
主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B;
如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发
TCP 要想保证可靠传输的前提就是网络通信是否通畅, "三次握手"机制就是用来验证网络通信是否通畅, 以及验证每个主机的发送能力和接收能力是否正常.
"三次握手"的每一步都有自己的用处:
除此之外, 通信的时候也涉及到一些需要双方保持一致的参数也可以通过"三次握手"协商.
综上所述, "三次握手"的作用主要就是两方面:
"四次挥手"的流程和"三次握手"非常相似, 经历过"四次挥手"之后连接就会断开, 双方就可以把各自保存的对方的信息的空间释放了.
网上很常见的一些面试题:
"四次挥手"可不可以三次完成?
"四次挥手"有的时候确实可以三次完成, 但是有的时候中间这两次不一定能合并.
因为 FIN 是通过应用程序的代码控制的, 而 ACK 是由内核控制的, 当收到 FIN 请求时会立刻返回 ACK, 但是由于程序可能没执行完所以不会立刻返回 FIN, 所以中间这两次不一定能合并.
如果服务器实在不发送 FIN 客户端连接就一直不会关闭吗?
当服务器接收到 FIN 请求就会转换成 CLOSE_WAIT 状态, 此时站在服务器的角度, 虽然连接没有关闭但是已经不能正常使用了. 如果缓冲区还有数据仍然可以正常读到但是如果进行写操作就会触发异常. 站在客户端角度, 如果经过一段时间的等待还是没有收到服务器的 FIN 请求就会单方面释放连接. 所以并不会一直不关闭.
如果通信过程中出现丢包怎么处理?
"三次握手"和"四次挥手"也带有重传机制, 会尽可能的重传, 如果连续多次重传失败就会单方面释放连接. 但是有一点需要注意的是: 最后一个 ACK 也有可能丢包, 所以当客户端发出去最后一个 ACK 时不能立即释放连接, 而是需要等待一段时间之后对方没有重传 FIN 才可以释放.(一般是等待网络是任意两点之间传输数据的最大时间 * 2)
刚才我们讨论了确认应答策略,对每一个发送的数据段,都要给一个ACK确认应答. 收到ACK后再发送下一个数据段. 这样做有一个比较大的缺点,就是性能较差。尤其是数据往返的时间较长的时候.
既然这样一发一收的方式性能较低,那么我们一次发送多条数据,就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了).
和之前的方式不同, 滑动窗口是一次性发出一组数据, 在这一组数据发送的过程中不需要等待 ACK, 此时就相当于一份等待时间等四个 ACK.
一次发送数据的大小称为"窗口".
"窗口"越大批量发送的数据就越多, 效率就越高, 但是不能无限大, 那样就相当于完全不用等 ACK就和不可靠传输差不多了.
当然, 在数据传输的过程中也会发生"丢包"此时就会分为以下两种情况:
滑动窗口虽然能提高效率但是如果窗口太大就可能导致接收方或者传输中间的链路处理不过来就会产生丢包, 反而影响了效率. 流量控制就是给滑动窗口加个现在避免窗口太大导致接收方处理不过来.
因此, 流量控制就是根据接收方的处理能力来限制发送方的发送速度(窗口大小)
流量控制是根据接收缓冲区的剩余空间大小来作为衡量的指标
接收方在返回 ACK 报文时就会把接收缓冲区剩余大小反馈给发送方, 作为下一次发送数据窗口大小的参考依据.
当我们看的该数据只有 16 位时不免会感到疑惑, 这里大小只有 16 位是不是就代表窗口大小最大就是 16? 其实不然, 在选项中有一个选项, 是窗口大小扩展因子, 实际窗口大小是 16 位窗口大小 << 扩展因子, 此时就可以使能够表示的窗口大小就非常大了.
当接收缓冲区满了 A 会停止发送数据, 但是由于不知道多会有空闲空间, 所以就会周期性发送 “窗口探测包”(不会携带具体数据)只是为了触发 ACK(查询当前接收缓冲区情况), 当发现有空闲空间就会发送数据.
接收方可以通过窗口大小反向控制发送方传输数据.