简单的实现了一个ping程序,没有做icmp差错报文的检查。

支持自定义字节数,支持发包个数

 #pragma pack(4)

 #define  ECHO_REQUEST        8
#define DATASIZE 65500
#define PACKETSIZE 65535 struct iphdr
{
unsigned char ip_hdr_len : ; //包头长度
unsigned char ip_version : ; //版本
unsigned char ip_tos; unsigned short ip_length; //总长度
unsigned short ip_identify;//标识
unsigned short ip_offset;//片偏移
unsigned char ip_ttl;
unsigned char ip_protocol;
unsigned short ip_cksum; struct in_addr ip_src; //源地址
struct in_addr ip_dst; //目的地址
}; struct icmphdr
{
unsigned char icmp_type; //8位类型
unsigned char icmp_code; //8位代码
unsigned short icmp_cksum; //16位的校验和 unsigned short icmp_identify;
unsigned short icmp_seq; LONGLONG icmp_timestamp;
char icmp_data[DATASIZE];
}; unsigned short checksum(int count,unsigned short* addr)
{
long sum = ; while(count > )
{
sum +=*addr++;
count -= sizeof(unsigned short);
} if(count > )
{
sum +=*(unsigned char*)addr;
} while(sum >> )
{
sum = (sum & 0xFFFF) + (sum >> );
} return (unsigned short)(~sum);
} void packet_pad(char * buf,int payload)
{
char pad[] = "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x7\x73\x74\x75\x76\x77"; int size = sizeof(pad) -;
int count = payload / size;
int remain = payload % size;
int offset = ; //偏移 memset((void *)buf,,payload); for(int i = ;i < count; ++i)
{
memcpy((void *)(buf + offset),(void *)pad,size);
offset += size;
} memcpy((void *)(buf + offset),(void *)pad,remain);
} LONGLONG getsystickcount64()
{
static LARGE_INTEGER tickspersecond = {};
LARGE_INTEGER tick; if(!tickspersecond.QuadPart)
{
QueryPerformanceFrequency(&tickspersecond);
} QueryPerformanceCounter(&tick); LONGLONG seconds = tick.QuadPart / tickspersecond.QuadPart;
LONGLONG leftPart = tick.QuadPart - (tickspersecond.QuadPart * seconds);
LONGLONG millseconds = ((leftpart << ) - ((leftpart << ) + (leftpart << ))) / tickspersecond.QuadPart;
LONGLONG ret = ((seconds << ) - ((seconds << ) + (seconds << ))) + millseconds; return ret;
}; bool ping(char * target,int payload,int count)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(, ), &wsaData); SOCKET soc = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
if(soc == -)
{
printf("create raw socket failed!\n");
return false;
} if(payload > DATASIZE)
{
printf("发送的字节数有错误,有效范围从 0 到 %d",DATASIZE);
return false;
} payload = payload - sizeof(LONGLONG); struct sockaddr_in addrsrv; addrsrv.sin_family = AF_INET;
addrsrv.sin_port = htons();
struct hostent* phostent = gethostbyname(target);
if (phostent)
{
addrsrv.sin_addr.s_addr = *(u_long *)phostent->h_addr_list[];
} printf("正在 Ping %s [%s] 具有 %d 字节的数据: \n",target,inet_ntoa(addrsrv.sin_addr),payload + sizeof(LONGLONG)); icmphdr ihdr = {}; memset((void *)ihdr.icmp_data,,DATASIZE);
packet_pad(ihdr.icmp_data,payload); //填充数据 ihdr.icmp_type = ECHO_REQUEST;
ihdr.icmp_identify = (unsigned short)GetCurrentProcessId(); int hdr_len = payload + sizeof(icmphdr) - DATASIZE; struct timeval timeout;
struct sockaddr_in addrcli; char recv[PACKETSIZE] = {}; unsigned long interval = ;
unsigned long avgdelay = ;
unsigned long maxdelay = ;
unsigned long mindelay = ~; unsigned int sndcnt = count;
unsigned int loscnt = ; for(int seq = ; seq < count; ++seq)
{
memset((void *)recv,,PACKETSIZE); ihdr.icmp_seq = seq;
ihdr.icmp_cksum = ;
ihdr.icmp_timestamp = getsystickcount64(); //时间戳
ihdr.icmp_cksum = checksum(hdr_len,(unsigned short *)&ihdr); if(sendto(soc,(char *)&ihdr,hdr_len,,(sockaddr *)&addrsrv,sizeof(addrsrv)) == -)
{
--sndcnt;
continue;
} int nlength = sizeof(addrcli);
timeout.tv_sec = ;
timeout.tv_usec = ; setsockopt(soc, SOL_SOCKET,SO_RCVTIMEO, (char*)&timeout,sizeof(timeout)); if(recvfrom(soc,recv,PACKETSIZE,,(sockaddr *)&addrcli,&nlength) == -)
{
printf("请求超时!\n");
++loscnt;
continue;
} iphdr* piphdr = (iphdr *)recv;
if(checksum(piphdr->ip_hdr_len << ,(unsigned short *)piphdr) != )
{
printf("invalid ip packet!\n");
continue;
} icmphdr* pichdr = (icmphdr *)(piphdr + );
if(checksum(hdr_len,(unsigned short *)pichdr) != )
{
printf("invalid icmp packet!\n");
continue;
} interval = getsystickcount64() - pichdr->icmp_timestamp;
avgdelay+= interval; maxdelay = interval > maxdelay ? interval : maxdelay;
mindelay = interval > mindelay ? mindelay : interval; printf("来自 %s 的回复: 字节=%d 时间=%dms TTL=%u\n",inet_ntoa(addrsrv.sin_addr),payload + sizeof(LONGLONG),interval,piphdr->ip_ttl); Sleep();
} printf("\n");
printf("%s 的 Ping 统计信息: \n",inet_ntoa(addrsrv.sin_addr));
printf(" 数据包: 已发送 = %d, 已接收 = %d, 丢失 = %d (%.2f%% 丢失),\n",sndcnt,sndcnt-loscnt,loscnt,(loscnt * ) / (double)sndcnt);
printf("往返行程的估计时间(以毫秒为单位):\n");
printf(" 最短 = %dms, 最长 = %dms, 平均 = %dms\n",mindelay,maxdelay,avgdelay / sndcnt);
printf("\n");
} int main(int argc,char * argv[])
{
ping("www.baidu.com",,);
return ;
}

TCP协议学习记录 (二) Ping程序的更多相关文章

  1. TCP协议学习记录 (三) Ping程序 RR选项 记录路由hop

    一开始想直接在上个程序改,自己构造IP包头,但后来发现不行,微软不让干了,所以后来选用libcap库来收发包 代码写的很乱.. #pragma pack(4) #define ECHO_REQUEST ...

  2. TCP协议学习记录 (一) ICMP时间戳请求

    程序只实现了获取时间戳,至于将时间戳转换成具体日期和时间,暂时没有好的办法. #define TIME_STAMP_REQUEST 13 struct iphdr { unsigned ; //包头长 ...

  3. TCP/IP协议学习之实例ping命令学习笔记

    TCP/IP协议学习之实例ping命令学习笔记(一) 一. 目的为了让网络协议学习更有效果,在真实网络上进行ping命令前相关知识的学习,暂时不管DNS,在内网中,进行2台主机间的ping命令的整个详 ...

  4. [网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序]

    [网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序] 为何学习socket套接字一定要先学习互联网协议: 1.首先:要想开发一款自己的C/S架构软件,就必须掌握socket ...

  5. Material Calendar View 学习记录(二)

    Material Calendar View 学习记录(二) github link: material-calendarview; 在学习记录一中简单翻译了该开源项目的README.md文档.接下来 ...

  6. Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客

    ==他的博客应该不错,没有细看 Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客 http://blog.csdn.net/u012706811/article/det ...

  7. JavaScript学习记录二

    title: JavaScript学习记录二 toc: true date: 2018-09-13 10:14:53 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...

  8. 2.VUE前端框架学习记录二

    VUE前端框架学习记录二:Vue核心基础2(完结)文字信息没办法描述清楚,主要看编码实战里面,有附带有一个完整可用的Html页面,有需要的同学到脑图里面自取.脑图地址http://naotu.baid ...

  9. 网络协议学习笔记(二)物理层到MAC层,交换机和VLAN,ICMP与ping原理

    概述 之前网络学习笔记主要讲解了IP的诞生,或者说整个操作系统的诞生,一旦有了IP,就可以在网络的环境里和其他的机器展开沟通了.现在开始给大家讲解关于网络底层的相关知识. 从物理层到MAC层:如何在宿 ...

随机推荐

  1. Oracle11g导出空表

    # Oracle11g导出空表 <!-- create time: 2015-06-01 23:35:24 --> ###原因 11G中有个新特性,当表无数据时,不分配`segment`, ...

  2. 【Python】pymongo使用

    官方文档:http://api.mongodb.com/python/current/index.html MongoReplicaSetClient:http://api.mongodb.com/p ...

  3. Table of Contents ---BCM

    Table of ContentsAbout This Document................................................................ ...

  4. Spring urlMapping

    背景 某url性能测试表明,qps单机最高只有4000多,虽然靠堆机器可以解决问题,但是显然不是什么优雅的方案. 试着把controller里的所有的逻辑都屏蔽,只是简单的返回hello world, ...

  5. 格式化namenode,造成无法启动datanode

    一个常见的问题:格式化namenode,造成无法启动datanode的问题.     问题描述:   无法启动datanode,查看日志,datanote尝试n次启动无效后,会出现这个语句 INFO ...

  6. linux 获取线程号

    #include <sys/types.h> pid_t gettid(void); 如果系统库里没有,则可以这样做: #include <sys/syscall.h> pid ...

  7. XidianOJ 1041: Franky的游戏O

    题目描述 Franky是super的人造人,来到了n*m的棋盘世界玩冒险游戏. n×m的棋盘由n行每行m个方格组成,左上角的方格坐标是(0,0),右下角的方格坐标是(n-1,m-1). 每次游戏时,他 ...

  8. calculator

    #include <stdio.h> #include <stdlib.h> typedef enum { FALSE = , TRUE }BOOL; void calcula ...

  9. SQL初级语法 [查询: SELECT]

    SQL查询: SELECT 普通查询: SELECT "栏位名" FROM "表格名" DISTINCT 查询:(去掉重复) SELECT DISTINCT & ...

  10. java中的那些坑

    最近准备换工作,为了少让人家鄙视,就要狠狠地藐视这些面试题目.找了本电子书,发了有好多坑,都是特别简单,但是很少有人做对的题目.面对这样的题目,我却有一种兴奋的感觉,也许是因为一直做着重复的工作没有新 ...