STM32 lwip freeRTOS实现ping

一、STM32CubeMX配置:

这里展示几个关键配置

1.打开ICMP功能,这个也是默认打开的。ping使用的就是ICMP协议

2.设置RAW模式接收字节数,这里默认是0,设置成和TCP、UDP一样

3.设置以太网中断优先级,这里需要调低,不然在freeRTOS中卡住,裸机中可不用设置

二、生成的代码中更改一些配置:

1.打开RAW功能

2.打开接收超时

三、代码

1.变量定义

typedef struct icmp_hdr

{

    unsigned char   icmp_type; // 消息类型

    unsigned char   icmp_code; // 代码

    unsigned short  icmp_checksum; // 校验和

    // 下面是回显头

    unsigned short  icmp_id; // 用来惟一标识此请求的ID号

    unsigned short  icmp_sequence; // 序列号

    unsigned long   icmp_timestamp; // 时间戳

} ICMP_HDR, *PICMP_HDR;



typedef struct _IPHeader// 20字节的IP头

{

    uint8_t     iphVerLen; // 版本号和头长度(各占4位)

    uint8_t     ipTOS; // 服务类型

    uint16_t    ipLength; // 封包总长度,即整个IP报的长度

    uint16_t    ipID;  // 封包标识,惟一标识发送的每一个数据报

    uint16_t    ipFlags; // 标志

    uint8_t     ipTTL; // 生存时间,就是TTL

    uint8_t     ipProtocol; // 协议,可能是TCP、UDP、ICMP等

    uint16_t    ipChecksum; // 校验和

    uint32_t    ipSource; // 源IP地址

    uint32_t    ipDestination; // 目标IP地址

} IPHeader, *PIPHeader;

typedef int SOCKET;

 

2.实现代码

int ETH_PingWork(const char * szDestIp)

{

long nRet = 0;

/*****************第一步:申请SOCKET************************************/

uint32_t ip = inet_addr(szDestIp);

SOCKET sRaw = lwip_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

if(sRaw == -1)

{

printf("Cannot create socket! Error %d\r\n", errno);

return errno;

}

// 设置接收超时

struct timeval tv_out;

tv_out.tv_sec = 1;

tv_out.tv_usec = 0;

nRet = setsockopt(sRaw, SOL_SOCKET,SO_RCVTIMEO, &tv_out, sizeof(tv_out));

if(-1 == nRet)

{

printf("Cannot set timeout! %d \r\n",errno);

}

/*****************第二步:组ICMP包************************************/

// 创建ICMP封包

char buff[sizeof(ICMP_HDR) + 32];

ICMP_HDR* pIcmp = (ICMP_HDR*)buff;

// 填写ICMP封包数据

pIcmp->icmp_type = 8; // 请求一个ICMP回显

pIcmp->icmp_code = 0;

pIcmp->icmp_id = (uint16_t)0x1234;

pIcmp->icmp_checksum = 0;

pIcmp->icmp_sequence = 0;

pIcmp->icmp_timestamp = 0xffff;

// 填充数据部分,可以为任意

memset(&buff[sizeof(ICMP_HDR)], 'E', 32);



/*****************第三步:发送ICMP包************************************/

//设置目的地址

struct sockaddr_in dest;

dest.sin_family = AF_INET;

dest.sin_port = htons(0);

dest.sin_addr.s_addr = ip;

//pIcmp->icmp_checksum = checksum((uint16_t*)buff, sizeof(ICMP_HDR) + 32);   //如果ping过去没回应需要屏蔽这条

//printf("icmp_checksum = %x\r\n",pIcmp->icmp_checksum);

nRet = (long)sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (struct sockaddr *)&dest, sizeof(dest));

if(nRet == -1)

{

printf(" sendto() failed: %d \r\n", errno);

return -1;

}

printf("sendto = %ld\r\n",nRet);        

/*****************第四步:接收ICMP包************************************/

char recvBuf[1024];

struct sockaddr_in from;

socklen_t nLen = sizeof(from);

nRet = (long)recvfrom(sRaw, recvBuf, 1024, 0, (struct sockaddr *)&from, &nLen);

if(nRet == -1)

{

printf(" recvfrom() failed: %d\r\n", errno);

return -1;

}

printf("recvfrom = %ld\r\n",nRet);

/*****************第五步:解析ICMP包************************************/

if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR))

{

printf(" Too few bytes from %s \r\n", inet_ntoa(from.sin_addr));

}

#if 0 // IP头解析

IPHeader * header = (IPHeader*)recvBuf;

struct in_addr a;

a.s_addr = header->ipSource;

printf("source ip %s\n", inet_ntoa(a));

a.s_addr = header->ipDestination;

printf("dest ip %s\n", inet_ntoa(a));

#endif

ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); // 接收到的数据中包含IP头,IP头大小为20个字节,所以加20得到ICMP头

if(pRecvIcmp->icmp_type != 0)// 回显

{

printf("nonecho type %d recvd \r\n", pRecvIcmp->icmp_type);

return -1;

}

if(pRecvIcmp->icmp_id != 0x1234)

{

printf(" someone else's packet! \r\n");

return -1;

}

printf(" %d bytes from %s:", (int)nRet, inet_ntoa(from.sin_addr));

printf(" icmp_seq = %d. ", pRecvIcmp->icmp_sequence);

printf(" \r\n");

return 0;

}

 

 

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值