做嵌入式网络开发的,想必都用过电脑ping开发板测试网路是否连通,本人参考一些网上代码,完善了这个过程。
原文参考:http://blog.csdn.net/jtttl/article/details/50583462
http://bbs.21ic.com/icview-406625-1-1.html
读懂本文,需要掌握的基本知识
1.以太网ICMP数据包相关常识
2.ucos任务创建,消息邮箱的传递
3.lwip的基本知识
本文可能需要完善的地方:
1.对接收到的ping回复没有做判断,仅仅发了一个邮箱,这样网络中的其它ping回复命令它也会认为是自己的。(当然前面筛选过的话,就不会,需要验证)
先在以下函数中增加一个case分支,用来接收ping的回传。其中pingEchoReply为ucos的一个消息邮箱。ucos不是本文重点,略过。
void icmp_input(struct pbuf *p, struct netif *inp)
剩下部分直接贴上代码:
ping.c文件:
//==================================1.头文件声明开始================================== #include "ping.h" #include "lwip/raw.h" #include "DataProcess.h" #include "lwip/icmp.h" //==================================1.头文件声明结束================================== struct raw_pcb *ping_pcb; OS_EVENT * pingEchoReply; //ping回复任务 //fuc:建立pcb unsigned char icmp_pcb_init(void) { ping_pcb = raw_new(IP_PROTO_ICMP); if(!ping_pcb){ return 1; } } //fuc:组装icmp的报文 //fuc:发送icmp数据包 void ping_send(u8 ip_addr1,u8 ip_addr2,u8 ip_addr3,u8 ip_addr4) { struct pbuf *p; struct ip_addr ipAddr; struct icmp_echo_hdr *iecho; //本机地址 IP4_ADDR(&ipAddr, Para.MIP[0], Para.MIP[1], Para.MIP[2], Para.MIP[3]); ip_addr_set(&ping_pcb->local_ip, &ipAddr); //目标地址 IP4_ADDR(&ipAddr, ip_addr1, ip_addr2, ip_addr3, ip_addr4); ip_addr_set(&ping_pcb->remote_ip, &ipAddr); p = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr), PBUF_RAM); if(!p){ DebugMsg("ping send failed\r\n", 0); return; } //组装icmp的报文 iecho = (struct icmp_echo_hdr *)p->payload; iecho->type = 8; //类型 iecho->code = 0; //code iecho->id =htons(0x0200) ; //id iecho->seqno =htons(0x5800); //报文序列号 iecho->chksum = 0; //校验和清0 iecho->chksum = inet_chksum(p->payload, sizeof(struct icmp_echo_hdr));//从算校验和 //发送ping数据包 raw_sendto(ping_pcb, p, &ping_pcb->remote_ip); pbuf_free(p); } void PingTask(void *p_arg) { INT8U err; while(1) { OSTimeDlyHMSM(0, 0, 5, 0); //每5秒执行一次任务 ping_send(Para.GAT[0],Para.GAT[1],Para.GAT[2],Para.GAT[3]); //ping_send(192,168,1,27); OSSemPend(pingEchoReply,1500,&err); //请求信号量,并启动1.5s超时 if(err!=0){ //任务超时 DebugMsg("ping time out\r\n", 0); }else{ DebugMsg("ping success\r\n", 0); } DebugMsg("cur pipe=%d\r\n", My.DPipe); //打印当前通道 } } //ping任务创建 #define PING_STACK_SIZE (1024) #define PING_TASK_PRIO (5) static OS_STK PingOut_stack[PING_STACK_SIZE]; void PingTaskCreate(void) { icmp_pcb_init(); pingEchoReply = OSSemCreate(0); OSTaskCreate(PingTask, NULL,&PingOut_stack[PING_STACK_SIZE-1],PING_TASK_PRIO); }
ping.h文件(可以删掉一部分东西的):
#ifndef _PING_H_ #define _PING_H_ #include "ucos_ii.h" #ifdef __cplusplus extern "C" { #endif //====================================头文件声明开始================================== //====================================头文件声明结束================================== //====================================宏定义开始====================================== typedef int pid_t; #define IPPROTO_IP 0 /* dummy for IP */ #define IPPROTO_ICMP 1 /* control message protocol */ #define IPPROTO_IGMP 2 /* internet group management protocol */ #define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ #define IPPROTO_TCP 6 /* tcp */ #define IPPROTO_PUP 12 /* pup */ #define IPPROTO_UDP 17 /* user datagram protocol */ #define IPPROTO_IDP 22 /* xns idp */ #define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */ #define IPPROTO_RAW 255 /* raw IP packet */ #define IPPROTO_MAX 256 //====================================宏定义结束====================================== extern OS_EVENT * pingEchoReply; //ping回复任务 #endif