C++判断主机IP和指定端口是否能Ping通

#include <iostream>
#include <winsock.h>
#include <string>
#include <sstream>
#pragma comment(lib,"Ws2_32.lib")
using namespace std;

USHORT checksum(USHORT* buff, int size)
{
	unsigned long cksum = 0;
	while (size > 1)
	{
		cksum += *buff++;
		size -= sizeof(USHORT);
	}
	// 是奇数
	if (size)
	{
		cksum += *(UCHAR*)buff;
	}
	// 将32位的chsum高16位和低16位相加,然后取反
	cksum = (cksum >> 16) + (cksum & 0xffff);
	cksum += (cksum >> 16);  
	return (USHORT)(~cksum);
}
typedef struct icmp_hdr
{
	unsigned char   icmp_type;   // 消息类型
	unsigned char   icmp_code;   // 代码
	unsigned short icmp_checksum; // 校验和
								  // 下面是回显头
	unsigned short icmp_id;   // 用来惟一标识此请求的ID号,通常设置为进程ID
	unsigned short icmp_sequence; // 序列号
	unsigned long   icmp_timestamp; // 时间戳
} ICMP_HDR, *PICMP_HDR;
int SetTimeout(SOCKET s, int nTime, BOOL bRecv)
{
	int ret = ::setsockopt(s, SOL_SOCKET,
		bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));
	return ret != SOCKET_ERROR;
}
//检查主机IP是否ping通
bool PingIP(string szDestIP)
{
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(1, 1);
	if (WSAStartup(wVersionRequested, &wsaData))
	{
		printf("Winsock Initialization failed.\n");
		exit(1);
	}
	SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	SetTimeout(sRaw, 1000, TRUE);
	SOCKADDR_IN dest;
	dest.sin_family = AF_INET;
	dest.sin_port = htons(0);
	dest.sin_addr.S_un.S_addr = inet_addr(szDestIP.c_str());
	char buff[sizeof(ICMP_HDR) + 32];
	ICMP_HDR * pIcmp = (ICMP_HDR *)buff;
	pIcmp->icmp_type = 8;
	pIcmp->icmp_code = 0;
	pIcmp->icmp_id = (USHORT)::GetCurrentProcessId();
	pIcmp->icmp_checksum = 0;
	pIcmp->icmp_sequence = 0;
	memset(&buff[sizeof(ICMP_HDR)], 'E', 32);
	USHORT nSeq = 0;
	char revBuf[1024];
	SOCKADDR_IN from;
	int nLen = sizeof(from);
	static int nCount = 0;
	int nRet;
	pIcmp->icmp_checksum = 0;
	pIcmp->icmp_timestamp = ::GetTickCount();
	pIcmp->icmp_sequence = nSeq++;
	pIcmp->icmp_checksum = checksum((USHORT *)buff, sizeof(ICMP_HDR) + 32);
	nRet = ::sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (SOCKADDR *)&dest, sizeof(dest));
	if (nRet == SOCKET_ERROR)
	{
		printf("sendto() failed:%d\n", ::WSAGetLastError());
		return false;
	}
	nRet = ::recvfrom(sRaw, revBuf, 1024, 0, (sockaddr *)&from, &nLen);
	if (nRet == SOCKET_ERROR)
	{
		cout << szDestIP << " ping failed." << endl;
		return false;
	}
	cout << szDestIP << " ping success." << endl;
	closesocket(nRet);
	WSACleanup();
	return true;
}

// 检查指定IP的端口是否打开
bool PingIPPort(string Ipaddr, int Port)
{
	int mysocket;
	struct sockaddr_in my_addr;
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(1, 1);
	if (WSAStartup(wVersionRequested, &wsaData))
	{
		cout << "Winsock Initialization failed." << endl;
		return false;
	}
	if ((mysocket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
	{
		cout << "socket is invalid." << endl;
		return false;
	}
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(Port);
	my_addr.sin_addr.s_addr = inet_addr(Ipaddr.c_str());
	if (connect(mysocket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == SOCKET_ERROR)
	{
		cout << "failed to open the port." << endl;
		closesocket(mysocket);
		return false;
	}
	closesocket(mysocket);
	WSACleanup();
	return true;
}
int str2int(string str)
{
	istringstream is(str);
	int i;
	is >> i;
	return i;
}
int main()
{
	cout << "Please input \"IP:Port:\"";
	string str;
	cin >> str;
	string strIp = str.substr(0, str.find_last_of(':'));
	string strPort = str.substr(str.find_last_of(':') + 1, str.size() - 1);
	int Port = str2int(strPort);
	PingIP(strIp);
	if (PingIPPort(strIp, Port))
		cout << str << " is open." << endl;
	else
		cout << str << " is closed." << endl;
	system("pause");
	return 0;
}

Dev-C++是一款经典的跨平台C++集成开发环境(IDE),如果你想用它编写一个简单的ping程序,你需要了解ping程序的基本原理,它常使用操作系统提供的网络套接字API来发送ICMP回显请求(Echo Request)消息并接收响应。以下是一个简化的步骤和基本代码示例: 1. **打开Dev-C++**:首先在IDE中创建一个新的C++项目。 2. **包含头文件**:在`#include`部分,添加`<winsock2.h>`(Windows API)和`<icmp.h>`(用于处理ICMP消息)。 ```cpp #include <winsock2.h> #include <ws2tcpip.h> #include <string> ``` 3. **初始化Winsock**:在`main()`函数开始前,需要初始化Winsock库。 ```cpp WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { // 错误处理 return 1; } ``` 4. **定义结构体和枚举**:用来表示IP地址和错误信息。 ```cpp struct sockaddr_in targetAddress; int error; ``` 5. **设置目标地址**:指定你想ping主机IP地址。 ```cpp std::string host = "127.0.0.1"; // 或者目标服务器IP memset(&targetAddress, 0, sizeof(targetAddress)); targetAddress.sin_family = AF_INET; inet_pton(AF_INET, host.c_str(), &targetAddress.sin_addr); targetAddress.sin_port = htons(80); // ICMP默认端口是1(如果不需要指定) ``` 6. **创建套接字**:创建一个UDP套接字,并绑定到本地回环接口。 ```cpp SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); if (sock == INVALID_SOCKET) { // 错误处理 WSACleanup(); return 1; } ``` 7. **发送ping请求**:使用`sendto()`函数发送ICMP回显请求。 ```cpp error = sendto(sock, (char*)&icmp_echo_request, sizeof(icmp_echo_request), 0, (sockaddr*)&targetAddress, sizeof(targetAddress)); if (error == SOCKET_ERROR) { // 错误处理 closesocket(sock); WSACleanup(); return 1; } ``` 8. **接收和解析响应**:创建一个缓冲区来接收响应,然后检查是否为回显应答。 ```cpp char buffer[512]; error = recvfrom(sock, buffer, sizeof(buffer), 0, NULL, NULL); if (error == SOCKET_ERROR) { // 错误处理 closesocket(sock); WSACleanup(); return 1; } if (buffer == ICMP_ECHO_REPLY) { // 应答解析,获取时间戳等信息 // ... } else { // 非回显应答,处理错误 // ... } ``` 9. **关闭资源**:最后关闭套接字和清理Winsock。 ```cpp closesocket(sock); WSACleanup(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值