Icpm ping包实现设置数据包大小的C++代码
时间: 2023-10-01 16:11:37 浏览: 127
ICPM的实现Ping应答的实现-工业以太网讲义
下面是一个简单的使用 ICMP 协议发送 ping 包并设置数据包大小的 C++ 代码示例:
```c++
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <cerrno>
#include <chrono>
#include <thread>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
using namespace std;
const int PACKET_SIZE = 4096;
const int MAX_WAIT_TIME = 5;
const int MAX_NO_PACKETS = 4;
unsigned short checksum(unsigned short *buf, int len)
{
unsigned long sum = 0;
while (len > 1) {
sum += *buf++;
len -= 2;
}
if (len == 1) {
sum += *(unsigned char*)buf;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
int ping(const char *ip, int packet_size)
{
int sockfd;
struct sockaddr_in addr;
struct timeval tv_begin, tv_end, tv;
struct icmphdr *icmp;
char sendpacket[PACKET_SIZE];
char recvpacket[PACKET_SIZE];
int packetsize = packet_size;
int nsend = 0, nreceived = 0, nerrors = 0;
int i, j, len;
double rtt;
struct addrinfo hints, *res;
struct timeval timeout = {0, 1000}; // 1ms
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMP;
if (getaddrinfo(ip, NULL, &hints, &res) != 0) {
return -1;
}
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) {
return -1;
}
if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) {
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
cout << "PING " << ip << " (" << inet_ntoa(addr.sin_addr) << ")" << endl;
len = packetsize + sizeof(struct icmphdr);
memset(sendpacket, 0, len);
icmp = (struct icmphdr*)sendpacket;
icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->checksum = 0;
icmp->un.echo.id = getpid();
for (i = 0; i < packetsize; ++i) {
sendpacket[sizeof(struct icmphdr) + i] = 'A';
}
icmp->checksum = checksum((unsigned short*)sendpacket, len);
gettimeofday(&tv_begin, NULL);
for (i = 0; i < MAX_NO_PACKETS; ++i) {
if (sendto(sockfd, sendpacket, len, 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
++nerrors;
continue;
}
++nsend;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
fd_set fd_sets;
FD_ZERO(&fd_sets);
FD_SET(sockfd, &fd_sets);
int ret = select(sockfd + 1, &fd_sets, NULL, NULL, &timeout);
if (ret <= 0) {
continue;
}
if (recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, NULL, NULL) < 0) {
++nerrors;
continue;
}
++nreceived;
gettimeofday(&tv_end, NULL);
tv = tv_end;
timersub(&tv_end, &tv_begin, &tv);
rtt = tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
struct iphdr *iph = (struct iphdr*)recvpacket;
icmp = (struct icmphdr*)(recvpacket + iph->ihl * 4);
if (icmp->type == ICMP_ECHOREPLY && icmp->un.echo.id == getpid()) {
printf("%d bytes from %s: icmp_seq=%u ttl=%d time=%.2f ms\n",
packetsize, inet_ntoa(addr.sin_addr), icmp->un.echo.sequence, iph->ttl, rtt);
} else {
++nerrors;
}
}
printf("%d packets transmitted, %d received, %d%% packet loss, time %.2fms\n",
nsend, nreceived, (nerrors + nsend - nreceived) * 100 / nsend, rtt);
close(sockfd);
return nreceived;
}
int main(int argc, char *argv[])
{
if (argc < 2) {
cout << "Usage: " << argv[0] << " <ip> [packet size]" << endl;
return 1;
}
int packet_size = PACKET_SIZE;
if (argc >= 3) {
packet_size = atoi(argv[2]);
}
return ping(argv[1], packet_size);
}
```
你可以通过在命令行中运行命令 `g++ -o ping ping.cpp` 来编译这个程序,并使用 `./ping <ip> [packet size]` 来运行它。其中,`<ip>` 是你要 ping 的 IP 地址或主机名,`[packet size]` 是可选参数,表示 ping 包的数据包大小,如果不指定,默认为 4096 字节。
阅读全文