Linux网
络协议栈
从上述⽹络协议栈,可以看出:
收发流程
⽹卡是计算机⾥的⼀个硬件,专⻔负责接收和发送⽹络包,当⽹卡接收到⼀个⽹络包后,会通过
DMA
技术,将⽹络包放⼊到 Ring Buffer
,这个是⼀个环形缓冲区。
1
、发送
⾸先,应⽤程序会调⽤
Socket
发送数据包的接⼝,由于这个是系统调⽤,所以会从⽤户态陷⼊到内核态中的Socket 层,
Socket
层会将应⽤层数据拷⻉到
Socket
发送缓冲区中。
接下来,⽹络协议栈从
Socket
发送缓冲区中取出数据包,并按照
TCP/IP
协议栈从上到下逐层处理。
如果使⽤的是
TCP
传输协议发送数据,那么会在传输层增加
TCP
包头,然后交给⽹络层;
⽹络层会给数据包增加
IP
包,然后通过查询路由表确认下⼀跳的
IP
,并按照
MTU
⼤⼩进⾏分⽚。 分⽚后的⽹络包,就会被送到⽹络接⼝层,在这⾥会通过 ARP
协议获得下⼀跳的
MAC
地址,然后增加帧头和帧尾,放到发包队列中。
这⼀些准备好后,会触发软中断告诉⽹卡驱动程序,这⾥有新的⽹络包需要发送,最后驱动程序通过
DMA
,从发包队列中读取⽹络包,将其放⼊到硬件⽹卡的队列中,随后物理⽹卡再将它发送出去。
2
、接收
为了解决频繁中断带来的性能开销,
Linux
内核在
2.6
版本中引⼊了
NAPI
机制,它是混合「中断和轮询」的⽅式来接收⽹络包,它的核⼼概念就是不采⽤中断的⽅式读取数据,⽽是⾸先采⽤中断唤醒数据接收的服务程序,然后poll 的⽅法来轮询数据。
⽐如,当有⽹络包到达时,⽹卡发起硬件中断,于是会执⾏⽹卡硬件中断处理函数,中断处理函数处理完需要「暂时屏蔽中断」,然后唤醒「软中断」来轮询处理数据,直到没有新数据时才恢复中断,这样⼀次中断处理多个⽹络包,于是就可以降低⽹卡中断带来的性能开销。
软中断会从
Ring Buffer
中拷⻉数据到内核
struct sk_buff
缓冲区中,从⽽可以作为⼀个⽹络包交给⽹络协议栈进⾏逐层处理。
⾸先,会先进⼊到⽹络接⼝层,在这⼀层会检查报⽂的合法性,如果不合法则丢弃,合法则会找出该⽹络包的上层协议的类型,⽐如是 IPv4
,还是
IPv6
,接着再去掉帧头和帧尾,然后交给⽹络层。到了⽹络层,则取出
IP
包,判断⽹络包下⼀步的⾛向,⽐如是交给上层处理还是转发出去。
当确认这个⽹络包要发送给本机后,就会从
IP
头⾥看看上⼀层协议的类型是
TCP
还是
UDP
,接着去掉
IP
头,然后交给传输层。
传输层取出
TCP
头或
UDP
头,根据四元组「源
IP
、源端⼝、⽬的
IP
、⽬的端⼝」 作为标识,找出对应的Socket,并把数据拷⻉到
Socket
的接收缓冲区。
最后,应⽤层程序调⽤
Socket
接⼝,从内核的
Socket
接收缓冲区读取新到来的数据到应⽤层。