c++实现Ping程序
时间: 2024-05-02 10:20:49 浏览: 158
linux系统下用C程序实现Ping功能.rar_linux_linux c++ 系统 源码_linux ping_ping l
下面是一个简单的 C++ 实现 Ping 程序的示例代码:
```c++
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/ip_icmp.h>
using namespace std;
const int PACKET_SIZE = 4096;
const int ICMP_HEAD_SIZE = 8;
const int MAX_WAIT_TIME = 5; // 最大等待时间,单位秒
const int MAX_COUNT = 4; // 最大尝试次数
// 计算校验和
unsigned short CalcChecksum(unsigned short *addr, int len) {
unsigned int sum = 0;
while (len > 1) {
sum += *addr++;
len -= 2;
}
if (len == 1) {
sum += *(unsigned char*)addr;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
// 发送 ICMP 报文
int SendIcmpPacket(int sock_fd, const struct sockaddr *dest_addr, int seq) {
char packet[PACKET_SIZE];
memset(packet, 0, PACKET_SIZE);
struct icmp *icmp_hdr = (struct icmp*)packet;
icmp_hdr->icmp_type = ICMP_ECHO;
icmp_hdr->icmp_code = 0;
icmp_hdr->icmp_id = getpid();
icmp_hdr->icmp_seq = seq;
memset(icmp_hdr->icmp_data, 0xa5, PACKET_SIZE - ICMP_HEAD_SIZE);
icmp_hdr->icmp_cksum = CalcChecksum((unsigned short*)icmp_hdr, PACKET_SIZE);
int ret = sendto(sock_fd, packet, PACKET_SIZE, 0, dest_addr, sizeof(struct sockaddr));
if (ret == -1) {
cerr << "sendto error" << endl;
return -1;
}
return 0;
}
// 接收 ICMP 报文
int RecvIcmpPacket(int sock_fd, struct timeval &tv, struct sockaddr *from_addr) {
char packet[PACKET_SIZE];
socklen_t addr_len = sizeof(struct sockaddr);
int ret = recvfrom(sock_fd, packet, PACKET_SIZE, 0, from_addr, &addr_len);
if (ret == -1) {
cerr << "recvfrom error" << endl;
return -1;
}
struct iphdr *ip_hdr = (struct iphdr*)packet;
int ip_hdr_len = ip_hdr->ihl * 4;
struct icmp *icmp_hdr = (struct icmp*)(packet + ip_hdr_len);
int icmp_hdr_len = ret - ip_hdr_len;
if (icmp_hdr->icmp_type == ICMP_ECHOREPLY && icmp_hdr->icmp_id == getpid()) {
tv.tv_sec = time(NULL) - tv.tv_sec;
cout << icmp_hdr_len << " bytes from " << inet_ntoa(((struct sockaddr_in*)from_addr)->sin_addr) << ": icmp_seq=" << icmp_hdr->icmp_seq << " time=" << tv.tv_sec << "s" << endl;
return 0;
}
return -1;
}
// Ping 操作
int Ping(const char *ip_addr) {
int sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sock_fd < 0) {
cerr << "socket error" << endl;
return -1;
}
struct sockaddr_in dest_addr;
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr(ip_addr);
int seq = 0;
int count = 0;
while (count < MAX_COUNT) {
if (SendIcmpPacket(sock_fd, (struct sockaddr*)&dest_addr, seq) == -1) {
cerr << "SendIcmpPacket error" << endl;
return -1;
}
struct timeval tv;
gettimeofday(&tv, NULL);
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(sock_fd, &read_fds);
struct timeval timeout;
timeout.tv_sec = MAX_WAIT_TIME;
timeout.tv_usec = 0;
int ret = select(sock_fd + 1, &read_fds, NULL, NULL, &timeout);
if (ret < 0) {
cerr << "select error" << endl;
return -1;
} else if (ret == 0) {
cout << "Request timeout for icmp_seq " << seq << endl;
} else if (FD_ISSET(sock_fd, &read_fds)) {
if (RecvIcmpPacket(sock_fd, tv, (struct sockaddr*)&dest_addr) == -1) {
cerr << "RecvIcmpPacket error" << endl;
return -1;
}
}
seq++;
count++;
sleep(1);
}
close(sock_fd);
return 0;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " <ip address>" << endl;
return -1;
}
if (Ping(argv[1]) == -1) {
cerr << "Ping error" << endl;
return -1;
}
return 0;
}
```
该程序使用了原始套接字进行 ICMP 报文的发送和接收,并采用了 select 函数进行超时等待。在主函数中,程序需要传入目标 IP 地址进行 Ping 操作。程序会尝试发送指定次数的 ICMP 报文,并等待回应,如果超时则输出“Request timeout”,如果收到回应则输出“icmp_seq=xx time=xx”,其中 xx 表示 ICMP 报文的序列号和延迟时间。
阅读全文