1、简述

一般情况下,我们想知道在当前电脑设备环境下,某一个网址能不能访问,最简单的方法是win + R 键 ,输入cmd,召唤cmd命令行程序,然后直接用ping命令 + 网址 来看返回的结果,那么我们是通过windows提供的工具来得到相应的结果,那我们能不能自己用代码实现呢?
答案肯定是可以的,在我们输入ping命令后,cmd.exe解析后就进行相应的操作,而我们就是去实现这个操作,下面就讲述一下如何用代码实现。

2、代码之路

我们先来看看用windows提供的cmd命令行程序通过ping命令得到的结果。
这里我们 ping 了 百度的网址,下图为 ping 了 两次得到的结果,我们发现返回来的实际IP地址不一样,这里也很容易理解,因为我们在浏览器访问一个网址,是经过DNS域名解析服务器根据主机名解析得到对应的IP地址,而百度在各个地方有多台服务器,所以这里返回的IP并不止一个。(这里简单提一下,详细请百度一下O(∩_∩)O)

我们可以直接ping + 域名(也就是网址) , 也可以 ping + IP(这里也就是域名对应的实际IP地址),我们看到,通过ping www.baidu.com ,我们可以看到实际的IP地址,这里我们也可以直接ping + IP得到返回结果。


我们也看到了通过ping可以得到域名对应的实际IP地址,那我们也可以通过代码来实现,并且能够返回域名对应的全部IP地址

域名解析实际IP地址

BOOL  GetRealIpByDomainName(char *szHost, char szIp[50][100], int *nCount)
{WSADATA wsaData;HOSTENT *pHostEnt;int nAdapter = 0;struct sockaddr_in   sAddr;if (WSAStartup(0x0101, &wsaData)){printf(" gethostbyname error for host:\n");return FALSE;}pHostEnt = gethostbyname(szHost);if (pHostEnt){while (pHostEnt->h_addr_list[nAdapter]){memcpy(&sAddr.sin_addr.s_addr, pHostEnt->h_addr_list[nAdapter], pHostEnt->h_length);sprintf_s(szIp[nAdapter], "%s", inet_ntoa(sAddr.sin_addr));nAdapter++;}*nCount = nAdapter;}else{DWORD  dwError = GetLastError();*nCount = 0;}WSACleanup();return TRUE;
}
//测试代码
void main()
{// 返回的域名对应实际IP的个数int nIpCount = 0;// 返回的域名对应实际I列表char szIpList[50][100];// 域名char szDomain[256] = { 0 };char szIp[1024] = { 0 };strcpy_s(szDomain, "www.baidu.com");GetIpByDomainName(szDomain, szIpList, &nIpCount);for (int i = 0; i < nIpCount; i++){strcat_s(szIp, szIpList[i]);strcat_s(szIp, "\t");}printf("DomainName : %s \n", szDomain);printf("Real IPList : %s", szIp);
}

测试结果

可以看出结果与用cmd命令行程序得到的结果一致。
这里 www.baidu.com 对应两个IP。这里是我这个地区得到的IP,其他地区以cmd命令行程序 ping的结果为准。ping的前提下是本地没有配置host文件,可以在 C:\Windows\System32\drivers\etc\hosts 这个文件中查看是否将某些域名配置成了固定的IP地址。

hosts简介

hosts文件其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应网页,如果没有找到,则系统会再将网址提交DNS域名解析服务器进行IP地址的解析。

hosts小应用

hosts文件就相当于本地网址的第一层过滤,可以把一些不想访问的网址进行过滤(比如恶意弹出的广告和网页游戏等),达到一层保护的效果
比如在hosts文件中添加 www.baidu.com 127.0.0.1 , 这样我们就访问不了百度网址了。

前几天也在某一篇文章中看到通过修改hosts文件配置可以过滤播放器的一些视频广告,具体做法详情百度一下哈 (^o^)/~。


C++ 实现 ping 功能

以下代码实现了我们的 cmd命令行程序中的ping 功能,但是只能够ping + IP 地址,不能够进行ping + 域名 ,需要配合上面的代码进行使用

parseurl.h

#pragma once#include <winsock2.h>
#include<stdlib.h>#pragma comment(lib, "Ws2_32.lib")#define DEF_PACKET_SIZE 32
#define ECHO_REQUEST 8
#define ECHO_REPLY 0struct IPHeader
{BYTE m_byVerHLen; //4位版本+4位首部长度BYTE m_byTOS; //服务类型USHORT m_usTotalLen; //总长度USHORT m_usID; //标识USHORT m_usFlagFragOffset; //3位标志+13位片偏移BYTE m_byTTL; //TTLBYTE m_byProtocol; //协议USHORT m_usHChecksum; //首部检验和ULONG m_ulSrcIP; //源IP地址ULONG m_ulDestIP; //目的IP地址
};struct ICMPHeader
{BYTE m_byType; //类型BYTE m_byCode; //代码USHORT m_usChecksum; //检验和 USHORT m_usID; //标识符USHORT m_usSeq; //序号ULONG m_ulTimeStamp; //时间戳(非标准ICMP头部)
};struct PingReply
{USHORT m_usSeq;DWORD m_dwRoundTripTime;DWORD m_dwBytes;DWORD m_dwTTL;
};class ParseUrl
{
public:ParseUrl();~ParseUrl();BOOL Ping(DWORD dwDestIP, PingReply *pPingReply = NULL, DWORD dwTimeout = 2000);BOOL Ping(char *szDestIP, PingReply *pPingReply = NULL, DWORD dwTimeout = 2000);
private:BOOL PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout);USHORT CalCheckSum(USHORT *pBuffer, int nSize);ULONG GetTickCountCalibrate();
private:SOCKET m_sockRaw;WSAEVENT m_event;USHORT m_usCurrentProcID;char *m_szICMPData;BOOL m_bIsInitSucc;
private:static USHORT s_usPacketSeq;
};

parseurl.cpp

#include "stdafx.h"
#include "parseurl.h"USHORT ParseUrl::s_usPacketSeq = 0;ParseUrl::ParseUrl() :
m_szICMPData(NULL),
m_bIsInitSucc(FALSE)
{WSADATA WSAData;WSAStartup(MAKEWORD(1, 1), &WSAData);m_event = WSACreateEvent();m_usCurrentProcID = (USHORT)GetCurrentProcessId();if ((m_sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0)) != SOCKET_ERROR){WSAEventSelect(m_sockRaw, m_event, FD_READ);m_bIsInitSucc = TRUE;m_szICMPData = (char*)malloc(DEF_PACKET_SIZE + sizeof(ICMPHeader));if (m_szICMPData == NULL){m_bIsInitSucc = FALSE;}}
}ParseUrl::~ParseUrl()
{WSACleanup();if (NULL != m_szICMPData){free(m_szICMPData);m_szICMPData = NULL;}
}BOOL ParseUrl::Ping(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout)
{return PingCore(dwDestIP, pPingReply, dwTimeout);
}BOOL ParseUrl::Ping(char *szDestIP, PingReply *pPingReply, DWORD dwTimeout)
{if (NULL != szDestIP){return PingCore(inet_addr(szDestIP), pPingReply, dwTimeout);}return FALSE;
}BOOL ParseUrl::PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout)
{//判断初始化是否成功if (!m_bIsInitSucc){return FALSE;}//配置SOCKETsockaddr_in sockaddrDest;sockaddrDest.sin_family = AF_INET;sockaddrDest.sin_addr.s_addr = dwDestIP;int nSockaddrDestSize = sizeof(sockaddrDest);//构建ICMP包int nICMPDataSize = DEF_PACKET_SIZE + sizeof(ICMPHeader);ULONG ulSendTimestamp = GetTickCountCalibrate();USHORT usSeq = ++s_usPacketSeq;memset(m_szICMPData, 0, nICMPDataSize);ICMPHeader *pICMPHeader = (ICMPHeader*)m_szICMPData;pICMPHeader->m_byType = ECHO_REQUEST;pICMPHeader->m_byCode = 0;pICMPHeader->m_usID = m_usCurrentProcID;pICMPHeader->m_usSeq = usSeq;pICMPHeader->m_ulTimeStamp = ulSendTimestamp;pICMPHeader->m_usChecksum = CalCheckSum((USHORT*)m_szICMPData, nICMPDataSize);//发送ICMP报文if (sendto(m_sockRaw, m_szICMPData, nICMPDataSize, 0, (struct sockaddr*)&sockaddrDest, nSockaddrDestSize) == SOCKET_ERROR){return FALSE;}//判断是否需要接收相应报文if (pPingReply == NULL){return TRUE;}char recvbuf[256] = { "\0" };while (TRUE){//接收响应报文if (WSAWaitForMultipleEvents(1, &m_event, FALSE, 100, FALSE) != WSA_WAIT_TIMEOUT){WSANETWORKEVENTS netEvent;WSAEnumNetworkEvents(m_sockRaw, m_event, &netEvent);if (netEvent.lNetworkEvents & FD_READ){ULONG nRecvTimestamp = GetTickCountCalibrate();int nPacketSize = recvfrom(m_sockRaw, recvbuf, 256, 0, (struct sockaddr*)&sockaddrDest, &nSockaddrDestSize);if (nPacketSize != SOCKET_ERROR){IPHeader *pIPHeader = (IPHeader*)recvbuf;USHORT usIPHeaderLen = (USHORT)((pIPHeader->m_byVerHLen & 0x0f) * 4);ICMPHeader *pICMPHeader = (ICMPHeader*)(recvbuf + usIPHeaderLen);if (pICMPHeader->m_usID == m_usCurrentProcID //是当前进程发出的报文&& pICMPHeader->m_byType == ECHO_REPLY //是ICMP响应报文&& pICMPHeader->m_usSeq == usSeq //是本次请求报文的响应报文){pPingReply->m_usSeq = usSeq;pPingReply->m_dwRoundTripTime = nRecvTimestamp - pICMPHeader->m_ulTimeStamp;pPingReply->m_dwBytes = nPacketSize - usIPHeaderLen - sizeof(ICMPHeader);pPingReply->m_dwTTL = pIPHeader->m_byTTL;return TRUE;}}}}//超时if (GetTickCountCalibrate() - ulSendTimestamp >= dwTimeout){return FALSE;}}
}USHORT ParseUrl::CalCheckSum(USHORT *pBuffer, int nSize)
{unsigned long ulCheckSum = 0;while (nSize > 1){ulCheckSum += *pBuffer++;nSize -= sizeof(USHORT);}if (nSize){ulCheckSum += *(UCHAR*)pBuffer;}ulCheckSum = (ulCheckSum >> 16) + (ulCheckSum & 0xffff);ulCheckSum += (ulCheckSum >> 16);return (USHORT)(~ulCheckSum);
}ULONG ParseUrl::GetTickCountCalibrate()
{static ULONG s_ulFirstCallTick = 0;static LONGLONG s_ullFirstCallTickMS = 0;SYSTEMTIME systemtime;FILETIME filetime;GetLocalTime(&systemtime);SystemTimeToFileTime(&systemtime, &filetime);LARGE_INTEGER liCurrentTime;liCurrentTime.HighPart = filetime.dwHighDateTime;liCurrentTime.LowPart = filetime.dwLowDateTime;LONGLONG llCurrentTimeMS = liCurrentTime.QuadPart / 10000;if (s_ulFirstCallTick == 0){s_ulFirstCallTick = GetTickCount();}if (s_ullFirstCallTickMS == 0){s_ullFirstCallTickMS = llCurrentTimeMS;}return s_ulFirstCallTick + (ULONG)(llCurrentTimeMS - s_ullFirstCallTickMS);
}

测试ping + Ip 代码


void main()
{ParseUrl objParseUrl;char *szDestIP = "112.80.248.73";PingReply reply;printf("Pinging %s with %d bytes of data:\n\n", szDestIP, DEF_PACKET_SIZE);for (int i = 0; i < 4; i++){objParseUrl.Ping(szDestIP, &reply);printf("Reply from %s: bytes=%ld time=%ldms TTL=%ld\n", szDestIP, reply.m_dwBytes, reply.m_dwRoundTripTime, reply.m_dwTTL);Sleep(500);}
}

测试结果


测试 结合域名解析实际IP地址 GetIpByDomainName方法

void pingIp(char Ip[100])
{ParseUrl objParseUrl;PingReply reply;printf("\nPinging %s with %d bytes of data:\n\n", Ip, DEF_PACKET_SIZE);for (int i = 0; i < 4; i++){objParseUrl.Ping(Ip, &reply);printf("Reply from %s: bytes=%ld time=%ldms TTL=%ld\n", Ip, reply.m_dwBytes, reply.m_dwRoundTripTime, reply.m_dwTTL);Sleep(500);}
}void main()
{int   nIpCount = 0;char  szIpList[50][100];char  szDomain[256] = { 0 };char  szIp[1024] = { 0 };strcpy_s(szDomain, "www.baidu.com");GetIpByDomainName(szDomain, szIpList, &nIpCount);printf("域名 : %s \n", szDomain);for (int i = 0; i < nIpCount; i++){pingIp(szIpList[i]);strcat_s(szIp, szIpList[i]);strcat_s(szIp, "\t");}printf("\n域名解析IP列表 : %s \n\n", szIp);
}

测试结果

注意

以上主要是用到了这个方法

BOOL ParseUrl::Ping(char *szDestIP, PingReply *pPingReply, DWORD dwTimeout)

这个方法中有三个参数,分别是ping的IP ,ping的返回结果以及ping超时时间,这里注意一下dwTimeout的值,在程序中我们默认dwTimeout为2s,即在2s内如果ping失败会不停地ping下去,直到2s结束,如果ping成功了直接返回,所以在ping的过程中调用Ping这个方法可能需要的时间不一样,如果很快就能ping通那么将立即返回,如果ping不通或者需要经过几次尝试才能ping通,那么就需要耗费一定的时间。所以,我们在ping一个IP的时候并不知道能否ping通,而如果我们程序在ping的时候不能阻塞很长时间,这就需要修改dwTimeout的值。

在最近工作中,我需要在界面打开时进行多个IP的ping操作,如果ping操作时间过长,界面将会卡住一段时间,所以这里就需要缩短ping超时的时间,但是并不是一味地将dwTimeout的值缩短越小越好,有时候明明能够ping通,却因为当前网络环境不好,同时dwTimeout的值设置非常小,导致可能ping不通,而dwTimeout的时间越长得到的结果可能更精确一些。所以这些都需要根据当前使用情况进行取舍,对dwTimeout的值进行合理设置


以上即为本篇文章的内容,通过两段代码结合实现了cmd命令行程序的ping功能,这里我们也可以用来判断当前设备有没有联网,在某些环境需要判断当前设备是否连接互联网是非常有必要的,在Qt QTcpSocket 对连接服务器中断的不同情况进行判定 这篇文章中,我们叙述了提供几种不同的方法检测客户端与服务器断开的几种方法,其中也提到了使用ping方法来判断本机是否联网,其中使用了Qt封装的库,直接调用即可,方便快捷,但是如果不是Qt程序,可以利用此篇文章提供的C++方法。

同时在Qt QTcpSocket 对连接服务器中断的不同情况进行判定 中也提到了一种更直接的方法,通过windows提供的IsNetworkAlive判断本地是否有网络连接,但是不能判断是否能访问互联网,这就需要通过ping 方法来判断了。可以直接在我贡献的资源中下载源码,进行使用。

代码下载

C++ 实现 ping 功能&& 域名(URL)解析实际 IP地址

C++ 实现 ping 功能 域名(URL)解析实际 IP地址相关推荐

  1. 个人博客搭建系列(一) 之 阿里云购买域名及解析对应ip地址

    前言 这不是前几天把个人博客搭好了么,想着买个域名对应到我服务器,然后最近会推出一系列的,从搭建博客到域名购买解析.配置ngnix的一套博客的搭建教程 那么,先厚着脸皮让大家瞅瞅我的博客: 蜕变的杨洋

  2. 网址(url),ip地址,域名,dns,hosts,服务器

    什么是服务器: 服务器最通俗的解释就是提供服务的机器 如何提供服务?提供什么服务?这很大程度上取决于用户了. 换一种说法,服务器也可以说成是一款性能更强,计算力更强的电脑.为什么这么说,因为电脑是用来 ...

  3. 国际域名及其他可解析域名免费捆绑动态IP地址

    国际域名及其他可解析域名免费捆绑动态IP地址   [ 日期:2004-09-25 ]   "让网络更免费更自由! 让所有国内的动态域名服务商破产!"本站推荐可解析三级域名:.COM ...

  4. 渗透测试-----信息收集(通过DNS解析找IP地址、CDN、IP查询、IP物理地址、搜索引擎、网站信息收集)

    文章目录 渗透测试 信息收集 一.IP地址信息收集 1. 通过DNS解析找IP地址 1.1 ping命令 1.2 nslookup命令 1.3 dig工具 1.4 dnsenum 1.5 站长工具 2 ...

  5. 引子 我想大家应该都很熟悉DNS了,这回在DNS前面加了一个D又变成了什么呢?这个D就是Dynamic(动态),也就是说,按照传统,一个域名所对应的IP地址应该是定死的,而使用了DDNS后,域名所对应

    引子 我想大家应该都很熟悉DNS了,这回在DNS前面加了一个D又变成了什么呢?这个D就是Dynamic(动态),也就是说,按照传统,一个域名所对应的IP地址应该是定死的,而使用了DDNS后,域名所对应 ...

  6. 实现一个域名对应多个IP地址和DNS优缺点详解!

    实现一个域名对应多个IP地址和DNS优缺点详解! 1.DNS定义: DNS(Domain Name System)是因特网的一项服务,它作为域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访 ...

  7. 全球免费公共 DNS 解析服务器 IP 地址列表推荐 (解决无法上网/加速/防劫持)

    全球免费公共 DNS 解析服务器 IP 地址列表推荐 基本上接触过网络相关知识的人应该多少都会听过 DNS 这个名词.因为 DNS 它非常重要,在我们上网的过程中扮演着重要的角色--"将网址 ...

  8. 全球免费公共【 DNS 】解析服务器 IP 地址列表推荐 【解决无法上网+加速+防劫持】

    全球免费公共 DNS 解析服务器 IP 地址列表推荐 (解决无法上网/加速/防劫持)    基本上接触过网络相关知识的人应该多少都会听过 DNS 这个名词.因为DNS 它非常重要,在我们上网的过程中扮 ...

  9. 计算机名和DNS域名的关系,域名、DNS、IP地址的对应关系

    什么是域名?什么是IP地址? 域名(英语:Domain Name),简称域名.网域,是由一串用点分隔的名字组成的上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置) ...

最新文章

  1. C++Primer学习——函数
  2. 小波降噪与重构例子 python
  3. 五周第四次课(4月23日)
  4. saml2_向SAML响应中添加自定义声明–(如何为WSO2 Identity Server编写自定义声明处理程序)...
  5. 如何用python处理txt_python处理txt文件操作
  6. java override报红_Eclipse @override报错解决
  7. java实现ip能访问_Java过滤ip,只允许配置的ip能够被访问
  8. HCIE-Security Day20:GRE协议:实验(一)配置基于静态路由的GRE隧道
  9. C语言汇编-函数调用堆栈的过程
  10. ADB Interface显示黄色惊叹号怎么办?
  11. 软件工程-实践者的研究方法第八版(不全)
  12. python自动视频剪辑_自动剪辑视频神器(适合自动剪 Vlog、视频教程等)
  13. android ios mp4格式转换,ios 开发 视频格式转换、mov转MP4
  14. 2019吉林大学计算机学硕考研,计算机科学与技术学院2019年硕士研究生复试基本要求...
  15. 高并发限流-漏桶算法和令牌桶算法
  16. php implode explode,PHP函数implode()与explode()的区别及数组与字符串互转的用法讲解...
  17. Android wifi 信号强度单位 dbm
  18. 卡券、直充下单接口文档
  19. 推荐一个和孩子玩24点游戏的工具:益乐24点
  20. 阿里云磁盘异常爆满的原因及解决方法

热门文章

  1. 计算机基础知识(2)
  2. WIFI6模块 802.11ac/ax AP6275S
  3. 如何将多个bin文件合成一个bin文件?(一)
  4. WinGate使用说明
  5. 工作学习中可能用到的网站
  6. 智能产品工厂测试软件,人工智能如何帮助工厂做质量检测
  7. 湖北开放学院金牌计算机专业,湖北开放职业学院“计算机基础知识大赛”成功举行...
  8. 80x86编程手册_编程从8到80
  9. 测量CAD图纸中2点之间的距离,有哪几种好用方法?
  10. 告警数下降10倍,携程实时智能检测平台实践