TCP协议学习记录 (二) Ping程序
简单的实现了一个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程序的更多相关文章
- TCP协议学习记录 (三) Ping程序 RR选项 记录路由hop
一开始想直接在上个程序改,自己构造IP包头,但后来发现不行,微软不让干了,所以后来选用libcap库来收发包 代码写的很乱.. #pragma pack(4) #define ECHO_REQUEST ...
- TCP协议学习记录 (一) ICMP时间戳请求
程序只实现了获取时间戳,至于将时间戳转换成具体日期和时间,暂时没有好的办法. #define TIME_STAMP_REQUEST 13 struct iphdr { unsigned ; //包头长 ...
- TCP/IP协议学习之实例ping命令学习笔记
TCP/IP协议学习之实例ping命令学习笔记(一) 一. 目的为了让网络协议学习更有效果,在真实网络上进行ping命令前相关知识的学习,暂时不管DNS,在内网中,进行2台主机间的ping命令的整个详 ...
- [网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序]
[网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序] 为何学习socket套接字一定要先学习互联网协议: 1.首先:要想开发一款自己的C/S架构软件,就必须掌握socket ...
- Material Calendar View 学习记录(二)
Material Calendar View 学习记录(二) github link: material-calendarview; 在学习记录一中简单翻译了该开源项目的README.md文档.接下来 ...
- Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客
==他的博客应该不错,没有细看 Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客 http://blog.csdn.net/u012706811/article/det ...
- JavaScript学习记录二
title: JavaScript学习记录二 toc: true date: 2018-09-13 10:14:53 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...
- 2.VUE前端框架学习记录二
VUE前端框架学习记录二:Vue核心基础2(完结)文字信息没办法描述清楚,主要看编码实战里面,有附带有一个完整可用的Html页面,有需要的同学到脑图里面自取.脑图地址http://naotu.baid ...
- 网络协议学习笔记(二)物理层到MAC层,交换机和VLAN,ICMP与ping原理
概述 之前网络学习笔记主要讲解了IP的诞生,或者说整个操作系统的诞生,一旦有了IP,就可以在网络的环境里和其他的机器展开沟通了.现在开始给大家讲解关于网络底层的相关知识. 从物理层到MAC层:如何在宿 ...
随机推荐
- spring 定时器Quartz
一.Quartz是什么 二. 核心接口 scheduler --- 核心调度器 Job --- 任务 JobDetail --- 任务描述 Tigger --- 触发器 三 . 核心接口之间 ...
- jquery.validate[.unobtrusive]和Bootstrap实现tooltip错误提示
类似的文章园子里已有,请看这里,个人感觉稍显复杂,日前也打算写一个简单的给项目用,一些关键点记录于此.最终效果如下: 后端使用Asp.net mvc5,前端框架有:jquery.validate.jq ...
- CMakeLists.txt for nginx
project(nginx) cmake_minimum_required(VERSION 2.8) aux_source_directory(. SRC_LIST) aux_source_direc ...
- Memcache的使用和协议分析详解
Memcache的使用和协议分析详解 作者:heiyeluren博客:http://blog.csdn.NET/heiyeshuwu时间:2006-11-12关键字:PHP Memcache Linu ...
- java ppt课后作业
1 .仔细阅读示例: EnumTest.java,运行它,分析运行结果? 枚举类型是引用类型,枚举不属于原始数据类型,它的每个具体值都引用一个特定的对象.相同的值则引用同一个对象.可以使用“==”和e ...
- 通过类名获取spring里的Bean
import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactor ...
- 读取excel数据,并统计输出Frame版本
package cn.cnnic.ops; import java.awt.Button; import java.awt.FileDialog; import java.awt.FlowLayout ...
- 给VMware下的Linux扩展磁盘空间(以CentOS6.5为例)
#查看挂载点:df -h#显示: 文件系统 容量 已用 可用 已用%% 挂载点/dev/mapper/vg_dc01-lv_root47G 12G 34G 25% /tmpfs 504M 88K 50 ...
- {HDU}{2516}{取石子游戏}{斐波那契博弈}
题意:给定一堆石子,每个人最多取前一个人取石子数的2被,最少取一个,最后取石子的为赢家,求赢家. 思路:斐波那契博弈,这个题的证明过程太精彩了! 一个重要的定理:任何正整数都可以表示为若干个不连续的斐 ...
- VC++ 6.0远程调试配置
VC开发环境之所以提供远程调试的能力,是因为有些情况下单机调试会让你崩溃掉...比如,调试GUI程序的WM_PAINT消息,因为要单步调试,所以调试器会对界面的重绘产生副作用(Heisenberg不确 ...