TCP/IP数据传输
创建套接字
协议栈
协议栈上半部分有两块:
- TCP协议(安全可靠 不丢包)
- UDP协议(不安全,会丢包,不建立连接)
协议栈下半部分: - IP协议:控制网络包收发操作
- ICMP协议:用于告知网络包传输过程出现的错误以及控制信息(目标IP等)
- ARP协议:用于根据IP地址查询以太网MAC地址
连接过程
所谓的连接过程,其实就是通信双方交换控制信息,例如客户端把自己的IP地址端口号告知服务端等等。
TCP 头部
头部主要是用来记录和交换控制信息的。
- TCP头部有20个字节
- 发送方端口号
- 接收方端口号
- 序号seq:发送方告诉接收方发送的数据相当于所有数据的第几个字节
- ACK:接收方告诉发送方已经收到所有数据的第几个字节
- 控制位
- ACK 表示数据已经接收到
- SYN 连接操作
- FIN 表示断开连接
- 窗口:接收方告诉发送方窗口大小(也就是能够处理多少数据)
3次招手
上图可以看出。在TCP协议中,三次握手主要需要让对方都知道自己发送数据的初始Seq并且确认双方都确认知道。双方都知道彼此的接收能力都是OK的。
收发数据
协议栈处理HTTP消息
- 协议栈在接收到应用程序的数据的时候并不会马上发送出去,会等待下一段数据,拼接后发送。因为防止出现大量小包发送导致网络拥堵。
- 协议栈主要通过两个要素来判断是否发送
- 网络包能容纳的数据长度MTU以及实际数据大小MSS
- 时间:会有一个计时器,到达一定时间之后,即使长度没有接近MSS也会发送
较大数据的拆分
如果数据量过大,发送缓冲区的数据就会超过MSS的长度,这个时候会将数据按照MSS长度进行拆分。每一块数据前面都会加上TCP头部。
- 最后会通过“序号(seq)”和“ACK”可以确认接收方是否收到网络包。
自动调节ACK等待时间
如果网络传输繁忙的时候就会发生拥塞,ACK返回会变慢。这个时候就需要将等待时间设置长一点,不然重复发包会使网络雪上加霜。
由于网络波动,那么就需要自动调节等待时间。TCP会在发送数据的过程中测量ACK返回时间做出相对应的处理。如果ACK慢就加长等待时间,如果快就缩短。
ACK 和窗口的合并
解决ACK和更新窗口大小的时机。
- 首先我们没必要每一次都向发送方更新窗口大小,因为发送方可以自行减去自己已发送的长度就可以计算出来。所以,更新时机应该是接收方从缓冲区取出数据的时候。
- ACK会等待一段时间,无需每一个都返回ACK,因此在连续发送ACK的时候只需要发送最后一个ACK就够了。只需要发送最终的结果是为了防止过多小包使网络拥堵。
断开连接
CLOSE_WAIT 状态
在被动关闭连接情况下,在已经接收到FIN,但是还没有发送自己的FIN的时刻,连接处于CLOSE_WAIT状态。
通常来讲,CLOSE_WAIT状态的持续时间应该很短,正如SYN_RCVD状态。但是在一些特殊情况下,就会出现连接长时间处于CLOSE_WAIT状态的情况。
出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket链接,但是我方忙与读或者写,没有关闭连接。
TIME_WAIT 状态
- 为实现TCP全双工连接的可靠释放
假设发起主动关闭的一方(client)最后发送的ACK在网络中丢失,由于TCP协议的重传机制,执行被动关闭的一方(server)将会重发其FIN,在该FIN到达client之前,client必须维护这条连接状态,也就说这条TCP连接所对应的资源(client方的local_ip,local_port)不能被立即释放或重新分配,直到另一方重发的FIN达到之后,client重发ACK后,经过2MSL时间周期没有再收到另一方的FIN之后,该TCP连接才能恢复初始的CLOSED状态。
如果没有这个状态,如果直接close 那么如果另一个使用这个端口会直接接收到FIN
TIME_WAIT 状态 危害
如果太多的TIME_WAIT 状态 那么会占用很多端口。
IP与以太网的包收发操作
TCP模块在执行连接,收发,断开等阶段我们都需要IP模块将其作为一个包装。
在数据传输的过程中,我们需要将数据在子网之间来回传送直到到达目标IP地址服务器。子网中主要有两种不同的转发设备,路由器和集线器。
- 路由器是根据目标IP地址判断下一个路由器的位置
- 集线器在子网在将网络包传输到下一个路由器。
实际上,集线器是一个按照以太网传输包的设备,因此,我们只有ip是不够的,我们需要知道下一个路由器的Mac地址,我们才可以把数据发送给下一个路由器。所以我们可以这样理解:
- IP协议是根据目标地址判断下一个IP转发设备的位置。
- 子网的以太网协议是将包传输到下一个转发设备。
IP头部 和 Mac头部
- 我们会先将包的目的地的IP写入IP协议
- IP协议会根据我们的目标IP地址去寻找传输方向(下一个路由器)
- 由于我们要把数据传输给下一个路由器需要通过以太网协议,那么就要获取到下一个路由器的mac地址(通过ARP广播的形式)