简单的实现了一个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. js 页面刷新方法

    1.reload方法,该方法强迫浏览器刷新当前页面语法:location.reload([bForceGet])参数:bForceGet,可选参数,默认为false从客户端缓存里取当前页.true,则 ...

  2. Sql获取数据集中各类型中的最大值(最新值)

    select * from  (    SELECT t.*,ROW_NUMBER() over (partition by t.pid order by t.op_time desc) num    ...

  3. JQUERY DIALOG窗格内不能使用FORM

    今天在做AJAX DIALOG数据提交实验,实验目的是,在DIALOG内显示另一页面,并将FORM组件信息提交保存至数据库.代码如下: DIALOG实现: function OpenDialog(ur ...

  4. Find out files transfered via Bluetooth

    The case was about business secret and forensic guy did a physical acquisition from a smart phone. H ...

  5. Python-lambda函数,map函数,filter函数

    lambda函数主要理解: lambda 参数:操作(参数). lambda语句中,冒号前是参数,可以有多个,用逗号隔开,冒号右边的返回值.lambda语句构建的其实是一个函数对象 map函数: ma ...

  6. thinkPHP-空操作

    空操作 当访问的方法不存在时,可以定义一个empty方法来避免空操作 function _empty() { echo "网页不存在,请检查地址信息"; } 这样当访问不存在的方法 ...

  7. IntelliJ IDEA 15.0.2远程debug tomcat

    背景 在最近的java项目中使用了linux环境下编译的so文件,所以无法在window环境下debug,故此有了这篇文章 环境 jdk:jdk-8u101-linux-x64 os:CentOS r ...

  8. web.config中的HttpCookie.HttpOnly属性

    Abstract: The program does not set the HttpCookie.HttpOnly property to true. Explanation: The defaul ...

  9. RabbitMQ 入门指南(Java)

    RabbitMQ是一个受欢迎的消息代理,通常用于应用程序之间或者程序的不同组件之间通过消息来进行集成.本文简单介绍了如何使用 RabbitMQ,假定你已经配置好了rabbitmq服务器. Rabbit ...

  10. .NET Framework 框架的一些简单介绍

    20世纪90年代以来出现的3种典型的组件技术: 1)OMC(对象组件模型)的CORBA2)Microsoft的COM/DCOM3)Sun公司的JavaBeans 在2002年,微软发布了.NET框架的 ...