【读书笔记-《网络是怎样连接的》- 5】Chapter2_4-网卡的工作过程
IP模块组装好的数据包,就可以交给网卡进行发送了。本篇就来介绍网卡在发送数据包时的工作过程。
1 以太网基础
以太网是一种为多台计算机能够彼此自由和廉价地相互通信而设计的通信技术,原型如下图所示。这种网络的本质其实是一根网线,通过收发器这种设备将不同网线之间的信号连接起来。
在这样的网络结构中,一台计算机发送的网络包会到达网络上所有其他的计算机。为了判断网络包是发送给谁的,增加了MAC头部,使用其中的MAC地址来判断网络包发送的目的地。这就是最初的以太网。
后来经过改进,先是有了中继式集线器结构,然后又有了交换式集线器的结构,如下图所示。
二者的区别在于中继式集线器结构中,网络包仍然会到达网络中所有的设备,而交换式集线器结构中,网络包只会发送给MAC地址对应的接收方。(中继式集线器简称为集线器,交换式集线器简称为交换机)。经过改进之后,以太网的3个性质仍然保持不变:通过MAC头部中的接收方MAC地址将网络包发送到目的地,通过MAC头部中的发送方MAC地址来识别发送方,通过以太类型识别包的内容。可以认为具备这三个性质的网络就是以太网。
2 网卡工作原理
2.1 网卡构成与初始化
IP模块生成的网络包还只是一串0和1的数字信息,需要通过网卡将数字信号转换为电信号或者光信号才能在网线上进行传输。网卡的主要工作过程如图所示,只代表其基本构成要素,并不代表实际的硬件构成。
与其他硬件一样,在操作系统启动时,网卡需要先由网卡驱动程序进行初始化后才能进入可以使用的状态。初始化过程包括硬件错误检查、初始设置等步骤,这些与其他硬件设备相同。还有一些以太网设备特有的初始化操作,如控制MAC模块中设置MAC地址。前面已经讲过,网卡的ROM中保存着网卡的MAC地址,将其读出就可以对MAC模块进行设置了。此外还有通过命令行或者配置文件设置网卡MAC地址的方法。真正生效的是网卡驱动程序初始化时在MAC模块中设置的MAC地址,可能与ROM中的MAC地址并不一致。
完成初始化操作后,网卡就可以进行网络包的收发操作了。
2.2 网络包结构
网卡驱动从IP模块接收到网络包之后,将其复制到网卡缓冲区内,然后通知MAC模块进行发送。
MAC模块将数据从缓冲区中取出后,首先会在开头加上报头和起始帧分界符,在末尾加上用于检测错误的FCS(帧校验序列),如下图所示。
报头是一串0和1交替出现的序列,长度为56比特,用于确定包的读取时机。为了理解报头的作用,先要说明如何通过电信号来读取数据。
用电信号表达数字信息时,需要用电信号的值对应0和1;而通过电信号读取数字信息,则是要从电信号中解析出0和1。为了判断出每个比特的分界线,需要在数据信号之外再发送一组时钟信号。在时钟的上升沿(或下降沿)时从数据信号中读取,根据值对应0或1就可以了。
这样产生了新问题。长距离传输时,网线较长,两根线路的长度会发生差异,数据信号和时钟信号会产生时间差。为了解决这个问题,可以采用将数据信号和时钟信号叠加在一起的方式。采用这种传输方式,我们需要从信号中找出时钟周期,从而提取出信号中的数据。报头的作用就在于此。在发送数据包前先发送一段用于测量时钟信号的特殊信号。
起始帧分界符则是用来表示包起始位置的标记。FCS用来检查包传输过程中可能出现的错误。它是一串32比特的序列,与CRC校验码一样,如果原始数据发生了变化,则FCS的值就会不同,从而可以判断数据发送过程中是否出现了错误。
2.3 网络包的发送
加上报头、起始帧分界符和FCS之后,网络包就可以通过网线发送出去了。有两种方式:使用集线器的半双工模式与使用交换机的全双工模式。全双工模式会在第三章详细介绍,这里来介绍一下半双工模式。
半双工模式中需要避免信号碰撞,因此发送前需要先判断网线中是否有其他设备发送的信号。如果有,则等待该信号传输完毕后再发送。发送过程中,MAC模块将数字信息转换为电信号,再通过称为PHY或者MAU的信号收发模块发送出去。
PHY(MAU)还需要监控接受线路中是否有信号进来。在开始发送前需要先确认没有其他信号进来,才能开始发送。在信号开始发送到发送结束的这段时间内没有信号进来,发送操作就完成了。也有很小的可能会出现多个设备同时发送网络包的情况,这时候就会发生信号碰撞。此时设备会停止发送,还会发送一段时间的阻塞信号,通知其他设备。
等待一段时间后,设备会再次重新发送。但如果所有设备都等待同样的时间,仍然会发生碰撞。因此会根据MAC地址生成一个随机数,等待随机的时间。在网络拥塞的时候,发生碰撞的可能性会提高,这样每次发生碰撞之后,就将等待时间延长一倍,以此类推。多次尝试仍然不行,就上报错误信息。
2.4 接收返回包
接下来来看网络包接收时的操作方式。在半双工模式中,一台设备发送的信号会到达集线器上的所有设备,接收操作的第一步就是将所有信号都接收过来。
接下来的操作与发送步骤相反。先通过报头同步时钟,然后将起始帧分界符后面的信号转换为数字信息。PHY(MAU)模块先将信号转换为通用格式,发送给MAC模块,MAC模块再将信号转换为数字信息,存放在缓冲区中。在存入缓冲区之前,MAC模块会检查FCS,如果FCS有问题,则直接丢弃这个包。如果没有问题,则检查MAC头部中的MAC地址是否与网卡初始化时分配给自己的MAC地址一致,如果不同,也直接丢弃。如果MAC地址一致,才会存入缓冲区中,并通过中断通知操作系统收到网络包。中断程序会调用网卡驱动,从网卡的缓冲区中取出收到的包,并通过MAC头部中的以太类型字段判断协议的类型。根据前一篇的内容,返回0800表示TCP/IP协议栈,于是下面会交给IP模块进行处理。
IP模块先是检查IP头部,格式没有问题则会检查IP头部中的接收方IP。客户端计算机不会进行包转发操作,因此如果IP头部中的接收方IP与自己的IP不一致,一定是发生了错误,IP模块会通过ICMP消息将错误告知发送方。
如果IP正确,则这个包会被接收下来。IP模块还有一项工作,即将分片的包还原成原始的包。关于分片功能,会在第三章详细介绍。分片的包会在IP头部的标志字段中进行标记,同一个包的分片具有相同的ID。此外IP头部的分片偏移量字段则表示了此分片在整个包中所处的位置。根据这些信息,在所有分片收到之后,就可以还原成原始的包了。接下来交给TCP模块进行处理。
3 UDP协议收发操作
前面详细讲解了TCP协议,这里简单介绍一下UDP协议。
TCP设计的复杂,是为了将数据高效且可靠地发送给对方,确保只重发出错或者未收到的包。但在数据很短的情况下,其实不用TCP这样复杂的机制,也可以高效地重发数据。如果只有一个包,发生了错误只要直接重发就好了,不必建立连接与断开连接的控制包。而发送数据后,将对方的回复作为接收确认也就可以了,也不再需要专门的接收确认包了。
这种情况下适用的就是UDP协议。UDP没有TCP的接收确认,窗口等机制,在发送时只需要将数据加上UDP头部,然后交给IP模块发送就可以了。
另一个使用UDP的场景是发送音视频数据的时候。音视频数据需要在确定的时机到达,如果错过了时机,再重发也没有用了。音视频播放过程中出现一些包的丢失可能只是产生一些失真或卡顿,一般也是可以接受的。
到这里第二章协议栈与网卡的部分就整理完毕了。下一章将会继续介绍网络包如何经过集线器、交换机与路由器等设备到达互联网。