16.1.2 内核中网络部分流程简介
网络协议栈是由若干个层组成的,网络数据的流程主要是指在协议栈的各个层之间的传递。在第7.2节里介绍了TCP网络编程的流程,一个TCP服务器的流程按照建立socket(),绑定(bind())地址端口,侦听端口listen(),接收连接accept(),发送数据send(),接收数据recv(),关闭socket()的顺序来进行。与此对应内核的处理过程也是按照此顺序进行的,网络数据在内核中的处理过程主要是在网卡和协议栈之间进行:从网卡接收数据,交给协议栈处理;协议栈将需要发送的数据通过网络发出去。
图16.3总结了各层间在网络输入输出时的层间调用关系。由图中可以看出,数据的流向主要有两种。应用层输出数据时,数据按照自上而下的顺序,依次通过插口层、协议层和接口层;当有数据到达的时候,自下而上依次通过接口层、协议层和插口层的方式,在内核层传递。
图16.3 网络输入输出的各层间调用
应用层的Socket的初始化、绑定(bind)、销毁通过调用内核层的socket()函数进行资源的申请、销毁。
发送数据的时候,将数据由插口层传递给协议层,协议层在UDP层添加UDP的首部、TCP层添加TCP的首部、IP层添加IP的首部,接口层的网卡则添加以太网相关的信息后,通过网卡的发送程序发送到网络上。
接收数据的过程是一个相反的过程,当有数据到来的时候,网卡的中断处理程序将数据从以太网网卡的FIFO对列中接收到内核,传递给协议层,协议层在IP层剥离IP的首部、UDP层剥离UDP的首部、TCP层剥离TCP的首部后传递给插口层,插口层查询socket的标示后,将数据送给用户层匹配的socket。
图16.4为Linux内核层的网络协议栈的架构视图。最上面是用户空间层,应用层的程序位于此处。最底部是物理设备,例如以太网网卡等,提供网络数据的连接、收发。中 间是内核层,即网络协议栈子系统。流经网络栈内部的是socket缓冲区(由结构sk_buffs接连),它负责在源和汇点之间传递报文数据。在16.1.4节中会对sk_buff 的结构进行介绍。
图16.4 Linux内核网络协议栈架构
顶部(参见图16.4)是系统调用接口,它为用户空间的应用程序提供了一种访问内核网络子系统的接口。位于其下面的是一个协议无关层,它提供了一种通用方法来使用底层传输层协议。然后是实际协议,在Linux中包括内嵌的协议TCP、UDP,当然还有IP。然后是另外一个网络设备协议无关层,提供了与各个设备驱动程序通信的通用接口,最下面是设备驱动程序本身。