C++ 实现 ping 功能&& 域名(URL)解析实际 IP地址
2017-10-15 22:12
633 查看
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地址
测试结果
可以看出结果与用cmd命令行程序得到的结果一致。
这里 www.baidu.com 对应两个IP。这里是我这个地区得到的IP,其他地区以cmd命令行程序 ping的结果为准。ping的前提下是本地没有配置host文件,可以在 C:\Windows\System32\drivers\etc\hosts 这个文件中查看是否将某些域名配置成了固定的IP地址。
hosts简介
hosts小应用
C++ 实现 ping 功能
以下代码实现了我们的 cmd命令行程序中的ping 功能,但是只能够ping + IP 地址,不能够进行ping + 域名 ,需要配合上面的代码进行使用。
parseurl.h
parseurl.cpp
测试ping + Ip 代码
测试结果
测试 结合域名解析实际IP地址 GetIpByDomainName方法
测试结果
注意
以上主要是用到了这个方法
这个方法中有三个参数,分别是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地址
一般情况下,我们想知道在当前电脑设备环境下,某一个网址能不能访问,最简单的方法是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 0 struct IPHeader { BYTE m_byVerHLen; //4位版本+4位首部长度 BYTE m_byTOS; //服务类型 USHORT m_usTotalLen; //总长度 USHORT m_usID; //标识 USHORT m_usFlagFragOffset; //3位标志+13位片偏移 BYTE m_byTTL; //TTL BYTE 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; } //配置SOCKET sockaddr_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地址
- C++ 实现 ping 功能&& 域名(URL)解析实际 IP地址
- C++:模拟实现类似<time.h>的计时功能
- C语言实现ping功能(Linux & Mac OS系统下)有注释
- 用JS实现ping的功能(JS ping url)
- C++ 实现的netstat -an 的功能<转>-目的为获取rtmp推流地址如果是域名的话查看1935的ip
- 用C++&递归的方法实现二叉树的基本功能~
- C++实现ping功能
- C++之编码实现ping的功能
- Internet 主机 IP地址 域名 统一资源定位符URL 域名服务器 DNS 万维网 WWW IP地址访问失败 IPV4 & IPV6 统一资源标识符 URI 统一资源名称 URN IP地址(简介
- c语言winsock 实现简单的域名解析功能(DNS. v 1.0)
- 借助微软提供的url重写类库URLRewriter.dll(1.0)实现程序自动二级域名,域名需要泛解析
- c++ ping 功能实现
- linux 无法解析域名,但是可以ping通IP地址
- c/c++实现获取域名的IP地址
- C++实现ping功能
- C++实现ping功能<转>
- 通过C++和shell脚本去解析URL && c++调用shell脚本后将脚本的内容返回给程序
- 康威生命游戏 第一部分-基本功能实现(C++ & Windows SDK)
- IP地址库解析——读取IP地址获得实际地理位置信息的java源码实现