我用C++,icmp制作了Ping程序.但它不适用于安卓
I made Ping Program using C++, icmp. But it doesnt work on android
这是ping代码。在select
函数之后,retval 仅为 0。我检查了这在 mac OS 上运行良好。我检查了很多IP。但它不仅适用于安卓设备。我不知道是什么问题。我第一次使用 SOCK_RAW 制作了套接字,但它仅适用于超级用户。所以我SOCK_DGRAM改了。它适用于普通用户的 Mac OS。和它有关吗?
int ping(string target)
{
int s, i, cc, packlen, datalen = DEFDATALEN;
struct hostent *hp;
struct sockaddr_in to, from;
struct ip *ip;
u_char *packet, outpack[MAXPACKET];
char hnamebuf[MAXHOSTNAMELEN];
string hostname;
struct icmp *icp;
int ret, fromlen, hlen;
fd_set rfds;
struct timeval tv;
int retval;
struct timeval start, end;
int end_t;
bool cont = true;
to.sin_family = AF_INET;
to.sin_addr.s_addr = htonl(inet_addr(target.c_str()));
//to.sin_port = 0;
if (to.sin_addr.s_addr != (u_int)-1)
{
hostname = target;
pErrorLabel->setString(hostname);
}
else
{
hp = gethostbyname(target.c_str());
if (!hp)
{
pErrorLabel->setString("Unknown host");
cerr << "unknown host " << target << endl;
return -1;
}
to.sin_family = hp->h_addrtype;
bcopy(hp->h_addr, (caddr_t)&to.sin_addr, hp->h_length);
strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
hostname = hnamebuf;
}
packlen = datalen + MAXIPLEN + MAXICMPLEN;
if ((packet = (u_char *)malloc((u_int)packlen)) == NULL)
{
pErrorLabel->setString("malloc error");
cerr << "malloc errorn";
return -1;
}
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)) < 0)
{
pErrorLabel->setString("administrator");
return -1; /* Needs to run as superuser!! */
}
icp = (struct icmp *)outpack;
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = 12345;
icp->icmp_id = getpid();
cc = datalen + ICMP_MINLEN;
icp->icmp_cksum = in_cksum((unsigned short *)icp, cc);
gettimeofday(&start, NULL);
i = sendto(s, (char *)outpack, cc, 0, (struct sockaddr*)&to, (socklen_t)sizeof(struct sockaddr_in));
if (i < 0 || i != cc)
{
if (i < 0)
perror("sendto error");
cout << "wrote " << hostname << " " << cc << " chars, ret= " << i << endl;
}
FD_ZERO(&rfds);
FD_SET(s, &rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;
std::stringstream ss;
ss << "socket=" << (int)s;
pErrorLabel->setString(ss.str().c_str());
while (cont)
{
retval = select(s + 1, &rfds, NULL, NULL, &tv);
if (retval == -1)
{
perror("select()");
pErrorLabel->setString("select()");
return -1;
}
else if (retval)
{
fromlen = sizeof(sockaddr_in);
if ((ret = recvfrom(s, (char *)packet, packlen, 0, (struct sockaddr *)&from, (socklen_t*)&fromlen)) < 0)
{
perror("recvfrom error");
pErrorLabel->setString("recvfrom error");
return -1;
}
// Check the IP header
ip = (struct ip *)((char*)packet);
hlen = sizeof(struct ip);
if (ret < (hlen + ICMP_MINLEN))
{
cerr << "packet too short (" << ret << " bytes) from " << hostname << endl;;
return -1;
}
// Now the ICMP part
icp = (struct icmp *)(packet + hlen);
if (icp->icmp_type == ICMP_ECHOREPLY)
{
if (icp->icmp_seq != 12345)
{
cout << "received sequence # " << icp->icmp_seq << endl;
continue;
}
if (icp->icmp_id != getpid())
{
cout << "received id " << icp->icmp_id << endl;
continue;
}
cont = false;
}
else
{
continue;
}
gettimeofday(&end, NULL);
end_t = 1000000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);
if (end_t < 1)
end_t = 1;
cout << "Elapsed time = " << end_t << " usec" << endl;
return end_t;
}
else
{
cout << "No data within one seconds.n";
return 0;
}
}
return 0;
}
在 Android 上,您无法从非原始套接字读取 ip 标头,您需要在接收的数据中获取正确的 icmp 标头偏移量,无论是否带有 ip 标头。
我修改了代码,因此它可以在Androi或MacOS上运行
...
// Check the IP header
ip = (struct ip *)((char*)packet);
// ip_hl means: the number of 32-bit words in the header
// On Android, you just can't get ip header from a none RAW socket, and there's direct icmp header in packet buffer
// If ip points to actually icmp header, the ip_hl will be zero according to the icmp echo reply's layout.
// So hlen can be safely used to jump the icmp header part with or without ip header.
hlen = ip->ip_hl * 4; // before modify is: hlen = sizeof(struct ip);
if (ret < (hlen + ICMP_MINLEN))
{
cerr << "packet too short (" << ret << " bytes) from " << hostname << endl;;
return -1;
}
// Now the ICMP part
icp = (struct icmp *)(packet + hlen);
...
相关文章:
- FLTK 2.0构建和演示,适用于VS2019的2011年左右的代码库
- "string.h"在构建适用于iOS的qt应用程序中找不到消息
- 为什么 std::erase(std::erase_if) 不是适用于<algorithm>任何容器的模板?
- 为什么这适用于 G++ 而不是 CLANG?
- 为什么不区分大小写适用于 std::unordered_set的 std::hash 函数?
- 声明适用于 auto,但不能显式声明类型?
- 什么是通用运行时组件 #ifdef 适用于Windows(UWP)而不是iOS
- Windows 上的 Cmake 不添加共享库路径(适用于 linux)
- Typedef适用于结构,但不适用于枚举,仅适用于C++
- 为什么函数模板不理解 NULL,但适用于 nullptr
- 链接器读取库,但在其中找不到符号?未解析的外部符号,但仅适用于 Win32 而不是 x64
- Netbeans 8.1(适用于 C/C++)找不到我的编译器(gcc-6.0.0 开发版本)
- random_shuffle() 适用于 Windows,但不能在 Linux 上编译
- C++指针到方法模板推导在面向 x86 时不编译,但适用于 x64
- 不在异常中嵌入std::字符串的规则是否仍然适用于move构造函数
- 移动文件夹Windows c++:适用于Vista及以上版本,不包括XP
- 适用于Android的Qt找不到任何兼容的设备答案找到但不知道如何
- 在Windows 7上不起作用,但它适用于Windows 8 dll。
- 可变参数模板转换为 std::function<R(ARGS...)>适用于 GCC 而不是 MSVC2013,为什么?
- C++11 cmath 函数不在 std 命名空间中,适用于 android NDK w/gcc-4.8 或 clang