上次大概的说了一下客户端和Web服务器的交互.
这一次记录一下客户端和Web服务器的连接和相互收发数据的具体流程.
为了看清楚连接的具体流程,我们先来看看TCP头部的具体格式
字段名称 | 长度(比特) | 含义 |
---|---|---|
发送方端口 号 | 16 | 发送网络包的程序的端口 |
接收方端口号 | 16 | 网络包接收方程序的端口 |
序号 (发送数据的顺序编号) | 32 | 发送方告知接收方该网络包发送的数据相当于所有发送数据的第几个字节 |
ACK号(接受数据的顺序编号) | 32 | 接收方告知发送方已经收到了所有数据的第几个字节 |
数据偏移量 | 4 | 表示数据部分的起始位置,也可以认为表示头部的长度 |
保留 | 6 | 未使用 |
控制位 | 6 | URG:表示紧急指针字段有效 |
ACK:表示接受数据序号字段有效,一般表示数据已经被接收方收到 | ||
PSH:通过flush操作发送的数据 | ||
RST:强制断开连接,用于异常中断的情况 | ||
SYN:发送方和接收方相互确认序号,表示连接操作 | ||
FIN:表示断开连接 | ||
窗口 | 16 | 接收方告知发送方窗口大小 |
校验和 | 16 | 检查是否出现错误 |
紧急指针 | 16 | 表示应急处理的数据位置 |
当一个TCP头部填充完毕后,会将TCP头部传送给网络层,网络层经过一系列处理,在加上IP后就可以进行发送,尝试连接了.当网络包到达服务器时,首先会匹配端口号 – 用自己TCP中的接收方端口号进行 端口号匹配.
上面写了TCP头部的序号字段用于发送数据的顺序编号,肯定的是–这个编号不能是固定值, 因为如果是固定值,会有几率被别人识别.对于数据不安全. 所以第一次发送请求连接之前,需要给定一个随机数作为序号值. 然后服务器收到后 会返回一个 ACK 值,用于数据确认,不仅发送ACK 值,服务器也要发送一个序号值,用于 客户端 数据确认. 当 客户端收到 服务器的 ACK值和 序号值,客户端也会返回一个ACK号用于确认数据. -------当这个操作完成后,则代表连接已经完成.
当游览器获得用户的输入后,就要向Web服务器发送自己所需要的信息.
先分析在客户端这边的操作:
首先,当协议栈收到数据并不是立即发送出去,而是先将数据存放在内部的发送缓冲区中.然后在交由协议栈发送出去.
问题来了:
- 协议栈是什么时候将数据发送出去的呢?
- 协议栈是怎样判断你的数据有没有写完?
假设:(1)
协议栈是已接收到数据时就开始发送,接受一点,发送一点.
这样的话,每次发送一点数据,会发送大量的数据包,从而造成网络堵塞.
假设:(2)
协议栈是接受一定的数据,达到这个数据量后 开始发送,这样就不会造成网络堵塞.
如果数据就只有一点,不够发送,协议栈就一直在等待数据,不会将数据发送出去.
假设:(3)
协议栈中有一个定时器,每当一定时间后,就会将数据发送出去,这样既不会造成网络堵塞,也不会造成数据发送不出去.
那么这个时间就是一个关键值了.
然后我们将假设(2)和假设(3) 结合起来,刚好解决这个发送数据的问题.
用一个定长缓冲区 + 一个定时器.
那么,这个时间是怎样来判断的呢?
其实,这个时间没有最准确的答案,因为不同的缓冲区长度和 数据的类型不确定. 在每一种类型下都有一个最佳 时间值.
所以 这个时间在不同的 协议栈中的 值是不同的.
这时,又有一个问题来了. 如果有一个数据长度 超过了缓冲区怎么办? 因为你缓冲区是定长的,总有一个数据的长度超过缓冲区的长度. 这时候如何处理?
这里我们引进 2 个概念. 一个网络包 由包头和消息体组成.
包头一般保存 收发放的端口号,序号,ACK号,窗口大小 …
MTU: 一个网络包的最大长度
MSS:去掉头部后,一个网络报所能容纳的TCP数据的最大长度
协议栈首先会对 数据进行拆分,将一个大数据拆分为 多个网络发送过去.这样就解决了无法发送大型数据包了.
问题又来了(总是问题~ ~ ~)
如果将一个大的数据进行拆分,网络包在数据传输过程中有快有慢,那么接收方怎样判断接收过来的网络包的顺序呢?
例如: 我们将一个字符串进行拆分发送, —“hello” ----> 发送为 h e l l o .
但是接收方接受的却是 “h l l e o”, 这样岂不是改变了数据?
这时候 包头起作用了.包头中有一个值 – 序号,它就是发送数据的顺序编号.
比如 h 的序号为 1
e 的序号为 2
l 的序号为 3 …
然后接收方按照顺序排列,组合数据.
除此之外,tcp协议 还有一个特点就是可以找回丢失的包.
当网络堵塞,或者网络不稳定难免出现丢包现象.那 tcp 是通过什么判定是否丢包了呢?
还是包头中的信息.包头中的 ACK号. 就是通过序号和ACK号来确定是否丢包了.
就是通过: 序号 + 数据长度 = ACK号.(当然这个过程也是很复杂的,后面再详细分析)
如果ACK号中间有缺失,就代表已经丢包了.这是 接收方就会通知发送方 重新发包.