如何使用C sockets进行ping测试

8
  • 编译器:Code::Blocks(GNU GCC)
  • 平台:Windows(x86)
  • 包含内容:winsock.h winsock2.h(同时链接了ws2_32)

我正在尝试编写一个程序,该程序将读取一个包含IP地址列表的文本文件,并逐个ping每个IP地址。如果主机响应ping,则将主机的IP地址复制到由用户指定的第二个文件中。不幸的是,这是我第一次使用C的套接字库,我找不到一个好的教程来教我如何使用C进行ping操作。根据我所理解的几篇教程,我需要在IP数据报中包含ICMP头,它是一个包含ICMP类型、代码和校验和的结构体。但我不知道如何去做,我应该自己声明这个结构体还是在头文件中声明?我假设它在头文件中,但教程们对它的确切声明位置有所矛盾。我尝试包含icmp.h和netinet/icmp.h,但我的编译器抱怨说它们不存在,所以我创建了自己的结构体。

    struct echo_request
    {
        char type; // Type
        char code; // Code
        short checksum; // Checksum
        short id; // Identification
        short seq; // Sequence
        int time; // Time
        char data[16]; // Data
    };

我原本以为我可以搞定,但是我的编译器却提示in_cksum()(校验生成器)未定义,导致我无法编译程序。

总的来说,我的问题是:我应该包含哪些头文件?如何创建ping数据包?我是否使用了正确的校验生成器函数?ping应该定向到80端口吗?我应该使用RAW还是DGRAM套接字?

以下是我目前拥有的代码,请注意我故意省略了错误检查。

    int socket_descriptor = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

    struct sockaddr_in address; //Initialize address struct
    memset(&address, 0, sizeof(address)); //Clear address struct

    //Declare address
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(ipaddress);
    address.sin_port = htons(80);

    //Bind socket to address
    bind(socket_descriptor, (struct sockaddr *)&address, sizeof(address));

    //Create packet
    struct echo_request packet; //See above for declaration of struct
    memset(packet.data, 1, 16);
    packet.type = 8; //ECHO_REQUEST
    packet.code = 0;
    packet.time = gettime();
    packet.checksum = 0;
    packet.checksum = in_cksum(packet, sizeof(packet));

  1. 结构体必须是紧凑的,确保编译器不会对字段进行对齐。
  2. Windows 是否良好支持原始套接字(我不知道)?
- Dmytro Sirenko
2个回答

5
如果您不必从头开始实现ping,并且只需要Windows解决方案,我会支持Anton的建议,使用IcmpSendEcho。如果您必须实现ping,请查看POCO ICMP软件包的实现方式。它是可移植的代码,并且在Windows上运行良好。
关于具体问题,以下是答案:
“我应该包含哪些头文件?”
#include <winsock2.h>

如何创建ping数据包?

参见ICMPv4PacketImpl::initPacket(),其中有IPv4数据包的示例。

我是否使用了正确的校验和生成函数?

对于Windows不是。参见ICMPPacketImpl::checksum(),其中有校验和函数的示例。

ping应该定向到80端口吗?

不应该。在 ICMP 中不存在端口这个概念。参见Does ICMP use a specific port?

我应该使用 RAW 还是 DGRAM 套接字?

应该使用 RAW。


@Alex,ICMP需要以管理员和/或root身份运行才能工作吗? - Top-Master
1
通常是这样的,@Top-Master。请参见https://dev59.com/uHM_5IYBdhLWcg3w3nXz#1189445。 - Alex

4

看起来你想要一个真正的解决方案,而不仅仅是为了重新实现PING。

我建议使用IP助手(在早期的WinXP系统上为ICMP.dll),具体来说,IcmpSendEcho(或其增强版本IcmpSendEcho2IcmpSendEcho2Ex,用于异步操作)。

MSDN上有一个完整的“ping”主机的示例。这可能是一个很好的起点。

更新:对于GCC(mingw),请链接-liphlpapi。


感谢您的回复。我知道IcmpSendEcho,但我想实现一个相对便携的解决方案。 - John Vulconshinz
但是,如果您的应用程序没有“管理员权限”,则根据以下内容“IcmpSendEcho”是唯一的选择:https://dev59.com/HGsz5IYBdhLWcg3wwKmh#7691109 - Top-Master

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接