ping工具的C语言简单实现 (ICMP echo)
来源:互联网 发布:焊接机器人编程 编辑:程序博客网 时间:2024/06/08 07:18
Windows和Linux 平台下都有一个使用非常频繁的工具: ping
此工具主要是检验网络中两节点间传递的数据包是否可达,计算耗时等,其原理是使用ICMP协议发送echo,并得到目的主机的回显。
以下是实现了最基本ping 功能的C程序,一共有三个文件:
icmphd.h —— 定义报文结构
icmphd.c ——实现其声明的函数
main.c —— 主函数入口
编译环境:
操作系统: win7 sp1
CPU :x86_64
编译器:
1) MinGW-GCC version 4.8.1 (tdm64-2)
2) Microsoft Visual Studio Ultimate 2012 version 11.0.50727.1 RTMREL
注:若使用的是MinGW-GCC,则编译时连接库: -lwsock32,否则因为编译器对函数的默认调用规则不同,无法在Windows SDK中找到
导出的符号(符号不匹配)。运行与调试时使用管理员权限,否则发送时报错,WinSock Error Code = 10013
源代码:
icmphd.h
/* author : ez date : 2014/10/20 describe : -*/#ifndef _ICMPHD_H_#define _ICMPHD_H_#include <stdint.h>#define DEF_DATA_LEN 0x10// random number// #define DEF_IDENTIFY0x0003#pragma pack (1)struct iphd {uint8_t m_cVersionAndHeaderLen;uint8_t m_cTypeOfService;uint16_t m_sTotalLenOfPacket;uint16_t m_sPacketID;uint16_t m_sSliceinfo;uint8_t m_cTTL;uint8_t m_cTypeOfProtocol;uint16_t m_sCheckSum;uint32_t m_uiSourIp;uint32_t m_uiDestIp;};struct icmphd {uint8_t type;uint8_t code;uint16_t chksum;uint16_t identifier;uint16_t seqnum; // big-endian};struct icmppk {struct icmphd hd;uint8_t data [DEF_DATA_LEN];};#pragma pack ()#define ICMPHD_SIZE (sizeof (struct icmphd))#define ICMPPK_SIZE (sizeof (struct icmppk))#define IPHD_SIZE(sizeof (struct iphd))extern struct icmppk* create_icmppk (uint8_t, uint8_t, uint16_t);#endif // ~ _ICMPHD_H_
icmphd.c
/* author : ez date : 2014/10/20 describe : -*/#include "icmphd.h"#include <stdlib.h>#include <string.h>#include <stdio.h>static uint16_t icmp_cal_cksum(uint8_t*, int);struct icmppk*create_icmppk (uint8_t _type, uint8_t _code, uint16_t _seq) {struct icmppk* pk = (struct icmppk*) malloc (ICMPPK_SIZE);if (pk != NULL) {int i = 0;memset (pk, 0, ICMPPK_SIZE);pk -> hd.type = _type;pk -> hd.code = _code;pk -> hd.identifier = 1;// big-endian((uint8_t*) (&(pk -> hd.seqnum))) [0] = (uint8_t) ((_seq & 0xff00) >> 8);((uint8_t*) (&(pk -> hd.seqnum))) [1] = _seq & 0x00ff;for (; i < DEF_DATA_LEN; i ++) // random datapk -> data [i] = i + '0';pk -> hd.chksum = icmp_cal_cksum ((uint8_t*) pk, ICMPPK_SIZE);}return pk;}static uint16_t icmp_cal_cksum(uint8_t* _data,int _data_len) { int sum = 0; int odd = _data_len & 0x01; uint16_t* value = (uint16_t*) _data; while (_data_len & 0xfffe) { sum += *(uint16_t*) _data; _data += 2; _data_len -= 2; } if (odd) { uint16_t tmp = ((*_data) << 8) & 0xff00; sum += tmp; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; }
main.c
/* author : ez date : 2015/7/11 describe : -*/#undef UNICODE#include "icmphd.h"#include <stdlib.h>#include <string.h>#include <stdio.h>#include <winsock2.h>#include <time.h>#if defined _WIN32 || defined _WIN64#include <windows.h> #endif #if !defined MAKEWORD#define MAKEWORD(low,high) ((WORD)(((BYTE)(low)) | ((WORD)((BYTE)(high))) << 8))#endif#pragma comment (lib, "ws2_32.lib")#define ADDR_OFFSET 1#define println(___STR) printf ("%s\n", ___STR)uint16_t sequence = 0;time_t start = 0, end = 0;uint32_t ip_num = 0;char* ip_char = NULL;struct icmppk* send_data;uint8_t* rcv_data;SOCKET sockfd = INVALID_SOCKET;struct sockaddr_in local;static struct icmppk*request_echo_icmp (/*const char* */);static voiddispose_resources ();static voidparse_reply_echo_icmp (struct icmppk*, void*);int ipstr_to_numeric (const char*, int *);staticvoid usage_disp () {printf ("Usage: ping <ip_address>\n");}static struct icmppk*request_echo_icmp (/*const char* _dst_addr */) {uint16_t ip_numeric = 0;struct icmppk* hd = NULL; // create icmp requesthd = create_icmppk (8, 0, ++ sequence);return hd;}static voidrcv_parse_reply_echo_icmp () {int rcv_len = 0;int frm_len = ICMPPK_SIZE;while (1) {rcv_len = recvfrom (sockfd, (char*) rcv_data, 0x100, 0,(struct sockaddr*) &local, &frm_len);if (rcv_len > 0) {struct icmppk* ptr = (struct icmppk*) (((uint8_t*) rcv_data) + IPHD_SIZE);if (((struct iphd*) rcv_data) -> m_uiSourIp == ip_num &&((struct iphd*) rcv_data) -> m_cTypeOfProtocol == IPPROTO_ICMP) {end = time (NULL);printf ("Reply from %s: bytes = %d, time = %d nm, req = %d, TTL = %d\n", ip_char,DEF_DATA_LEN, difftime (end, start),ntohs (ptr -> hd.seqnum),((struct iphd*) rcv_data) -> m_cTTL);start = end = 0;#ifdef _MSC_VERSleep (1000);#elif __GNUC__sleep (1);#endifbreak;} else continue;} else /*if (rcv_len == 0)*/continue;// else // break;}}static voiddisplay_frame (struct icmppk* _pk, int _len) {int i = 0;for (; i < _len; i ++)printf ("0x%02x ", ((uint8_t*) _pk) [i]);}int ipstr_to_numeric (const char* _str, int * _addr) {const char* index;unsigned char* addr = (unsigned char*) _addr;int isnumeric = 1;int i = 3;*_addr = 0;index = _str;while ((*index) && (isnumeric)) {if (isdigit ((unsigned char) *index))addr [i] = addr [i] * 10 + (*index - '0'); // big-endianelse if (*index == '.') {i --;if (i == -1) isnumeric = 0;} else isnumeric = 0;index ++;}if (isnumeric && i) return -1; // errorif (isnumeric) return 0; // successful}int main (int argc, char *argv []) { WSADATA wsaData; struct sockaddr_in hints;int remte_addr = 0;int timeout = 1000; int res;if (argc < 2) {usage_disp ();return 0;} // Initialize Winsock res = WSAStartup (MAKEWORD (2,2), &wsaData); if (res != 0) { printf("WSAStartup fault, error: %d\n", res); return 1; }rcv_data = (uint8_t*) malloc (0x100); memset (&hints, 0, sizeof (struct sockaddr_in)); memset (&local, 0, sizeof (struct sockaddr_in)); hints.sin_family = AF_INET;hints.sin_addr.s_addr = ip_num = inet_addr (ip_char = argv [ADDR_OFFSET]);local.sin_family = AF_INET;local.sin_addr.s_addr = inet_addr ("127.0.0.1"); sockfd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sockfd == INVALID_SOCKET) { printf ("Socket fault, error: %ld\n", WSAGetLastError ()); WSACleanup ();dispose_resources (); return 1; }printf ("Ping host %s\n", ip_char); while (1) {send_data = request_echo_icmp ();start = time (NULL);// send data to serverres = sendto (sockfd, (const char*) send_data, ICMPPK_SIZE, 0,(struct sockaddr*) &hints, sizeof (hints));if (res == SOCKET_ERROR) {printf ("Send Error : %d\n", WSAGetLastError ());closesocket (sockfd);WSACleanup ();dispose_resources ();return 1;}// receive from remotercv_parse_reply_echo_icmp ();} // shutdown (sockfd, SD_BOTH); closesocket (sockfd); WSACleanup(); dispose_resources (); return 0; }static voiddispose_resources () {rcv_data && ( free (rcv_data), (rcv_data = NULL));send_data && ( free (send_data), (send_data = NULL));}当然因为写的有点匆忙,很多地方还需要改进,本想做成跨平台的(Windows与Linux),也只写了一点点。还有输入的内容没有过滤等
很多问题,不过算是基本能用,下图是我截取的,在我的电脑上运行的结果。欢迎提出宝贵的意见。
0 0
- ping工具的C语言简单实现 (ICMP echo)
- C语言实现ICMP协议Ping命令
- C语言实现ICMP协议Ping命令
- ICMP 的 Ping 实现
- linux下Ping工具的C语言实现
- ping命令的C语言实现(linux, IPv4,简单版)
- ICMP 协议及 Ping程序的实现
- ICMP协议及ping程序的实现
- 基于ICMP协议的ping程序实现
- java实现ICMP协议的ping功能
- ICMP API实现ping
- SOCK_RAW, icmp, ping实现
- ping功能实现(ICMP)
- 用ICMP协议(C#)实现Ping程序-在公司最近十天的工作内容总结(四)
- c语言实现ping
- Ping/Echo节点监测机制的实现
- linux下ping的C语言实现
- 基于C语言实现的Ping程序
- Android中利用java反射机制Reflect
- Machine Learning week 4 One vs All and Neural network
- C#静态构造函数
- Java中单例设计模式
- 1066 Bash游戏
- ping工具的C语言简单实现 (ICMP echo)
- 窜梁鸿于海曲
- LeetCode(24) Swap Nodes in Pairs
- Apache Web Server -> httpd 的文档根目录 及 访问控制
- Ruby String(2)
- 遍历搜索空间的例子:熄灯问题
- 杭电1005Number Sequence
- Linux、xshell等中文乱码问题
- MVC传递数据-传递对象或对象集合