TCP/IP详解卷二实现:第一章:概述

第一章概述主要讲述了一个执行发送消息和接受消息的UDP程序,内核经历了哪些事。其中发送和接受的数据都存储在mbuf这个数据结构。

1.UDP示例程序

其中主要的三个系统调用为socket、sendto、recvfrom

socket引出了描述符、sendto引出了输出处理、recvfrom引出了输入处理。

2. 描述符

当调用socket后,会返回一个描述符fd

我们知道,对于文件系统中,fopen函数也会返回一个描述符,描述符指向进程已打开的文件结构,文件结构指向该文件的inode,而inode则存储着该文件的数据所在磁盘的扇区号。

对于网络,socket会返回一个描述符,描述符指向一个文件结构,文件结构不再指向一个inode而是socket,socket中so_type如果是UDP类型,那么so_pcb则指向一个存储所有UDP数据报的PCB的双向队列。

3. 输出处理

输出指的是示例程序调用sendto,本机利用内存mbuf结构封装UDP数据报,然后从传输层到物理层,层层封装,输出到其他电脑(本例其他电脑依然指的是本机)。

处理模块的顺序如图

显然插口层与TCP/IP协议无关。

3.1 插口层

首先sendto中传入的参数有目的ip、目的端口号、以及需要输出的数据。

根据传入的参数,插口层将目的ip、目的端口号存储在一个mbuf中,如下图

将需要传输的150字节数据存储在一个mbuf链表中,如下图

3.2. UDP输出例程

插口层将上述存储数据的mbuf链表的指针传递给协议层的UDP输出例程,并调用UDP输出例程,在UDP输出例程中,需要在这150字节中加入IP首部和UDP首部。具体如下图

第一个mbuf中灰色的72字节部分留给后续层添加以太网首部。

UDP输出例程填写UDP首部和IP首部中它能填写的部分,然后进行UDP校验并把计算和填写在UDP首部,UDP校验需要遍历这150字节数据,这是第二次遍历,第一次是将这150字节数据拷贝到内核mbuf中。

接着UDP输出例程调用IP输出例程。

3.3 IP输出例程

IP输出例程要填写IP首部中剩余字段,包括:IP校验和。确定数据报应发到哪个输出接口(这是IP路由功能),必要时对IP保温分片,以及调用接口输出函数。

假设输出接口是一个以太网接口,再次把mbuf链表的指针作为一个参数,调用一个通用的以太网输出函数

3.4 以太网输出函数

此时协议层已经结束,来到了接口层中的以太网输出。

以太网输出函数第一个功能,就是ARP,即利用32位的目的IP地址获得48位的目的MAC地址。

然后把一个14字节的以太网首部添加到链表的第一个mbuf中,紧接IP首部。

之后此mbuf链表被加到此接口的输出队列队尾。如果接口不忙,接口的"开始输出"例程立即被调用。若接口忙,在它处理完输出队列中其他缓存后,再来处理本mbuf链表。

当接口处理它输出队列的一个mbuf时,它把数据复制到它的传输缓存中,并且开始输出。本例子192字节被复制到传输缓存,14字节以太网首部,20字节IP首部,8字节UDP首部以及150字节用户数据。这是内核第三次遍历数据。一旦mbuf被复制到设备传输缓存,mbuf链表就会被以太网设备驱动程序释放。这三个mbuf被放回到内核的自由缓存池中。

4. 输入处理

输入处理指的是,调用recvfrom,从其他电脑接收到传输过来的mbuf,然后从物理层到传输层再到进程、层层解析,最后将数据读到内存。

输入是异步的,也就是说,当进程调用recvfrom,自身会自主软中断,阻塞,中断程序从物理层到传输层再到进程,层层解析,最后交给调用recvfrom的进程后,输入软中断结束,进程会被唤醒。

4.1 设备驱动程序和以太网输入函数

该部分是接口层(即物理层+数据链路层)

进程调用recvfrom后会中断,首先由以太网设备驱动程序来处理这个中断,假设设备驱动程序接收到传输过来的数据(共54字节,20字节IP首部、8字节UDP首部及26字节数据),那么会把该54字节数据复制到mbuf中,如下图

其中灰色部分16字节留给接口层首部(比如以太网首部),但没有使用。

设备驱动程序把mbuf传给一个通用以太网输入例程。

然后以太网输入例程通过以太网帧中的类型字段确定哪个协议层

来接收此分组。

在这个例子中,类型字段表示一个IP数据报,从而mbuf被加入到IP输入队列中。

另外产生一个软中断来执行IP输入例程。

4.2 IP输入例程

IP输入是异步的,并通过一个软中断来执行。

整个IP输入队列被处理完后返回。

IP输入例程处理每个接收到的IP数据报,它验证IP首部校验和,处理IP选项,验证数据报的目标IP与主机IP是否一致,并当系统被配置为一个路由器且数据报被标注为其他的IP地址时转发此数据报,如果IP数据报到达它的最终目标,调用IP首部中标识的协议(ICMP、IGMP、TCP、UDP)的输入例程。本例是UDP输入例程

4.3 UDP输入例程

UDP输入例程验证UDP首部中的各字段,然后确定一个进程是否应该接收此数据报。

一个进程可以接收到指定UDP端口的所有数据报。

本例中,UDP输入例程从一个全局变量udp开始,查看所有UDP协议控制块链表,寻找一个本地端口号(inp_lport)与接收的UDP数据报的目的端口号匹配的协议控制块。这个PCB由本例程序socket创建。

UDP输入例程将需要发送给进程的数据放入mbuf中,如下图

删除了IP首部和UDP首部,只保留了26字节的数据。

最后mbuf链表指针传递给进程,并且进程被唤醒,等待内核调度。

4.4 进程输入

本例进程调用recvfrom时被阻塞,在内核中处于睡眠状态,现在进程被唤醒。26字节数据被内核从mbuf复制到我们程序的缓存中。

我们程序把recvfrom的第5和第6个参数设置为空指针,告诉系统在接收过程中不关心发送方的IP地址和UDP端口号。这使得系统调用recvfrom略过链表第一个mbuf,仅返回第二个mbuf的26字节数据。

然后内核的recvfrom代码释放这两个mbuf,放回到自由mbuf池中。

相关推荐
就这个java爽!1 小时前
JAVA网络编程【基于TCP和UDP协议】超详细!!!
java·开发语言·网络·tcp/ip·udp·eclipse·idea
xxpro1 小时前
S3C2440开发板点亮LED灯+PWM定时器
单片机·嵌入式硬件
一叶飘零_sweeeet1 小时前
为什么 Feign 要用 HTTP 而不是 RPC?
java·网络协议·http·spring cloud·rpc·feign
KookeeyLena71 小时前
动态IP与静态IP:哪种更适合用户使用?
网络·网络协议·tcp/ip
百里与司空1 小时前
学习CubeIDE——定时器开发
stm32·单片机·嵌入式硬件·学习
时之彼岸Φ3 小时前
Web:HTTP包的相关操作
网络·网络协议·http
秋已杰爱3 小时前
HTTP中的Cookie与Session
服务器·网络协议·http
W21553 小时前
LINUX网络编程:http
网络·网络协议·http
honey ball4 小时前
仪表放大器AD620
运维·单片机·嵌入式硬件·物联网·学习
luckyluckypolar5 小时前
STM32 -中断
stm32·单片机·嵌入式硬件·物联网