探索服务器内部——服务器的接收操作

1、网卡将接收到的信号转换为数字信号:

到达服务器的网络包其本质是电信号或者光信号,接收信号的过程和客户端其实是一样的。具体过程在之前的文章中已经介绍过,这里简单回顾一下。

接收操作的第一步是网卡接收到信号,然后将其还原成数字信息。局域网中传输的网络包信号是由1和0组成的数字信息与用来同步的时钟信号叠加而成的,因此只要从中分离出时钟信号,然后根据时钟信号进行同步,就可以读取并还原出1和0的数字信息了。

接下来需要根据包末尾的帧校验序列(FCS)来校验错误,即根据校验公式(以太网中使用CRC-32方式计算)计算刚刚接收到的数字信息,然后与包末尾的FCS值进行比较,从而判断出接收到的数字信息是否存在错误。如果接收的包是无效的,就需要丢弃。当FCS一致,接下来需要检查MAC头部的接收方MAC地址,看看这个包是不是发给自己的。如果包的接收者不是自己,那么就需要丢弃这个包。如果都没有问题,那么还原后的数字信息就会被保存在网卡内部的缓冲区中。上面这些操作都是由网卡的MAC模块来完成的。

在这个过程中,服务器的CPU并不是一直在监控网络包的到达,而是在执行其他的任务,因此CPU并不知道此时网络包已经到达了。因此,网卡需要通过中断将网络包到达的事件通知给CPU。然后CPU就会暂停当前的工作,并切换到网卡任务。然后,网卡驱动会开始运行,从网卡缓冲区中将接收到的包读取出来,根据MAC头部的以太类型字段判断协议的种类,并调用负责处理该协议的软件。这里,以太类型的值应该是表示IP协议,因此会调用TCP/IP协议栈,并将包转交给它(网卡驱动并不会直接调用协议栈,而是先切换回操作系统,然后再由操作系统去调用协议栈,由协议栈继续执行接收操作)。

2、IP模块的接收操作:

IP模块首先会检查IP头部的格式是否符合规范,然后检查接收方IP地址,看包是不是发给自己的。当服务器启用类似路由器的包转发功能时,对于不是发给自己的包,会像路由器一样根据路由表对包进行转发(也可以启用类似防火墙的包过滤功能)。

确认包是发给自己的之后,接下来需要检查包有没有被分片。检查IP头部的内容就可以知道是否分片,如果是分片的包,则将包暂时存放在内存中,等所有分片全部到达之后将分片组装起来还原成原始包;如果没有分片,则直接保留接收时的样子。

接下来需要检查IP头部的协议号字段,并将包转交给相应的模块。例如,协议号为06(十六进制),则将包转交给TCP模块;如果是11(十六进制),则转交给UDP模块。这里假设这个包被转交给TCP模块。

3、TCP模块如何处理连接包:

当TCP头部中的控制位SYN为1时,表示这是一个发起连接的包。这时,TCP模块会执行接受连接的操作,不过在此之前,需要先检查包的接收方端口号,并确认在该端口号上有没有与接收方端口号相同且正在处于等待连接的套接字。如果没有,则向客户端返回错误通知的包(一个表示接收方端口不存在等待连接的套接字的ICMP消息)。

如果存在,则为这个套接字复制一个新的副本,并将发送方IP地址、端口号、序号初始值、窗口大小等必要的参数写入这个套接字中,同时分配用于发送缓冲区和接收缓冲区的内存空间。然后生成代表接收确认的ACK号,用于从服务器向客户端发送数据的序号初始值,表示接收缓冲区剩余容量的窗口大小,并用这些信息生成TCP头部,委托IP模块发送给客户端。

这个包到达客户端之后,客户端会返回表示接收确认的ACK号,当这个ACK号返回服务器后,连接操作就完成了。

这时,服务器端的程序应该进入调用accept的暂停状态,当将新套接字的描述符转交到服务器程序之后,服务器程序就会恢复运行。

4、TCP模块如何处理数据包:

首先,TCP模块会检查收到的包对应哪个套接字。然后,TCP模块会对比该套接字中保存的数据收发状态和收到的包的TCP头部中的信息是否匹配,以确认数据收发操作是否正常。当收到的数据进入接收缓冲区后,TCP模块就会生成确认应答的TCP头部,并根据接收包的序号和数据长度计算出ACK号,然后委托IP模块发送给客户端。

接下来,应用程序会调用Socket库的read来获取收到的数据,这时数据会被转交到应用程序。然后,控制流程会转移到服务器程序,对收到的数据进行处理,也就是检查HTTP请求消息的内容,并根据请求的内容向浏览器返回相应的数据。

5、TCP模块的断开操作:

在TCP协议的规则中,断开操作可以由客户端或服务器任何一方发起,具体的顺序是由应用层协议决定的。Web中,这一顺序随HTTP协议版本的不同而不同,在HTTP1.0中,是服务器先发起断开操作。

这时,服务器程序会调用Socket库的close,TCP模块会生成一个控制位FIN为1的TCP头部,并委托IP模块发送给客户端。当客户端收到这个包之后,会返回一个ACK号。接下来客户端调用close,生成一个FIN为1的TCP头部发给服务器,服务器再返回ACK号,这时断开操作就完成了。HTTP1.1中,是客户端先发起断开操作,这种情况下只要将客户端和服务器的操作颠倒一下就可以了。

无论哪种情况,当断开操作完成后,套接字会在经过一段时间后被删除。

Guess you like

Origin blog.csdn.net/qq_38386085/article/details/104458418