目录
  • PING原理

1.简介

  PING是基于ICMP(Internet Control Message Protocol)协议工作的。ICMP报文是封装在IP包中,工作在网络层。

2.协议

  ICMP包头的类型字段有2类,一类是查询报文,用于检测通信链路是否正常;一类是差错报文,通知出错原因。

  回送消息是用于进行通信的主机间,判断所发的数据包是否已经成功到达对端的一种消息,ping命令就是利用这个消息实现的:可以向对端发送回送请求的消息(request,8),也可以接收对端主机发送回来的应答(reply,0)

Type(8位) Code(8位)
Checksum(16位)
Identifier(16位)
Sequence Number(16位)
选项数据

Type(类型):0代表回送应答,8代表回送请求

Code(代码):值为0

Checksum(校验和)

Identifier(标识符):Unix系统在实现ping程序时,把ICMP报文中的标识符字段设置成发送进程的PID号

Sequence Number(序号):从0开始,每发送一次新的请求就加1

抓包:

请求包(Response frame:40 表示应答此请求的reply包是N0.40这一包)

应答包(Request frame:37 表示此包是对N0.37这一请求包的应答)

3.通信流程

  ①执行ping 192.168.x.x命令后,源主机会先构建一个ICMP请求消息数据包(类型为8)

  ②由ICMP协议将这个数据包连同192.168.x.x这一地址一起交给IP层。IP层将以192.168.x.x作为目的地址,本地ip地址作为源地址,协议字段置为1表示是ICMP协议,再加上一些其他的信息构建成一个IP数据包。

  ③之后,需要加入MAC头,如果在本地ARP映射表中能直接查到192.168.x.x这一地址所对应的MAC地址,则可以直接使用。在获取MAC地址后,由数据链路层构建一个数据帧,其中,目的地址是刚刚找到的MAC地址,源地址是本机的MAC地址。

  ④对端设备收到这个数据帧后,将其中的目的MAC地址和自己的本地MAC地址对比,如果符合则接收,不符合就丢弃。如果MAC地址符合,那么提取出IP数据包,经IP层检查后,再提取出有用的相关信息给ICMP协议。

  ⑤识别出这是一个ping请求帧后,将构建一个ICMP应答包(类型为0),经过同样的流程传给发送请求包的主机。

  • 代码解释(CH395.c)

1.设置395相关网络参数及对端,将ip包协议字段置为1,表示为Internet控制消息 (ICMP)协议类型。

1 /* CH395相关定义 */
2 const UINT8 CH395IPAddr[4] = {192,168,1,126}; /* CH395IP地址 */
3 const UINT8 CH395GWIPAddr[4] = {192,168,1,1}; /* CH395网关 */
4 const UINT8 CH395IPMask[4] = {255,255,255,0}; /* CH395子网掩码 */
5 const UINT8 DestIPAddr[4] = {192,168,1,23}; /* 目的IP */
6 const UINT8 IPRawProto = 1; /* IP包协议类型 */

2.初始化395和socket的参数,并将socket设置为ipraw模式。(关于ipraw模式的介绍和使用可以查阅CH395的官方手册)

 1 /**********************************************************************************
2 * Function Name : InitCH395InfParam
3 * Description : 初始化CH395Inf参数
4 * Input : None
5 * Output : None
6 * Return : None
7 **********************************************************************************/
8 void InitCH395InfParam(void)
9 {
10 memset(&CH395Inf,0,sizeof(CH395Inf)); /* 将CH395Inf全部清零*/
11 memcpy(CH395Inf.IPAddr,CH395IPAddr,sizeof(CH395IPAddr)); /* 将IP地址写入CH395Inf中 */
12 memcpy(CH395Inf.GWIPAddr,CH395GWIPAddr,sizeof(CH395GWIPAddr)); /* 将网关IP地址写入CH395Inf中 */
13 memcpy(CH395Inf.MASKAddr,CH395IPMask,sizeof(CH395IPMask)); /* 将子网掩码写入CH395Inf中 */
14 }
15
16 /**********************************************************************************
17 * Function Name : InitSocketParam
18 * Description : 初始化socket
19 * Input : None
20 * Output : None
21 * Return : None
22 **********************************************************************************/
23 void InitSocketParam(void)
24 {
25 memset(&SockInf,0,sizeof(SockInf)); /* 将SockInf[0]全部清零*/
26 memcpy(SockInf.IPAddr,DestIPAddr,sizeof(DestIPAddr)); /* 将目的IP地址写入 */
27 SockInf.ProtoType = PROTO_TYPE_IP_RAW; /* IP RAW模式 */
28 SockInf.IPRAWProtoType = IPRawProto;
29 }
30
31 /**********************************************************************************
32 * Function Name : CH395SocketInitOpen
33 * Description : 配置CH395 socket 参数,初始化并打开socket
34 * Input : None
35 * Output : None
36 * Return : None
37 **********************************************************************************/
38 void CH395SocketInitOpen(void)
39 {
40 UINT8 i;
41 /* socket 0为IP RAW模式 */
42 CH395SetSocketDesIP(0,SockInf.IPAddr); /* 设置socket 0目标IP地址 */
43 CH395SetSocketProtType(0,SockInf.ProtoType); /* 设置socket 0协议类型 */
44 CH395SetSocketIPRAWProto(0,SockInf.IPRAWProtoType); /* 设置协议字段 */
45
46 i = CH395OpenSocket(0); /* 打开socket 0 */
47 mStopIfError(i); /* 检查是否成功 */ /* 检查是否成功 */
48 }

3.在socket的接收中断中,调用 CH395GetRecvLength()函数获取当前缓冲区中的数据长度,在调用CH395GetRecvData()函数读取数据,最后调用 CH395IcmpRecvData()函数对收到的ping包处理和分析。

 1 /**********************************************************************************
2 * Function Name : CH395SocketInterrupt
3 * Description : CH395 socket 中断,在全局中断中被调用
4 * Input : sockindex
5 * Output : None
6 * Return : None
7 **********************************************************************************/
8 void CH395SocketInterrupt(UINT8 sockindex)
9 {
10 UINT8 sock_int_socket;
11
12 UINT16 len;
13
14 sock_int_socket = CH395GetSocketInt(sockindex); /* 获取socket 的中断状态 */
15 // printf("SOCK status : %02x\n",sock_int_socket);
16 if(sock_int_socket & SINT_STAT_SENBUF_FREE) /* 发送缓冲区空闲,可以继续写入要发送的数据 */
17 {
18 }
19 if(sock_int_socket & SINT_STAT_SEND_OK) /* 发送完成中断 */
20 {
21 IcmpSuc++;
22 }
23 if(sock_int_socket & SINT_STAT_RECV) /* 接收中断 */
24 {
25 printf("recv back!\r\n");
26 len = CH395GetRecvLength(sockindex); /* 获取当前缓冲区内数据长度 */
27 if(len == 0)return;
28 if(len > 512) len = 512;
29 CH395GetRecvData(sockindex,len,MyBuffer); /* 读取数据 */
30 CH395IcmpRecvData(len,MyBuffer);
31 }
32 if(sock_int_socket & SINT_STAT_CONNECT) /* 连接中断,仅在TCP模式下有效*/
33 {
34
35 }
36 if(sock_int_socket & SINT_STAT_DISCONNECT) /* 断开中断,仅在TCP模式下有效 */
37 {
38 }
39 if(sock_int_socket & SINT_STAT_TIM_OUT) /* 超时中断 */
40 {
41 }
42 }

4.在CH395PINGInit()函数中,进行引脚初始化、复位395、初始化395、初始化socket、打开socket等操作。

调用 CH395EnablePing(1)函数开启ping功能(默认开启)

InitParameter()--- PING参数变量初始化

InitPing()--- PING初始化,生成ping查询报文

 1 /**********************************************************************************
2 * Function Name : main
3 * Description : main主函数
4 * Input : None
5 * Output : None
6 * Return : None
7 **********************************************************************************/
8 void CH395PINGInit(void)
9 {
10 UINT8 i;
11 Delay_Ms(100);
12 printf("CH395EVT Test Demo\n");
13 CH395_PORT_INIT();
14 CH395CMDReset(); /* 复位CH395芯片 */
15 Delay_Ms(1000); /* 延时1000毫秒,要分开写,否则无效 */
16
17 i = CH395CMDGetVer(); /*获取芯片以及固件版本号 */
18 printf("固件版本号:%02x\n",i);
19 InitCH395InfParam(); /* 初始化CH395相关变量 */
20 i = CH395Init(); /* 初始化CH395芯片 */
21 printf("CH395Init:%02x\n",i);
22 mStopIfError(i);
23
24 while(1)
25 { /* 等待以太网连接成功*/
26 if(CH395CMDGetPHYStatus() == PHY_DISCONN) /* 查询CH395是否连接 */
27 {
28 printf("CH395 DISCONN\n");
29 Delay_Ms(200); /* 未连接则等待200MS后再次查询 */
30 }
31 else
32 {
33 printf("CH395 Connect Ethernet\n"); /* CH395芯片连接到以太网,此时会产生中断 */
34 break;
35 }
36 }
37 InitSocketParam(); // /* 初始化socket相关变量 */
38 CH395SocketInitOpen();//
39
40 //CH395EnablePing(1);//默认开启
41 InitParameter();
42 InitPing();
43 printf("!!\r\n");
44 // TIM2_Init();
45 // Intervalometer_4ms();
46 }
 1 /**********************************************************************************
2 * Function Name : InitParameter
3 * Description : Ping参数初始化
4 * Input : None
5 * Output : None
6 * Return : None
7 **********************************************************************************/
8 void InitParameter( void )
9 {
10 UNREACH_COUNT=0;
11 TIMOUT_COUNT=0;
12 SUCRECV_COUNT=0;
13 IcmpCont=0;
14 IcmpSeq=0;
15 IcmpSuc=0;///
16 icmp_tmp=0;
17 CH395GetIPInf(CH395INF_BUF);
18 }
19
20 /**********************************************************************************
21 * Function Name : InitPing
22 * Description : Ping初始化
23 * Input : None
24 * Output : None
25 * Return : None
26 **********************************************************************************/
27 void InitPing( void )
28 {
29 IcmpHeader head;
30 UINT32 check_sum=0;
31 UINT8 i;
32
33 IcmpCont++;
34 IcmpSeq += 1;
35 head.i_type = ICMP_HEAD_TYPE;//8
36 head.i_code = ICMP_HEAD_CODE;//0
37 head.i_id = ICMP_HEAD_ID;//512
38 head.i_seq = ICMP_HEAD_SEQ+IcmpSeq;//100+
39 memset(head.i_data,0,sizeof(head.i_data));
40
41 for( i=0;i<ICMP_DATA_BYTES;i++ ){//32
42 if(i<26)
43 head.i_data[i] = i + 'a';
44 else
45 head.i_data[i] = i + 'a' - 26;
46 if(i%2==0)
47 check_sum += head.i_data[i]<<8;
48 else
49 check_sum += head.i_data[i];
50 }
51 check_sum += head.i_type<<8;
52 check_sum += head.i_code;
53 check_sum += head.i_id;
54 check_sum += head.i_seq;
55 head.i_cksum = check_sum>>16;
56 head.i_cksum += check_sum&0xffff;
57 head.i_cksum = 0xffff - head.i_cksum;
58 memset(SEND_BUF,0,sizeof(SEND_BUF));
59 memcpy(SEND_BUF,&head,sizeof(head));
60
61 SEND_BUF[2] = head.i_cksum >> 8;
62 SEND_BUF[3] = head.i_cksum & 0xff;
63 SEND_BUF[4] = head.i_id >> 8;
64 SEND_BUF[5] = head.i_id & 0xff;
65 SEND_BUF[6] = head.i_seq >> 8;
66 SEND_BUF[7] = head.i_seq & 0xff;
67 }

5.在main函数中,通过 CH395SendData()函数发送 InitPing()函数生成的40字节的数据,简单实现按键按一下发送一次ping请求包。

 1 /**********************************************************************************
2 * Function Name : main
3 * Description : main主函数
4 * Input : None
5 * Output : None
6 * Return : None
7 **********************************************************************************/
8 int main(void)
9 {
10
11 Delay_Init();
12 USART_Printf_Init(115200);
13 Delay_Ms(100);
14 /* 延时100毫秒 */
15 GPIO_Toggle_INIT_C();
16 CH395PINGInit();
17 //
18 //Delay_Ms(2000);
19 //CH395SendData(0,MyBuffer1,2);
20 //Delay_Ms(20);
21 // CH395SendData( 0,SEND_BUF,40 );
22 // Delay_Ms(20);
23 // CH395SendData( 0,SEND_BUF,40 );
24 //
25 // Delay_Ms(20);
26 // CH395SendData( 0,SEND_BUF,40 );
27 // Delay_Ms(20);
28 // CH395SendData( 0,SEND_BUF,40 );
29 while(1)
30 {
31 if(CH395_INT_WIRE == 0)
32 {
33 CH395GlobalInterrupt();
34 }
35 if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == RESET)
36 {
37 Delay_Ms(2);
38 if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == RESET)
39 {
40 printf("PING %d times\r\n",++t);
41 CH395SendData( 0,SEND_BUF,40 );
42 while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) == RESET);
43 }
44 }
45 // CH395SendData( 0,SEND_BUF,40 );
46 // Delay_Ms(1500);
47 /*查询状态执行相应命令*/
48 // CH395_PINGCmd();
49 // InitPing();
50 }
51 }

效果如下,按下按键发送一次ping请求包,对端reply一包数据。(一共发了3次ping_request,成功进入socket接收中断接收处理回包)


工程代码及抓包:https://files.cnblogs.com/files/blogs/808422/CH395_%E4%B8%BB%E5%8A%A8ping.zip?t=1702869711&download=true

CH395实现主动ping对端功能(代码及说明)的更多相关文章

  1. 原生JS实现购物车结算功能代码+zepto版

    html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  2. 常见.NET功能代码汇总 (2)

    常见.NET功能代码汇总 23,获取和设置分级缓存 获取缓存:首先从本地缓存获取,如果没有,再去读取分布式缓存写缓存:同时写本地缓存和分布式缓存 private static T GetGradeCa ...

  3. 通过javascript库JQuery实现页面跳转功能代码

    通过javascript库JQuery实现页面跳转功能代码的四段代码实例如下. 实例1: 1 2 3 4 $(function(){ var pn = $("#gotopagenum&quo ...

  4. IOS开发-OC学习-常用功能代码片段整理

    IOS开发-OC学习-常用功能代码片段整理 IOS开发中会频繁用到一些代码段,用来实现一些固定的功能.比如在文本框中输入完后要让键盘收回,这个需要用一个简单的让文本框失去第一响应者的身份来完成.或者是 ...

  5. 20个开发人员非常有用的Java功能代码

    本文将为大家介绍20个对开发人员非常有用的Java功能代码.这20段代码,可以成为大家在今后的开发过程中,Java编程手册的重要部分. 1. 把Strings转换成int和把int转换成String ...

  6. 串口发送端verilog代码分析

    串口发送端verilog代码分析 `timescale 1ns / 1ps ////////////////////////////////////////////////////////////// ...

  7. python的select服务端的代码和客户端的代码

    服务端的代码 import socket import queue import select ip_bind = ("127.0.0.1",9000) message_queue ...

  8. day1 函数 (独立功能代码块)

    1.引入函数 2.函数执行过程 4.带参数的函数 5.带返回值的函数 6. 多个返回值 (return a,b,c)元组 7.4种函数 1.引入函数 独立功能代码块 ---> 封装 ----&g ...

  9. js经常使用功能代码

    js经常使用功能代码(持续更新): 1---折叠与展开 <input id="btnDisplay" type="button" class=" ...

  10. c++ 网络编程(一)TCP/UDP windows/linux 下入门级socket通信 客户端与服务端交互代码

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9601511.html c++ 网络编程(一)TCP/UDP  入门级客户端与服务端交互代码 网 ...

随机推荐

  1. 《Linux基础》05. 定时任务调度 · 磁盘分区与挂载 · 网络配置

    @ 目录 1:定时任务调度 1.1:crontab 1.2:at 2:磁盘分区与挂载 2.1:原理介绍 2.2:硬盘说明 2.3:磁盘目录情况查询 2.3.1:lsblk 2.3.2:df 2.3.3 ...

  2. 云服务器中Linux如何安装宝塔面板?

    作者:西瓜程序猿 主页传送门:https://www.cnblogs.com/kimiliucn 官方使用手册:https://www.kancloud.cn/chudong/bt2017/42420 ...

  3. 原来你是这样的JAVA--目录

    .NET程序员转Java过程中遇到的一些经验分享,陆续更新中. 原来你是这样的Java[01]--基础一瞥 原来你是这样的Java[02]-包.传参.构造器 原来你是这样的Java[03]-继承.多态 ...

  4. 【项目源码】JSP超市积分管理系统源码下载

    会员积分管理系统的目标是为中小规模的会员积分管理系统的目标是为中小规模的超市提供会员信息管理.会员积分管理以及积分兑换管理的具体解决方案. 网站和积分管理系统采用B/S结构,使用J2EE的技术开发完成 ...

  5. RK3568开发笔记(七):在宿主机ubuntu上搭建Qt交叉编译开发环境,编译一个Demo,目标板运行Demo测试

    前言   在之前的博文中已经搭建好了一个比较完善的ubuntu宿主机,都很完善了但是发现没有Qt交叉编译开发环境,所以还需要搭建一套Qt交叉编译开发环境.   补充说明   本篇是基于<RK35 ...

  6. PHP上传文件$_FILES, $_POST为空 empty 时, 文件上传大小限制

    原因 今天在使用ci upload库时, 上传mp4发现表单为空, 上传png等类型却可以正常. 折腾一番后才恍然, PHP上传大小限制的问题. Make一下. 真是失策啊, 一开始我还不相信到处瞎折 ...

  7. 【matplotlib 实战】--平行坐标系

    平行坐标系是一种统计图表,它包含多个垂直平行的坐标轴,每个轴表示一个字段,并用刻度标明范围.通过在每个轴上找到数据点的落点,并将它们连接起来形成折线,可以很容易地展示多维数据.随着数据增多,折线会堆叠 ...

  8. Django框架——Web应用、基于SOCKET写一个web应用、 手撸简单web框架、http协议、Web框架(手撸自己的Web框架)、django简介以及简单使用

    文章目录 1 Web应用 一 Web应用程序是什么 1.1 Web应用程序的优点 1.2 Web应用程序的缺点 1.3 B/S架构优点 二 基于SOCKET写一个web应用 2.1 main.py 2 ...

  9. tmai

    天猫精灵技能应用平台合作协议 发布日期:2020年03月18日 更新日期:2021年02月01日 鉴于您(语音技能.小程序或应用程序APP等的制作.提供或开发者)希望入驻或与天猫精灵技能应用平台(又称 ...

  10. Vue源码学习(九):响应式前置:实现对象的依赖收集(dep和watcher)

    好家伙,这是目前为止最绕的一章,也是十分抽象的一章 由于实在太过抽象,我只能用一个不那么抽象的实例去说服我自己   完整代码已开源https://github.com/Fattiger4399/ana ...