W5100S-EVB-PICO主动PING主机IP检测连通性(十)

news2024/12/23 10:50:12

前言

        上一章节我们用我们开发板在UDP组播模式下进行数据回环测试,本章我们用开发板去主动ping主机IP地址来检测与该主机之间网络的连通性。

什么是PING?

        PING是一种命令, 是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接。ping 使用的是ICMP协议,它发送icmp回送请求消息给目的主机。ICMP协议规定:目的主机必须返回ICMP回送应答消息给源主机。如果源主机在一定时间内收到应答,则认为主机可达。可以理解为ping命令是ICMP的一种形式,而ICMP属于网络层协议,因而ping也工作在网络层。

连接方式

  • 开发板直连主机
  • 开发板和主机都接在路由器LAN口

PING测试

        我们的W5100S以太网芯片,既可以通过一个socket端口开启IPRAW模式自己组包(ICMP报文)对目标IP进行ping测试,从而在软件上实现ping功能,也可以通过配置SOCKET-less命令相关寄存器,通过SOCKET-less命令直接在硬件上实现ping功能,省去了在软件上组包、解析数据包的烦恼,而且不占用socket端口,非常方便和易于实现。下面我们通过这两种方式分别进行ping测试:

1. 相关代码

1. 通过IPRAW模式实现(软件)

        我们打开库文件PING文件夹里的ping.c文件,我们主要用到这几个函数:ping_auto()、ping_request()、ping_reply()、do_ping()等,ping_request()和ping_reply()主要是ping请求的组包和收到ping回复的数据包解析,用到的数据转换和处理大家自行查看,这里我们主要看下ping_auto()函数,它通过在一个循环里构建一个状态机来对socket状态进行轮询,做出对应处理,如果端口关闭状态,就设置对应端口协议为ICMP协议,然后以IPRAW模式打开;进入IPRAW模式后,发送ping请求,然后判断是否收到或超时,收到就进行解析,之后跳出,超时则跳出,当请求数和回复数相等且为4次时结束大循环,然后将它再封装成do_ping()方便直接调用,如下所示:

/* Ping the Internet automatically. */
void ping_auto(uint8_t sn, uint8_t *addr)
{
    int32_t len = 0;
    uint8_t cnt = 0;
    uint8_t i;

    for (i = 0; i < 10; i++)
    {
        if (req == rep && req == 4)
            break;
        switch (getSn_SR(sn))
        {
        case SOCK_IPRAW:
            ping_request(sn, addr);
            req++;
            while (1)
            {
                if ((len = getSn_RX_RSR(sn)) > 0)
                {
                    ping_reply(sn, addr, len);
                    sleep_ms(50);
                    rep++;
                    break;
                }
                else if (cnt > 200)
                {
                    printf("Request Time out.\r\n");
                    cnt = 0;
                    break;
                }
                else
                {
                    cnt++;
                    sleep_ms(50);
                }
            }
            break;
        case SOCK_CLOSED:
            close(sn);
            setSn_PROTO(sn, IPPROTO_ICMP);
            if (socket(sn, Sn_MR_IPRAW, 3000, 0) != 0)
            {
            }
            while (getSn_SR(sn) != SOCK_IPRAW)
                ;
            sleep_ms(2000);
        default:
            break;
        }
#ifdef PING_DEBUG
        if (rep != 0)
        {
            printf(" Ping Request = %d, PING_Reply = %d\r\n", req, rep);
            if (rep == req)
                printf(" PING SUCCESS\r\n ");
            else
                printf(" REPLY_ERROR\r\n ");
        }
#endif
        // if(rep==4)break;
    }
}

/* ping response. */
uint8_t ping_request(uint8_t sn, uint8_t *addr)
{
    uint16_t i;
    int32_t t;
    ping_reply_received = 0;
    PingRequest.Type = PING_REQUEST;    /*Ping-Request*/
    PingRequest.Code = CODE_ZERO;       /*总是 '0'*/
    PingRequest.ID = htons(RandomID++); /*设置ping响应ID为随机的整型变量*/
    PingRequest.SeqNum = htons(RandomSeqNum++);
    for (i = 0; i < BUF_LEN; i++)
    {
        PingRequest.Data[i] = (i) % 8;
    }
    PingRequest.CheckSum = 0;
    PingRequest.CheckSum = htons(checksum((uint8_t *)&PingRequest, sizeof(PingRequest)));
    t = sendto(sn, (uint8_t *)&PingRequest, sizeof(PingRequest), addr, 3000);
    if (t == 0)
    {
        printf("\r\n Fail to send ping-reply packet  r\n");
    }
    else
    {
        printf(" 正在 Ping: %d.%d.%d.%d  \r\n", (addr[0]), (addr[1]), (addr[2]), (addr[3]));
    }
    return 0;
}

/* Resolving ping reply. */
uint8_t ping_reply(uint8_t s, uint8_t *addr, uint16_t rlen)
{
    uint16_t tmp_checksum;
    uint16_t len;
    uint16_t i;
    uint8_t data_buf[128];

    uint16_t port = 3000;
    PINGMSGR PingReply;
    len = recvfrom(s, (uint8_t *)data_buf, rlen, addr, &port); /*从目的端接收数据*/
    if (data_buf[0] == PING_REPLY)
    {
        PingReply.Type = data_buf[0];
        PingReply.Code = data_buf[1];
        PingReply.CheckSum = (data_buf[3] << 8) + data_buf[2];
        PingReply.ID = (data_buf[5] << 8) + data_buf[4];
        PingReply.SeqNum = (data_buf[7] << 8) + data_buf[6];

        for (i = 0; i < len - 8; i++)
        {
            PingReply.Data[i] = data_buf[8 + i];
        }
        tmp_checksum = ~checksum(data_buf, len); /*检查ping回复的次数*/
        if (tmp_checksum != 0xffff)
            printf("tmp_checksum = %x\r\n", tmp_checksum);
        else
        {
            printf(" 来自 %d.%d.%d.%d 的回复: ID=%x 字节=%d \r\n",
                   (addr[0]), (addr[1]), (addr[2]), (addr[3]), htons(PingReply.ID), (rlen + 6));
            ping_reply_received = 1; /*当退出ping回复循环时,设置ping回复标志为1*/
        }
    }
    else if (data_buf[0] == PING_REQUEST)
    {
        PingReply.Code = data_buf[1];
        PingReply.Type = data_buf[2];
        PingReply.CheckSum = (data_buf[3] << 8) + data_buf[2];
        PingReply.ID = (data_buf[5] << 8) + data_buf[4];
        PingReply.SeqNum = (data_buf[7] << 8) + data_buf[6];
        for (i = 0; i < len - 8; i++)
        {
            PingReply.Data[i] = data_buf[8 + i];
        }
        tmp_checksum = PingReply.CheckSum; /*检查ping回复次数*/
        PingReply.CheckSum = 0;
        if (tmp_checksum != PingReply.CheckSum)
        {
            printf(" \n CheckSum is in correct %x shold be %x \n", (tmp_checksum), htons(PingReply.CheckSum));
        }
        else
        {
        }
        printf("  Request from %d.%d.%d.%d  ID:%x SeqNum:%x  :data size %d bytes\r\n",
               (addr[0]), (addr[1]), (addr[2]), (addr[3]), (PingReply.ID), (PingReply.SeqNum), (rlen + 6));
        ping_reply_received = 1; /* 当退出ping回复循环时,设置ping回复标志为1  */
    }
    else
    {
        printf(" Unkonwn msg. \n");
    }
    return 0;
}

void do_ping(uint8_t sn, uint8_t *ip)
{
    if (req < 4)
    {
        printf("------------------PING test start-----------------------\r\n");
        sleep_ms(1000);
        ping_auto(sn, ip);
    }
    else if (req == 4)
        close(sn);
}

2. 通过SOCKET-less命令实现(硬件)

我们找到SLping()函数,它需要我们传入两个参数:ping测试远程IP地址和ping测试次数,然后我们配置相应的SOCKET-less重传时间、重传次数、远程IP地址、中断屏蔽寄存器,然后根据传入的参数值设置ping次数,传入的值为0则将其设置为数据类型的最大值;接着在for循环里面,设置ping序列号和ID,并开启ping请求发送命令,用Switch状态机轮询中断寄存器,根据中断置位情况进行相应处理,这里分为超时和收到ping应答两个状态(情况),最后统计请求和应答成功、失败数后,进入阻塞;如下所示:

/**
 * socket-less ping
 * remote_ip:  ping ip address
 * ping_count: ping times, if its 0,always request to the max :65535 times.
 */
void SLping(uint8_t *remote_ip, uint16_t ping_count)
{
    uint16_t i;
    static uint16_t succ_count = 0;
    setSLRTR(5000); // 5000 * 100us = 500ms
    setSLRCR(2);
    setSLPIPR(remote_ip);
    setSLIMR(0x05);
    if (ping_count == 0)
        ping_count = 65535;
    for (i = 0; i < ping_count; i++)
    {
        printf("Ping the %d.%d.%d.%d \r\n", remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3]);
        setPINGSEQR(RandomSeqNum);
        setPINGIDR(RandomID);
        setSLCR(0X01);  // ping
        sleep_ms(2000); // wait
        switch (getSLIR() & 0x07)
        {
        case PING_INT:
            printf("Reply from %d.%d.%d.%d : ID: %x SeqNum: %x.\r\n", remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3], getPINGIDR(), getPINGSEQR());
            succ_count++;
            break;
        case TIMEOUT_INT:
            printf("Request timeout\r\n");
        default:
            break;
        }
        RandomID++;
        RandomSeqNum++;
    }

    printf("Ping request: %d, Succ: %d, Fail: %d.\r\n", ping_count, succ_count, (ping_count - succ_count));
    while (1)
        ;
}

主程序只需要初始化相关对应信息后,传入主函数循环调用即可,这里我们要进行ping测试的主机IP为我们开发板同一网段的电脑IP,如下所示:

#define SOCKET_ID 0
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)

void network_init(void);

wiz_NetInfo net_info = {
    .mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x2e},
    .ip = {192, 168, 1, 11},
    .sn = {255, 255, 255, 0},
    .gw = {192, 168, 1, 1},
    .dns = {8, 8, 8, 8},
    .dhcp = NETINFO_STATIC};
wiz_NetInfo get_info;
static uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0,};
static uint8_t remote_ip[4] = {192, 168, 1, 2};

int main()                                                          
{   
    stdio_init_all();
    sleep_ms(2000);
    network_init();

    while(true)
    {
        do_ping(SOCKET_ID, remote_ip);
        // SLping(remote_ip, 4);
        sleep_ms(500);
    }
}

void network_init(void)
{
    uint8_t temp;
    wizchip_initialize();
    printf("W5100s udp client example.\r\n");
    sleep_ms(2000);
    wizchip_setnetinfo(&net_info);
    print_network_information(get_info);
    sleep_ms(2000);   
}

2. 测试现象

编译烧录后,打开串行监视器,打开wireshark输入过滤条件<icmp>然后开启监听,可以看到在串口打印的配置信息,以及ping测试情况,wireshark的抓包情况,这里是通过软件实现的测试,硬件实现大家自行尝试;测试结果如下图所示:

相关链接

本章例程链接icon-default.png?t=N7T8https://gitee.com/wiznet-hk/w5100s-evb-pico-routine.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/954434.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【枚举区间】CF Edu10 C

Problem - C - Codeforces 题意&#xff1a; 思路&#xff1a; 应该反思一下这么典的思路为什么会想不到 枚举区间&#xff0c;一个很经典的套路是&#xff0c;枚举 l&#xff0c;对 r 计数 对于一个l&#xff0c;r取这么多限制中离 l 最近的那个 Code&#xff1a; #inclu…

一分钟科普:如何查看电脑型号?推荐五种常用方法,建议收藏

电脑型号是识别和区分不同电脑设备的关键。无论您是需要升级硬件、安装驱动程序&#xff0c;还是获取技术支持&#xff0c;了解电脑型号都能为您提供有用的信息。以下是几种查看电脑型号的方法&#xff1a; 方法一&#xff0c;物理标签查看法&#xff1a; 许多品牌的电脑在机身…

汽车服务门店小程序模板制作指南

在数字化时代&#xff0c;一个小程序的力量不可忽视。它不仅是展示品牌形象和提供用户服务的重要工具&#xff0c;更是扩大客户群体和提高营收的关键手段。对于汽车服务门店来说&#xff0c;拥有一个精美且功能齐全的小程序&#xff0c;更将成为你在竞争激烈的市场中的重要武器…

pdf文件打开后部分文字无法显示

场景&#xff1a;pdf文件在系统内预览正常&#xff0c;但是下载到本地电脑上&#xff0c;使用wps查看&#xff0c;部分标题会消失&#xff0c;只有标题里面的数字还能显示出来 经过一系列排查&#xff0c;发现查看的电脑上缺失了字体&#xff0c;使用wps查看时&#xff0c;缺失…

公交站牌部分代码

/*** 提交申请*/Log(title "维修业务", businessType BusinessType.UPDATE)PostMapping( "/submitApply/{id}")ResponseBodypublic AjaxResult submitApply(PathVariable Long id ,String variablesStr){try {System.out.println("variables: "…

多个Y轴的echarts图表组件

组件文件&#xff1a;<template><div class"wrap"><div ref"multipleLineChart" :style"{ height: height, width: width }" style"overflow:hidden"></div></div></template><script> exp…

【2D/3D RRT* 算法】使用快速探索随机树进行最佳路径规划(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

java八股文面试[多线程]——阻塞队列

阻塞队列大纲&#xff1a; 什么是阻塞队列 阻塞队列&#xff1a;从名字可以看出&#xff0c;他也是队列的一种&#xff0c;那么他肯定是一个先进先出&#xff08;FIFO&#xff09;的数据结构。与普通队列不同的是&#xff0c;他支持两个附加操作&#xff0c;即阻塞添加和阻塞删…

图像分类学习笔记(七)——MobileNet

一、MobileNetV1 传统的神经网络&#xff0c;内存需求大、运算量大&#xff0c;导致无法在移动设备以及嵌入式设备上运行。之前的VGG16模型权重大小大概有490M&#xff0c;ResNet模型权重大小大概有644M。MobileNet网络是由google团队在2017年提出的&#xff0c;专注于移动端或…

分析三维模型OBJ格式轻量化在网络传输中的重要性

分析三维模型OBJ格式轻量化在网络传输中的重要性 三维模型的OBJ格式轻量化在网络传输中扮演着重要的角色。随着互联网的快速发展和普及&#xff0c;越来越多的三维模型需要通过网络进行传输&#xff0c;涉及到下载、上传、共享等场景。而原始的三维模型文件往往较大&#xff0c…

正中优配:巨头深夜发声:向全社会开放!历史新高,万亿AI龙头火了!

当地时间8月30日周三&#xff0c;美股三大股指团体收涨&#xff0c;接连第四日收高。美股8月买卖进入尾声&#xff0c;出资者重视通胀与工作方面的一些重要经济数据。万亿AI巨子英伟达收涨0.98%&#xff0c;股价再创前史新高。 据百度官方微信大众号8月31日0时音讯&#xff0c…

vue3渲染函数h的简单使用——定义局部组件

vue3渲染函数h的简单使用 基本用法 创建 Vnodes Vue 提供了一个 h() 函数用于创建 vnodes&#xff1a; import { h } from vueconst vnode h(div, // type{ id: foo, class: bar }, // props[/* children */] )更多用法 详情查看官方文档 在SFC中定义局部组件使用 h函数…

【Qt学习】10 利用QSharedMemory实现单例运行

问题 让应用程序只有一个运行实例 QSharedMemory除了可以完成进程间通信&#xff0c;还可以实现应用程序单例化。 解法 首先&#xff0c;看看QSharedMemory的几个函数&#xff1a; 1、QSharedMemory(const QString &key, QObject *parent Q_NULLPTR)构造函数 该构造函数…

Ceph的纠删码特性 EC(Erasure Code)代码流程

从GitHub上Clone Ceph项目&#xff0c;我是基于(ceph version 12.2.11 luminous 版本)的代码来分析的 一、EC&#xff08;Erasure Code&#xff09;是什么&#xff1f; Ceph的纠删码特性EC&#xff1a;将写入的数据分成N份原始数据&#xff0c;通过这N份原始数据计算出M份效验…

html2canvas 截图空白 或出现toDataURL‘ on ‘HTMLCanvasElement或img标签没截下来 的所有解决办法

1.如果截图空白&#xff1a; 1.1以下的参数是必须要有的。 width: shareContent.offsetWidth, //设置canvas尺寸与所截图尺寸相同&#xff0c;防止白边height: shareContent.offsetHeight, //防止白边logging: true,useCORS: true,x:0,y:0,2&#xff0c;如果出现了报错 toData…

go gin gorm连接postgres postgis输出geojson

go gin gorm连接postgres postgis输出geojson 1. 技术环境 go-gin-gorm postgres-postgis 2. 简单实现代码 思路就是&#xff1a;采用原生sql实现查询、更新等&#xff0c;采用gorm的raw来执行sql语句 package mainimport ("fmt""net/http""github.…

23HW-0Day(漏洞检测Tools)V1.7—批量漏洞检测

工具更新一、 更新如下漏洞利用&#xff1a; 1、用友移动管理系统appmanager文件上传 2、用友移动管理系统category文件上传 3、用友U8CRM文件上传 4、用友U8CRM文件读取 5、用友U8-Cloud文件上传 6、致远OAM1移动协同软件命令执行 工具更新二、 本次更新&#xff0c;工具支…

游戏测试和软件测试有什么区别?

针对手游而言&#xff0c;游戏测试的本质是APP&#xff0c;所以不少手游的测试方式与APP测试异曲同工&#xff0c;然而也有所不同。APP更多的是具有一种工具&#xff0c;一款APP好不好用不重要&#xff0c;关键点在于实用。而游戏则具有一种玩具属性&#xff0c;它并不见得实用…

基于mike平原河网水动力学模块建模教程

Mike 11是在河流模拟中应用非常广泛的优秀软件&#xff0c;在洪水演进、实时洪水预报、水库和水工建筑物优化调度、水工建筑物设计、桥梁的水力设计、溃坝过程模拟、河流泥沙输移和河道演变、河流及湿地的生态及水质评估、水污染对流和扩散、突发日常水质污染事故预警方面得到了…

像linux 一样清理Windows C盘

像 linux 有命令 du -sh 查看文件夹大小 但是windows 可就没有这个命令了&#xff0c;就算有命令&#xff0c;也不能扫描子目录里面的文件 但是windows 可以借助 软件来清理&#xff0c;和linux 一样 文件上面是目录&#xff0c;下面是文件所占用空间大小的图&#xff0c;咋…