ip模块中存储的是一堆数字信号,网卡内部会把数字信号转换成电信号或者光信号在网线中传输。
网卡只是一个硬件,需要驱动程序去操作他,计算机中已经把主流网卡的驱动程序(不只是网卡的,还有鼠标,键盘这些硬件都需要驱动程序去操作运行)内置到计算机中了。
网卡的初始化
网卡和其他硬件一样,通上电之后需要完成初始化操作才能正常工作。
网卡mac模块设置mac地址
这些操作包括硬件错误检查、初始设置等步骤,这些步骤对于很多其他硬件也是共通的,但也有一些操作是以太网特有的,那就是在控制以太网收发操作的MAC模块中设置MAC地址。
mac地址会在网卡生产时写入网卡rom中。操作系统完成初始化之后,网卡的驱动程序会去读取网卡的mac地址并保存到自己mac模块中, 当完成这些初始化操作后就可以接受ip模块的委托了
mac模块的mac地址并不一定是网卡rom中的mac,也可以通过命令手动设置网卡mac模块的mac地址
组装控制信息
网卡的mac模块负责两部分:
1.驱动程序初始化时会取出网卡rom的mac地址并设置到mac模块之后填充。mac地址是tcpip模块从mac模块中取出的
2.ip协议通过本地路由表找到发送方的ip地址,并将数据传递给网卡,ip模块发送的数据会保存到网卡的缓冲区中;什么时候读取缓冲区进行数据发送呢? 网卡的mac模块会读取缓冲区数据 并将数字信号转换为通用信号并借助mai模块转换为网卡传输的数据格式并发送到网线中
添加报头起始帧和fcs
网卡会取出缓冲区的数据并切割,为每部分的头部填充包头和起始帧;尾部添加验证是否短缺的尾部(检测错误的帧校验序列)
为什么需要添加报头和起始帧呢?
报头
报头是一段长度为52bit, 01交替出现的数字信号,当用电信号来表示数字信号时,是通过高低电压的方式来判断的。其实他有一个作用是为了观察时钟信号的频率的(为了之后还原 原始数字信号的),之后讲解
起始帧
当56位的报头数据结束后,开始发送起始帧,起始帧末尾的两位都是1也就是末尾有两段是高电压,和之前的电路不同,因此当识别到这个不同的电路时,就知道接下来是真实的数据了,用来表示包起始位置的标记
起始帧后面就是ip模块发送的数据了(从网卡的缓冲区中取数据)
叠加时钟信号识别原始数据
但是真实的情况是并没有图中的那条界限去分割这些电信号(比如出现连续为1或连续为0的情况时接受方不知道该怎么切割信号还原),因此会将数字信号和时钟信号(时钟信号是固定频率固定信号)进行叠加然后发送,接收方只要知道了时钟信号的发送频率然后根据图中右下角的表和最终收到的信号对比就可以还原拿到原始的数字信号。
如何确定时钟信号的频率~报头
时钟信号是以10 Mbit/s或者100 Mbit/s这种固定频率进行变化的, 因此我们不能一开始就发送包的数据,需要观察一段时间时钟信号发送的频率。所以要在包前面加上一段用来测量时钟信号的特殊信号,这就是报头的作用。
「如果在包信号结束之后,继续传输时钟信号,就可以保持时钟同步的状态,下一个包就无需重新进行同步。有些通信方式采用了这样的设计,但以太网的包结束之后时钟信号也跟着结束了,没有通过这种方式来保持时钟同步,因此需要在每个包的前面加上报头,用来进行时钟同步。」
如何保持时钟信号同步_每个包头部都加报头
如果在包信号结束之后,继续传输时钟信号,就可以保持时钟同步的状态,下一个包就无需重新进行同步。有些通信方式采用了这样的设计,但以太网的包结束之后时钟信号也跟着结束了,没有通过这种方式来保持时钟同步,因此需要在每个包的前面加上报头,用来进行时钟同步。
fcs末尾校验序列
fcs用来检查包传输过程中因噪声导致的波形紊乱、数据错误,它是一串32比特的序列, 是根据包中所有的内容带入一个公式中计算出来的序列。当电信号中有一个比特位发生变化(可能是受到了电磁干扰,附近电信号的干扰)那么计算出来的值就会有变化。当接收方计算出来的fcs和发送方的fcs不一致时,就代表信号受到了干扰。
phy/mau模块发送网卡信号
添加完上面的三个控制信息后,接下来就开始发送包了,发送包的方式有两种:一种是使用集线器的半双工模式,一种是使用交换机的全双工模式。
发送和接收同时并行的方式叫作“全双工”,相对地,某一时刻只能进行发送或接收其中一种操作的叫作“半双工”。
如果是半双工模式,发送数据前需要判断网线中是否还存在其他设备发送的数据,如果有需要等待其他设备信号发送完毕再发送,否则会发生信号碰撞。
发送包是委托网卡中的mac模块进行发送数据,mac模块会从报头起始的地方到包末尾的所有内容都转换任意格式的通用信号,在借助phy模块或者mau模块把通用信号转换成可在网线中传输的格式。 phy模块还会检测网线中是否有信号在传输,只有没有的时候才会发送到网线上。
将数字信息转换为电信号的速率就是网络的传输速率,例如每秒将10 Mbit的数字信息转换为电信号发送出去,则速率就是10 Mbit/s。
根据以太网信号方式的不同,有些地方叫MAU(Medium Attachment Unit,介质连接单元),有些地方叫PHY(Physical Layer Device,物理层装置)。在速率为100 Mbit/s以上的以太网中都叫PHY。
以太网不会确认发送的信号对方有没有收到。根据以太网的规格,两台设备之间的网线不能超过100米,在这个距离内极少会发生错误,万一发生错误,协议栈的TCP也会负责搞定,因此在发送信号时没有必要检查错误。
阻塞信号
但是接收方还是可能会同时收到好几台设备的请求,虽然比万一还小但还是有一定几率发生碰撞,发生碰撞的时候在发送数据就没有意义了,因此会停止发送数据。
并且发送一个信号通知设备不用发信息了,这个信号就是阻塞信号,发送信息的设备会等待一段时间在进行发送,当然等待的时间肯定是不同的,不然还是会发生碰撞,等待的时间是根据MAC地址生成一个随机数计算出来的。
当网络非常阻塞时,可能等待之后还是会发生碰撞,每次发生碰撞都会延长一倍的等待时间进行重试,当重试达到十次时报告网络错误~
对比全双工模式发送信号的时候不需要考虑这么多,只管发送就行~
phy/mau模块接受网卡信号
转换为数字信号验证fcs
之前讲解集线器的时候说过使用集线器发送信号的话 集线器的所有网络设备都会接受到信号
接着phy/mau模块分析报头得知时钟信号的频率,利用时钟信号还原出原始的数字信号,当识别到起始帧时把数据转换成通用信号发送给mac模块(和发送相反 mac转换成通用信号发送给phy)
mac模块把通用信号再转换成数字信号放入缓冲区中,到达末尾时将从包开头到结尾的所有比特套用到公式中计算出FCS,然后和包末尾的FCS进行对比,正常情况下两者应该是一致的,如果中途受到噪声干扰而导致波形发生紊乱,则两者的值会产生差异,这时这个包就会被当作错误包而被丢弃。
验证接收方是否为目的地
当fcs一致时,检查包中的接收方mac信息是否和当前设备的mac地址一致,来判断这个包是不是发送给自己的。如果是发送给自己的则会把数据放入网卡的缓冲区中,这时候mac模块就会通知计算机收到了一个包。
有一个特殊的例子,其实我们也可以让网卡不检查包的接收方地址,不管是不是自己的包都统统接收下来,这种模式叫作“混杂模式” (Promiscuous Mode)。
发送中断信号处理缓冲区数据
mac模块将数据放入到缓冲区就会通知计算机去处理数据了,通知计算机是通过中断的机制处理的;
回到开始我们利用网卡发送数据的时候,计算机不可能一直等待网卡返回数据再去处理其他事情这样太效率太低了,因此计算机通知网卡发送数据后就去干别的事情去了;当网卡的数据回来之后,同样也需要暂停别的事情去处理网卡返回的缓冲区数据,那么计算机怎么知道网卡的数据回来了呢?答案是通过中断
中断机制
中断是有编号的,网卡安装的时候已经在硬件中设置了中断号, 在中断处理程序中将硬件的中断号和相应的驱动程序绑定。
中断处理程序绑定中断号并控制网卡读取数据到对应协议栈
当网卡插入计算机时,会给分配一个中断号并在中断处理程序中将中断号和对应的网卡驱动绑定。这样当网卡发起中断请时,
通过扩展总线的中断信号线发送信号,信号线通过中断控制器连接在cpu中。收到中断信号时cpu会挂起当前任务,切换到操作系统中的中断处理程序运行
中断处理程序会调用网卡驱动,将网卡缓冲区内的数据取出来,判断mac头部的以太类型填充到对应协议栈的缓冲区中(比如0800是tcpip,则把网卡缓冲区的数据放到tcpip协议栈,如果不存在对应的协议栈则放弃)
现在都是即插即用的中断号设置方式,不需要关心中断号,之前需要手动设置中断号因此出现了很多莫名其妙的问题
网卡不会关心包里的内容,只要按照以太类型将包交给对应的协议栈就可以了。接下来,协议栈会判断这个包应该交给哪个应用程序,并进行相应的处理。
协议栈处理错误
假如以太类型为0800,此时到达了tcp/ip协议栈。ip模块会取出ip头部的ip地址判断是否和本机中网卡的ip地址一致。
ip模块的mac头部用于在以太网中传输,ip头部用于在协议栈验证
如果一致就说明找到正确的目的地了,如果不一致,还需要看接收方操作系统:
客户端(windows,mac)和服务器操作系统不一样,服务器的操作系统如果ip地址不一致可以充当路由器的功能进行转发;而客户端的操作系统如果ip地址不一致是发生了错误,IP模块会通过ICMP消息将错误告知发送方。例如收到不是自己ip的包就会用3,这个表中列出了转发接受过程中遇到的错误
分片重组
网线和集线器中只能传输小包,所以会将一个大包拆分成多个小包,小包也叫分片,每个小包中都有一个分片的id,同一个包的分片具有相同的id。且每个小包的ip头部还有一个分片偏移量(fragment offets)代表当前分片在整个包中的偏移量
ip模块会将这些分片的小包存储到缓冲区中,当所有相同id的小包凑齐后根据偏移量进行拼接还原成大包。
协议栈将数据放入缓冲区,等待应用程序取出
ip模块还原出原始数据后,交给了tcp模块,tcp模块根据ip头部接收方发送方ip地址和tcp头部发送方接收方端口号找到对应的套接字,根据套接字的不同状态进行处理。如果包内容是应用程序放入缓冲区中等待应用程序取出,如果是控制信息类的包比如请求链接断开连接这种生成对应的包返回,然后通知应用程序这些状态即可。
tcp模块和ip模块看成一个整体,tcp模块越权检查ip头部信息,省去了和ip模块交互的逻辑提高效率。
此外,找到套接字需要发送方ip,接收方ip和发送接受方的端口, 之后讲解套接字机制讲解