本文共 6055 字,大约阅读时间需要 20 分钟。
使用socket函数创建套接字,并与uv_udp_t关联,可以实现对icmp包的发送和接收,实现类似ping命令的功能。
uv_loop_t* loop = uv_default_loop(); uv_udp_t* pUdp = new uv_udp_t; int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); uv_udp_init(loop, pUdp); uv_udp_open(pUdp, sock);
学习icmp协议和libuv关于udp,定时器的使用。
创建了ICMP的套接字,并与uv_udp_t关联
创建一个定时器,并与uv_udp_t关联,用于处理响应超时 构造并发送一个icmp包req 收到icmp包rsp,打印响应内容,关闭定时器,关闭uv_udp_t句柄 超时未收到rsp,打印超时,关闭uv_udp_t句柄,关闭定时器
需要注意的是:由于套接字协议是IPPROTO_ICMP,收到的包是包含IP头的。
///*在入口函数中包含 _CrtDumpMemoryLeaks(); 即可检测到内存泄露*/#define CRTDBG_MAP_ALLOC #include#include ////#include //for kbhit()#include "stdafx.h"#include "uv.h"#pragma pack(1)#define ICMP_ECHOREPLY 0#define ICMP_ECHOREQ 8#define REQ_DATASIZE 32 // Echo 请求数据的大小// IP Header -- RFC 791typedef struct tagIPHDR{ u_char VIHL; // Version and IHL u_char TOS; // Type Of Service short TotLen; // Total Length short ID; // Identification short FlagOff; // Flags and Fragment Offset u_char TTL; // Time To Live u_char Protocol; // Protocol u_short Checksum; // Checksum struct in_addr iaSrc; // Internet Address - Source struct in_addr iaDst; // Internet Address - Destination}IPHDR, *PIPHDR;// ICMP Header - RFC 792typedef struct tagICMPHDR{ u_char Type; // Type u_char Code; // Code u_short Checksum; // Checksum u_short ID; // Identification u_short Seq; // Sequence char Data; // Data}ICMPHDR, *PICMPHDR;// ICMP Echo Requesttypedef struct tagECHOREQUEST{ ICMPHDR icmpHdr; uint64_t dwTime; char cData[REQ_DATASIZE];}ECHOREQUEST, *PECHOREQUEST;// ICMP Echo Replytypedef struct tagECHOREPLY{ IPHDR ipHdr; ECHOREQUEST echoRequest; char cFiller[256];}ECHOREPLY, *PECHOREPLY;#pragma pack()//目的ipstruct sockaddr_in g_saDest;//icmp校验u_short in_cksum(u_short *addr, int len){ register int nleft = len; register u_short *w = addr; register u_short answer; register int sum = 0; while( nleft > 1 ) { sum += *w++; nleft -= 2; } if( nleft == 1 ) { u_short u = 0; *(u_char *)(&u) = *(u_char *)w ; sum += u; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return (answer);}void CreateIcmp(char* buff, ULONG* size){ ECHOREQUEST echoReq; static int nId = 1; static int nSeq = 1; int nRet; //构造请求 echoReq.icmpHdr.Type = ICMP_ECHOREQ; echoReq.icmpHdr.Code = 0; echoReq.icmpHdr.Checksum = 0; echoReq.icmpHdr.ID = nId++; echoReq.icmpHdr.Seq = nSeq++; for (nRet = 0; nRet < REQ_DATASIZE; nRet++) echoReq.cData[nRet] = ' '+nRet; //保存发送时间 echoReq.dwTime = uv_hrtime(); echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST)); memcpy(buff, &echoReq, sizeof(ECHOREQUEST)); *size = sizeof(ECHOREQUEST);}static void slab_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { /* up to 16 datagrams at once */ static char slab[16 * 64 * 1024]; buf->base = slab; buf->len = sizeof(slab);}static void on_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* rcvbuf, const struct sockaddr* addr, unsigned flags) { ECHOREPLY* r = (ECHOREPLY*)rcvbuf->base; struct sockaddr_in* ad = (struct sockaddr_in*)addr; uv_timer_t* pTimer = (uv_timer_t*)handle->data; char ip[64] = { 0}; uv_ip4_name(ad, ip, sizeof(ip)); if (nread == 0) { /* Everything OK, but nothing read. */ return; } if (memcmp(&g_saDest.sin_addr, &ad->sin_addr, sizeof(ad->sin_addr)) != 0) { return; } uint64_t now = uv_hrtime(); uint64_t time = now - (r->echoRequest.dwTime); double dtime = time / 1000000.0 ; printf("%d bytes form %s: icmp_seq=%d ttl=%d time=%.3f ms\n", sizeof(ECHOREQUEST) - sizeof(ICMPHDR), ip, (r->echoRequest.icmpHdr.Seq), r->ipHdr.TTL, dtime); //停止定时器,关闭定时器句柄 if(pTimer) { uv_timer_stop(pTimer); uv_close((uv_handle_t*)pTimer, NULL); } //停止udp的接收,关闭udp句柄 uv_udp_recv_stop(handle); uv_close((uv_handle_t*)handle, NULL);}static void on_send(uv_udp_send_t* req, int status) { uv_buf_t *buf = (uv_buf_t *)req->data; //发送完毕释放内存 delete [] buf->base; delete buf; delete req;}void timercb(uv_timer_t* req){ uv_udp_t* handle = (uv_udp_t*)req->data; //停止udp的接收,关闭udp句柄 uv_udp_recv_stop(handle); uv_close((uv_handle_t*)handle, NULL); printf("timeout\n"); //停止定时器,关闭定时器句柄 uv_timer_stop(req); uv_close((uv_handle_t*)req, NULL);}int _tmain(int argc, _TCHAR* argv[]){ //libuv环境初始化,内存分配 uv_loop_t* loop = uv_default_loop(); uv_udp_t* pUdp = new uv_udp_t; uv_timer_t* pTimer = new uv_timer_t; uv_udp_send_t *reqSend = new uv_udp_send_t; //设置ping的目的地址 const char* strDstIp = "192.168.10.1"; uv_ip4_addr(strDstIp, 0, &g_saDest); //创建发送数据的buf uv_buf_t *buf = new uv_buf_t; buf->base = new char[sizeof(ECHOREQUEST)] ; buf->len = sizeof(ECHOREQUEST); //创建套接字,设置关联 int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); uv_udp_init(loop, pUdp); uv_udp_open(pUdp, sock); //初始化定时器,做简单的数据关联,以便后续管理 uv_timer_init(loop, pTimer); pTimer->data = pUdp; pUdp->data = pTimer; reqSend->data = buf; //构造icmp请求报文 CreateIcmp(buf->base, &buf->len); printf("ping %s:\n", strDstIp); //发送icmp报文,启动udp接收,启动1s超时的定时器 uv_udp_send(reqSend, pUdp, buf, 1, (const sockaddr*)&g_saDest, on_send); uv_udp_recv_start(pUdp, slab_alloc, on_recv); uv_timer_start(pTimer, timercb, 1000, 0); uv_run(loop, UV_RUN_DEFAULT); //超时或收到响应后退出释放内存 delete pUdp; delete pTimer; //关闭loop printf("uv_loop_close ...\n"); uv_loop_close(loop); _CrtDumpMemoryLeaks(); getchar(); return 0;}
转载地址:http://mmkgf.baihongyu.com/