如果目标不存在,sendto() 不会产生错误

sendto() does not generate error if destination does not exist

我正在使用 C 中的 sendto() 函数。我已经设置了目标地址和目标端口。在发送 UDP 帧时,我可以在 Wireshark 中看到帧,并且 Wireshark 显示的数据包数量与我在程序中定义的完全相同。

问题是即使无法到达目标地址,帧仍在发送,我可以在 Wireshark 中看到它。

如果目标 IP 不存在,sendto() 函数不应该生成错误吗?

 if (sendto(sockfd, &buffer[i], UDP_FRAME, 0,
                    (const struct sockaddr*)&server, sizeof(server)) < 0)
        {
            fprintf(stderr, "Error in sendto()\n");
            //return EXIT_FAILURE;
        }

目的地。 IP:234.168.0.1 目标端口:80 或 9(丢弃协议)

    #define PORT (80)
    #define FRAMES (20000)
    #define UDP_FRAME (1442)
    #define SERVERADDRESS "234.168.0.1"
    #define BUFFER_SIZE (FRAMES * UDP_FRAME)
    char buffer[BUFFER_SIZE];

    int main(int argc, char **argv)
{
    struct timespec start, end, loop_start, loop_end;
    int sockfd, count_frame = 0, frames_total, i = UDP_FRAME, n=1;
    struct sockaddr_in server;

    printf("Build Data...\n");
    build(buffer, sizeof(buffer));

    printf("Configure socket...\n");
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        fprintf(stderr, "Error opening socket");
        return EXIT_FAILURE;
    }

    /*----------------------------------------------------*/
/*---       Initialize address protocol            ---*/
/*----------------------------------------------------*/

    bzero((char*)&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(SERVERADDRESS);
    server.sin_port = htons(PORT);

    /*---------------------------------------------------*/
/*---       S E N D I N G   D A T A        --*/
/*---------------------------------------------------*/

    printf("\nSend UDP data...\n\n");
    clock_gettime(CLOCK_MONOTONIC_RAW, &start);
    clock_gettime(CLOCK_MONOTONIC_RAW, &loop_start);
    frames_total = 0;

    for (int i = 0; i < BUFFER_SIZE; i += UDP_FRAME) {
    //while(1) {    

        if (sendto(sockfd, &buffer[i], UDP_FRAME, 0,
                    (const struct sockaddr*)&server, sizeof(server)) < 0)
        {
            fprintf(stderr, "Error in sendto()\n");
            //return EXIT_FAILURE;
        }
    count_frame += 1;

    clock_gettime(CLOCK_MONOTONIC_RAW, &loop_end);
    if ((loop_end.tv_nsec - loop_start.tv_nsec) > 5000000) {
        printf("\nCount [%d] ... ", n);
        printf("Fames sent: %d\n", count_frame);
        frames_total += count_frame;
        n+=1;
        count_frame = 0;
        clock_gettime(CLOCK_MONOTONIC_RAW, &loop_start);
    }

    }
    printf("Total successful counted frames: %d \n", frames_total);

    return EXIT_SUCCESS;
}

sendto() 如果主机不知道到主机的 路由 会给你一个错误(几乎从来没有这种情况,因为你的主机会有默认网关)。否则,如果您的数据包未到达目标应用程序,您可能(或可能不会)收到 ICMP 目的地无法到达的消息,但这是不可靠的,并且不会通过调用 sendto().

进行通信

你可以做的是用

查询套接字
struct sock_extended_err err;
socklen_t errlen = sizeof(err);
getsockopt(fd, SOL_IP, IP_RECVERR, &err, &errlen);

对于收到的错误,这将为您提供有关套接字上收到的错误的详细信息(即 ICMP 端口无法访问,ICMP 主机无法访问等。pp)。这会有所帮助,但正如我所说,它是不可靠的,因为 ICMP 消息通常受到严格的速率限制,如果您的数据包被数据包过滤器(防火墙)阻止,则在途中被过滤或根本不发送。

UDP 是一种不可靠的协议。一旦数据包离开接口,对 sendto 的调用就成功了。之后,是否到达目的地取决于网络。

即使网络支持表明主机或端口不可访问的 ICMP 消息,在您的特定情况下也无关紧要,因为您要发送到多播地址。如果您至少有一个支持多播的接口,系统将选择一个接口来发送数据包。它可以被多个(或没有)主机接收。所以说目的地不可达是没有意义的。