目前,IP层的东西基本讲解完,数据包的发送或分片发送没有具体涉及到。数据包的发送,与上层协议密切相关,即传输层,后面的内容就是讨论传输层的东西了。这里先讲解传输层协议中比较简单的ICMP协议。ICMP(Internet

Control Message

Protocol)是Internet控制报文协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。

在以前讲解IP层ip_input函数时,已经三次涉及到了ICMP的东西,第一次在数据包转发过程中,需要将数据包的TTL值减1,若此时TTL值变为0则用icmp_time_exceeded函数向源主机返回一份超时ICMP信息;还有两次是ip_input函数通过IP报文头部的协议字段值判断该数据包是交给哪个上层协议的,若是ICMP协议,则调用icmp_input函数;若没有一个协议能接受这个数据包,则调用icmp_dest_unreach函数向源主机返回一个协议不可达ICMP差错控制包。这里先讲解icmp_time_exceeded和icmp_dest_unreach函数是怎样发送ICMP信息包的。

先来看看ICMP报文的格式,所有ICMP报文的前四个字节都是一样的,分别为1字节的类型字段,1字节的代码字段和2字节的校验和字段。校验和字段的计算覆盖整个ICMP报文。类型字段和代码字段唯一确定了该ICMP报文属于那种类型:如回显、超时、时间戮请求等等,尽管各种类型的ICMP报文结构通常是不相同的,但它们开始的四个字节是相同的。ICMP报文从大的方面来说可以分为ICMP查询报文和ICMP差错报文。ICMP查询报文包括ICMP回显应答、回显请求、时间戮请求、地址掩码请求等等类型,LWIP只实现了ICMP回显应答;ICMP差错报文有目的不可达、超时、重定向等等类型,LWIP只实现了目的不可达、超时两项ICMP处理功能。这里先讲解目的不可达和超时两种类型的ICMP处理。

目的不可达和超时两种ICMP报文均属于ICMP差错报文,协议中规定,ICMP差错报文应始终包含产生ICMP差错报文的IP数据报的IP首部和数据前8个字节。所以,目的不可达和超时这两种ICMP报文均有下面的报文结构,这个结构与前面所述完全相符,不解释了。

 先讲与icmp_dest_unreach函数所描述的目的不可达差错报文。该报文的类型字段值应为3,代码字段值应为(0~15),目前LWIP只支持(0~5),分别表示网络不可达、主机不可达、协议不可达、端口不可达、需进行分片但设置了不分片位、源站选择失败。很明显,在ip_input函数找不到将该数据包交到哪个上层协议时,应该产生一个协议不可达的差错报文,即代码字段值为2。函数原型如下,输入参数为接收到的目标不可达的IP数据包和应该用于填充ICMP头部代码字段的值。

void icmp_dest_unreach(struct pbuf *p,

enum icmp_dur_type t)

现在来看看这个函数做了哪些工作,首先为要发送数去的ICMP数据包申请一个pbuf缓冲区,这个缓冲区的长度为上图所述结构的长度与一个IP数据报头大小之和,之所以要多申请IP数据报头大小的空间是为了当该ICMP数据包被递交给IP层发送时,IP层不需要再去申请一个数据报头来封装该ICMP数据包,而是直接在已经申请好的报头中填入IP头部数据,注意这里申请好的pbuf的payload指针是指向ICMP数据报头处的。接下来,函数填写ICMP数据包的相关字段,将类型段填充为3,代码段为输入参数t,同时将不可达的IP数据包的IP报头和数据前8个字节拷贝到ICMP数据包相应字段,最后计算校验和字段的值,然后调用ip_output函数将组装好的ICMP包发送出去。

ip_output函数通过调用ip_output_if函数完成数据包的发送,它在调用ip_output_if函数前,要先根据发送数据包的目的IP地址找到相应的发送网络接口结构,并将该结构作为调用ip_output_if函数的参数。ip_output_if函数主要是填充IP报头各个字段的值,然后调用netif->output函数将封装好的IP数据包发送出去。

icmp_time_exceeded函数用于产生一个超时类型的ICMP报文。该类型的报文与上面所述的报文有完全相同的报文结构,但类型字段值应为11,代码字段应为0或1,分别代表传输期间生存时间超时和数据组装期间生存时间超时。对于后者,在讨论数据包重组时,我们知道每个ip_reassdata结构体中都有个时间字段,当指定的时间到达而数据包还未被组装完毕,则内核会将该ip_reassdata结构相关的所有分片数据全部删除,并向源主机发送一个代码字段为1的超时ICMP报文。

从代码流程和内容来看,icmp_time_exceeded函数和icmp_dest_unreach函数完全一样,只是在填充ICMP报文的类型和代码字段使用了不同的值,这里不再赘述。

接下来该讨论ICMP查询报文了,这部分在整个产品的设计调试过程中显示出非常重要的作用。即Ping命令,它与ICMP回显应答、请求报文密切相关。

这小段来自于协议:“Ping”这个名字源于声纳定位操作。目的是为了测试另一台主机是否可达。该程序发送一份

ICMP回显请求报文给主机,并等待返回ICMP回显应答。一般来说,如果不能Ping到某台主机,那么就不能

Telnet或者FTP到那台主机。反过来,如果不能Telnet到某台主机,那么通常可以用Ping程序来确定问题出在哪里。Ping程序还能测出到这台主机的往返时间,以表明该主机离我们有“多远”。同时,Ping程序也能在数据包的路由过程中记录下路由路径。

ICMP回显请求和回显应答报文格式如下图,回显应答的类型值为0,回显请求类型值为8,二者代码字段值均为0,Unix系统在实现ping程序时是把ICMP报文中的标识符字段置成发送进程的ID号。这样即使在同一台主机上同时运行了多个ping程序实例,ping程序也可以识别出返回的信息。序列号从0开始,每发送一次新的回显请求就加

1。

icmp_input函数处理接收到的ICMP数据包,并根据包类型做相应的处理。目前LWIP只能处理ICMP回显请求包,对其他类型的ICMP包不做响应,这在嵌入式产品中是足够用了的。对于ICMP回显请求,icmp_input需要生成一个回显应答报文返回给源主机。

来看看icmp_input函数做了哪些工作。首先将传进来的数据包pbuf的payload指针调整为指向ICMP头部,并判断ICMP头部长度是否小于4个字节,若是,则说明是个错误的ICMP数据包,该包被丢弃。对于正确的ICMP包,函数根据其头部类型字段的值判断该做什么样的处理。当前版本只实现了对ICMP回显请求的相关响应操作。

若当前的数据包为ICMP回显请求,则函数继续判断该数据包是否为广播或者多播包,对这两种数据包不做处理;接下来判断该数据包大小是否小于ICMP回显请求头部长度(如上图所示),是则丢弃数据包;接下来函数为这个数据包申请IP报头和以太网帧头内存空间,成功后将该ICMP包类型字段变为0,从新计算校验和,并将IP报头的源IP地址和目的IP地址交换位置,最后将整个数据包利用ip_output_if函数将数据包发送出去。ICMP回显应答将回显请求中的数据原样返回给源主机,源主机在收到回显应答后,通过处理回显应答中的数据可以得到相关信息,如计算往返时间等。

ICMP就是这么多了。

icmp源代码 tcp/ip协议栈 c语言实现,ICMP处理《LwIP协议栈源码详解——TCP/IP协议的实现》...相关推荐

  1. lwip路由实现_TCP超时与重传《LwIP协议栈源码详解——TCP/IP协议的实现》

    在TCP两端交互过程中,数据和确认都有可能丢失.TCP通过在发送时设置一个定时器来解决这种问题.如果当定时器溢出时还没有收到确认,它就重传该数据.对任何TCP协议实现而言,怎样决定超时间隔和如何确定重 ...

  2. Go 语言 bytes.Buffer 源码详解之1

    转载地址:Go 语言 bytes.Buffer 源码详解之1 - lifelmy的博客 前言 前面一篇文章 Go语言 strings.Reader 源码详解,我们对 strings 包中的 Reade ...

  3. android 远程视频监控程序源码,详解基于Android已开放源代码的远程视频监控系统教程...

    网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.Socket的英文原义是"孔"或"插座".通常也称作"套接字 ...

  4. udhcp源码详解(四) 之租赁IP的管理

    Server端对于租赁出去的IP的管理是基于结构体dhcpOfferedAddr的,该结构体的定义是在leases.c文件里:(结构体的成员介绍说明见详解之数据结构) [cpp] view plain ...

  5. 【C语言/C++】益智游戏开发:2048(源码详解)

    前言 C/C++作为元老级的编程语言,任时光更迭依旧屹立不倒,哪怕如今炙手可热的AI,其底层也是用其编写.C/C++可以说是永不过时的语言. 那么作为新手该如何上手这门语言?一切不敲代码的学编程手段都 ...

  6. 【C语言/C++】项目实战:猜拳游戏(源码详解)

    这是一个简单的猜拳游戏(剪子包子锤),让你与电脑对决.你出的拳头由你自己决定,电脑则随机出拳,最后判断胜负. 下面的代码会实现一个猜拳游戏,让你与电脑对决.你出的拳头由你自己决定,电脑则随机出拳,最后 ...

  7. C语言 printf源码详解,从头一起学c语言(六)————printf函数的详解

    这段时间很忙,更新的晚了,见谅.当然同样有今天我们的主角十分复杂,之前介绍了这个手记并非是面对新手的,而是我的复习手记.所以我们会讲头文件,或许有错误,如果有大手子看到,希望能够提出我的错误. pri ...

  8. Android源代码介绍,Android-Log源码详解

    Log.java 源码目录:frameworks/base/core/java/android/util 编译目录:frameworks/base image.png 我惊奇的发现,Log.java里 ...

  9. android五子棋源代码,Android五子棋游戏源码详解

    最近看了鸿洋大牛的五子棋教程,受益匪浅,讲的非常好,关于五子棋的游戏原理非常清楚,并且学到了不少知识,在这里感谢鸿洋大神的分享.我觉得我的源码注释写的非常清楚了,希望能给你带来不少的收获. 布局< ...

  10. 冒泡排序C语言实现 - 源码详解

    冒泡排序 时间复杂度:O(N²) 稳定性:稳定 排序原理:         从前往后依次比较相邻的两个数据(如0:1 1:2 2:3 3:4 ... n:tail),         根据排序方向,将 ...

最新文章

  1. notepad php必用功能,Notepad中值得一提的特性
  2. rsync备份之windows+linux
  3. 第十二届蓝桥杯大赛软件赛省赛 C/C++ 大学B组
  4. UCloud想吃科创板的“第一个螃蟹”
  5. rjdbc读取mysql_R通过RJDBC连接外部数据库 (转)
  6. js中遇到的一个错误Uncaught SyntaxError: missing )after argument list
  7. Android的虚拟机Dalvik 介绍
  8. 李迟2021年10月知识总结
  9. csv解析java_Java CSV解析器
  10. Java Web开发的轻便架构Tapestry5---页面渲染一
  11. 自动量程万用表的实现原理_自动量程万用表模块设计方案[图]
  12. visio添加箭头图标
  13. 【TypeScript】使用CRA创建支持TS的React项目(从踩坑到放弃)
  14. rasa框架nlu源码解析
  15. 剪切文件丢失如何恢复
  16. Altium设置菜单之系统菜单
  17. java获取天气的方法
  18. 怎么为typora配置一个可爱的小鲨鱼主题?
  19. 【华为OD机试c++/java/python 真题2023 Q1】
  20. java遍历数组的三种方法

热门文章

  1. solidworks中皮带同步轮配合如何做?几张图教会你
  2. 科蓝ichat泡分机器人 官网
  3. AutoCAD Civil 3D 2012正式发布
  4. 有爱无碍,科技为他们点亮漫天星光
  5. PMP考试需要准备什么教材呢?
  6. 设置谷歌浏览器和Edge浏览器为黑色背景
  7. 【NeatUpload】因用了NeatUpload大文件上传控件而导致Nonfile portion 4194304 bytes错误的解决方法
  8. C-Free 3.5.2 注册码
  9. JAVA集合框架概述
  10. 电商API,获得淘宝商品类目