网络小结二:TCP/IP

一、协议栈的内部结构

协议栈的大致结构为:

TCP UDP

IP ICMP ARP

网卡驱动

网卡

套接字的实质:当浏览器调用系统的Socket库创建套接字时,其实是操作系统分配了一块内存地址用于保存通信相关的控制信息:通信双方的IP地址、端口号,当前的状态(连接、断开等),并返回一个对应的描述符给浏览器(描述符可以理解为Java中的引用),浏览器或其他的应用使用描述符来委托操作系统进行通信操作,系统根据描述符找到对应的套接字,从而获取到套接字内保存的相关信息进行后续操作。

连接的实质:其实在客户端和服务器之间并不存在一个实际的连接。连接的本质是客户端套接字和服务端套接字交换必要的控制信息:初始序号、双方的IP端口、窗口大小等信息。

二、TCP连接的三次握手:

1、首先客户端生成控制头信息,将SYN控制位置1(代表连接),生成自己的初始序号并写入头信息中(随机生成而不是从1开始,为了安全),同时附带双方的端口号信息,客户端的窗口信息

2、服务端接收信息,计算出自己的序号,将控制位ACK置1,同时计算出ACK号(ACK号为序号加上数据长度),同时附带服务端的窗口信息,写入控制头中返回给客户端

扫描二维码关注公众号,回复: 3245697 查看本文章

3、客户端接收后,将ACK状态位置1并返回ACK号给服务器,服务器接收到此应答后,连接才最终完成。

为什么不是两次握手?:防止网络拥塞导致的时延问题。假设客户端的第一次握手请求在网络的某个节点产生了拥塞,客户端收不到应答的情况下会再次发送握手请求。如果此时连接建立完成并且通信结束客户端和服务器端已经断开连接了,此时,第一次拥塞的握手请求到达服务器,服务器再次建立好连接,并返回响应给客户端(两次握手的情况下,已经建立好了连接),服务器会等待客户端发送消息,而其实客户端根本不会发送消息。这种情况会造成服务端资源的浪费,因而,服务器端收到第三次握手的确认才视为连接建立完毕,如果收不到第三次握手的信息,服务端会废弃此次连接。

三、数据的收发操作

浏览器将数据通过套接字传递给协议栈时,协议栈并不会立即将数据发送出去,而是会先将数据存储在缓冲区中,等待合适的时机再将数据发送出去,这样可以避免网络中有很多的小包,提升网络的效率。

那发送数据的时机怎么判断呢?主要有两点:

1、大小,缓存数据达到合适大小时发送,协议栈会根据MTU参数来判断。MTU表示一个网络包的最大长度,在以太网中是1500字节,这个长度包含了控制头的长度(IP头、TCP头),实际的数据包最大长度是MSS(即MTU减去控制头的长度)。当缓存数据的长度超过或者接近MSS时再发送出去,可以避免发送大量小包的问题。

2、时间,当应用程序发送效率不高时,如果还是等待达到合适的长度再发送出去会造成较长的延时,效果也不理想。因此,协议栈内部会有一个计时器,当达到合适的时间时,也会将数据发送出去。(这个时间以ms为单位,并不会很长。)

矛盾:发送数据的这两个条件本身是相互矛盾的。协议栈本身并没有做出相应的平衡,具体的控制其实是协议的开发者来完成的。因为很难做到有效的平衡,因此协议栈给应用程序保留了控制发送时机的余地。像浏览器这种会话型应用,对实时性要求很高,会要求协议栈不使用缓存而是直接发送数据。

当缓存中的数据超出MSS的长度怎么办呢?TCP会以MSS的长度为单位,将缓存的数据拆分成多个网络包,然后给每个网络包加上TCP头部,之后将其转交给IP协议进行发送。

发送的实际过程:发送一个网络包时,TCP头部中会携带 序号字段,代表了发送数据的开始序号,服务端TCP收到这个数据包时,在对数据包进行校验并确认数据包没有问题时,会将ACK控制位置1并计算出ACK号(序号+数据长度)返回给客户端,客户端收到了ACK号,便知道了 ACK号之前的数据发送成功。(TCP将数据包发送出去后,不会丢弃数据包,而是将数据包保存到缓存中,以防止一定时间内收不到 ACK应答信号,需要重新发送相应的网络包,这就是TCP的错误重传机制)

发送方和接收方的速率匹配问题:如果收发数据时,发送方总是等接收到接收方返回的ACK信号之后,才开始下一步的发送,中间等待的这段时间其实浪费掉了,导致效率不高。所以常用的方式是发送完成之后立马开始下一次发送,而不是等待接收ACK应答信号。但是这种方式会导致一个问题:当发送方和接收方速率不匹配时,如果发送方发送速率高于接收方处理速率,会导致在接收方的缓存空间满了之后,发送方发送的后续包无法被接收。只有当发送方和接收方速率相匹配时,网络才能被最高效的利用。

滑动窗口机制:滑动窗口机制用来匹配发送方和接收方的发送和接收速率。TCP头部有一个 窗口字段,用来告诉发送方 接收方的缓存剩余空间大小,然后发送方就可以根据窗口字段连续发送相应数量的数据包,这样就匹配了双方的速率。当接收方缓冲区的数据被取出时,接收方会在给发送方的应答中更新窗口信息,告知发送方可以继续发送相关数据。

四、接收完成之后的断开操作

当双方通信完毕时,服务端和客户端便会开始进行端口操作。在HTTP1.0中,一般是服务端在发送完成数据之后,会主动断开连接;而HTTP1.1中,由于增加了connection头,可以设置keep-alive建立客户端和服务器之间的长连接,这时断开操作一般由客户端发起。

断开操作(TCP四次挥手):假设A、B两端完成通信,A首先发起断开操作,将控制头中的FIN位置1,代表进行断开操作,B收到之后,回应ACK号;其次,B也会发送一个只有头信息的包,将FIN位置1,A收到之后应答ACK。至此,双方都已经进入断开状态。

但是,断开操作完成之后客户端不会立马删除套接字,而是要等待一段时间之后删除。原因:网络延迟问题,如果服务端发起断开操作,客户端收到后应答ACK号,而ACK号在传输的过程中由于网络问题堵在了某个节点。服务器端一段时间后未收到ACK应答,会重新发送一个断开请求。如果客户端应答ACK号之后立马删除了套接字,并且恰好这个端口创建了一个新的套接字建立了新的连接,然后收到了服务器重新发过来的断开请求,导致新的连接直接进入断开阶段(造成了结果不可预知的误操作)。

五、包

一个网络包由 头信息和消息体两部分组成。以TCP为例,数据到达TCP层时,会被拆分成大小固定的数据包,然后在前面加上TCP头(保存双方端口,序号,窗口,以及SYN、FIN、RST、ACK等控制位信息),然后TCP会委托IP进行包的转发操作。IP协议会为 包添加上对应的IP头(并不是一个互联网设备一个IP,而是一张网卡一个IP,一个设备可能有多个IP地址)和MAC头(MAC地址是网卡出厂时写死在网卡的ROM中的,开机之后由网卡驱动读取并保存在内存中)。IP协议会根据目的IP地址,查询路由表寻找要转发到的路由器地址,然后根据ARP(地址解析协议,查找对应IP地址的MAC地址,方法简单粗暴:在局域网中发送一个广播,然后等待对应IP地址的设备应答自己的MAC地址,有缓存机制,缓存一段时间之后会清空缓存重新请求)查询到对应的MAC信息,并填写到MAC头中的接收端MAC地址中。这样,以太网设备:交换机、路由器等便可以将其传输到对应的设备。到达对应的设备之后,就重复之前的过程,改写MAC头信息,一直到包到达网络设备为止。

六、UDP

与TCP相比,UDP很简单很迅速但可靠性差。

常用场景:DNS基于UDP;视频音频的传输可以基于UDP,因为如果某几个包丢掉,没必要重传(播放时间已经过了,重传没有意义),并且丢几个包并不会影响音视频的播放。

猜你喜欢

转载自blog.csdn.net/weixin_37882382/article/details/80413496
今日推荐