当前位置: 首页 > 知识库问答 >
问题:

UDP数据包是否可以分为多个较小的数据包[重复]

百里锋
2023-03-14

如果UDP数据包超过MTU,它能被分割成几个更小的数据包吗?看起来MTU碎片是关于IP层的,所以我认为它可以。

如果是,为避免碎片,建议通过UDP发送的最大数据包大小是多少?为什么?

共有2个答案

方宜
2023-03-14

如果您想要特定大小的数据包碎片,下面的示例将非常有用。

#define UDP_FRAG_1024 1024

static int udp_raw_socket = -1;
static int udp_ip_iden = 1234;

int udp_frag1024_sendto(int s, caddr_t buf, int buf_len, int flags, struct sockaddr *to, int to_len)
{
    /* You must be in the sudoers files. */

    struct sockaddr_in sin;
    struct sockaddr_in *ptr_din = (struct sockaddr_in *)to;
    int sin_len = sizeof(sin);
    unsigned char packet[1500];
    short packet_len;
    short ip_iden;
    int sent1;
    int sent2;

    if (udp_raw_socket == -1) {
        int opt_val = 1;
        int *ptr_opt_val = &opt_val;

        udp_raw_socket = socket(AF_INET,SOCK_RAW,IPPROTO_RAW);

        (void)setsockopt(udp_raw_socket,IPPROTO_IP,IP_HDRINCL,(char *)ptr_opt_val,sizeof(opt_val));
    }

    if (buf_len > 2*UDP_FRAG_1024) {
        printf("buf_len %d not supported.\n",buf_len);
        return -1;
    }
    else if (buf_len <= UDP_FRAG_1024) {
        return sendto( s, buf, buf_len, flags, to, to_len );
    }
    else {
        ip_iden = udp_ip_iden++;

        (void)getsockname(s,(struct sockaddr *)&sin,&sin_len);

        /* 1st framentation - IP header */

        packet_len = 20 + 8 + UDP_FRAG_1024;

        packet[0] = 0x45; /* ver and header length */
        packet[1] = 0x00; /* tos */
        *(short *)&packet[2] = htons(packet_len);
        *(short *)&packet[4] = htons(ip_iden);
        packet[6] = 0x20; packet[7] = 0x00; /* flag */
        packet[8] = 0x40; /* ttl */
        packet[9] = 0x11; /* udp */
        packet[10] = 0x00; packet[11] = 0x00;/* checksum */
        memcpy( &packet[12], &sin.sin_addr.s_addr, 4 );
        memcpy( &packet[16], &ptr_din->sin_addr.s_addr, 4 );

        /* 1st framentation - UDP header */

        memcpy( &packet[20], &sin.sin_port, 2 );
        memcpy( &packet[22], &ptr_din->sin_port, 2 );
        *(short *)&packet[24] = htons(8+buf_len);
        packet[26] = 0x00; packet[27] = 0x00; /* checksum */

        /* 1st framentation - payload */

        memcpy( &packet[28], buf, UDP_FRAG_1024 );

        sent1 = sendto(udp_raw_socket,packet,packet_len,0,to,sizeof(struct sockaddr_in));

        /* 2nd framentation */

        packet_len = 20 + buf_len - UDP_FRAG_1024;

        *(short *)&packet[2] = htons(packet_len);
        packet[6] = 0x00; packet[7] = (8+UDP_FRAG_1024)/8; /* flag:0x81*8=129*8=1032=8+1024 */
        packet[10] = 0x00; packet[11] = 0x00; /* checksum */

        memcpy( &packet[20], buf+UDP_FRAG_1024, buf_len-UDP_FRAG_1024 );

        sent2 = sendto(udp_raw_socket,packet,packet_len,0,to,sizeof(struct sockaddr_in));
    }

    return ((sent1 - 20 - 8) + (sent2 - 20));
}

void udp_frag1024_sendto_test()
{
    int s;
    struct sockaddr_in my_addr;
    struct sockaddr_in to_addr;
    char buffer[4096];
    int sent;

    s = socket(AF_INET, SOCK_DGRAM, 0);

    my_addr.sin_family      = AF_INET;
    my_addr.sin_addr.s_addr = inet_addr("192.168.0.229");
    my_addr.sin_port        = htons(12345);

    bind(s,(struct sockaddr *)&my_addr,sizeof(my_addr));

    to_addr.sin_family      = AF_INET;
    to_addr.sin_addr.s_addr = inet_addr("192.168.0.19");
    to_addr.sin_port        = htons(12345);

    memset(buffer,'A',sizeof(buffer));

    sent = udp_frag1024_sendto(s,buffer,2047,0,(struct sockaddr *)&to_addr,sizeof(struct sockaddr_in));

    close(s);

    printf("sent %d bytes\n",sent);
}
柯良骏
2023-03-14

如果任何IP数据报大于MTU,则可以将其分段。它是否包含UDP、TCP、ICMP等并不重要。

大多数以太网支持1500字节的MTU。IPv4报头为20字节,UDP报头为8字节,UDP数据包的有效负载不应大于1500-20-8=1472字节,以避免碎片。

这是假设数据包中不存在IP选项。如果是这样的话,有效载荷将需要小于该值才能解释它。

这仅适用于IPv4。IPv6不支持分段。

您还可以看到关于UDP的MTU的问题。

 类似资料:
  • 我一直在写一个程序,它使用UDP上的停止和等待协议通过局域网和广域网发送数据包。我最近一直在测试我的程序,并注意到较大的数据包(接近64k字节)的丢包率更高。直觉上这是有道理的,但实际原因是什么?

  • 我创建了某种类型的客户机/服务器应用程序,它有自己的数据ACK系统。由于某些限制,它最初是用TCP编写的,但它的基础是考虑到UDP编写的。 我发送到服务器的数据包有自己的封装(数据包id和数据包大小报头。我知道UDP还有一个校验和,所以我没有为此添加报头),但是TCP是如何工作的,我知道服务器可能接收不到整个数据包,所以我收集并缓冲了接收到的数据,直到收到一个完整的有效数据包。 我想知道的是:如果

  • 根据Stevens(图示为TCP/IP),traceroute程序用增量TTL(1、2、3等)向目的主机发送UDP数据包,以从ICMP TTL过期消息中获取中间跳信息。 “到达目的地”条件是ICMP端口无法到达的消息,因为traceroute寻址的随机端口数量很高(也就是说,不太可能有人在那里监听) 所以我的问题是:是否有技术原因(缺点、RFCs等)使用UDP数据包而不使用例如ICMP回送请求消息

  • 通过UDP发送大量的小数据包会占用更多的资源(cpu、zlib压缩等)。我在这里读到,通过UDP发送一个大的~65kBYTEs数据包可能会失败,所以我认为发送许多较小的数据包会更频繁地成功,但是随之而来的是使用更多处理能力的计算开销(或者至少这是我假设的)。问题基本上是这样的:发送最大成功数据包并将计算保持在最低限度的最佳方案是什么?有没有一个特定的尺寸在大部分时间都有效?我使用Erlang作为服

  • 好的,我正在为我的网络课程编程,我必须使用UDP在Java中实现一个项目。我们正在实现一个HTTP服务器和客户端以及一个“gremlin”函数,该函数以指定的概率破坏数据包。HTTP服务器必须在应用层将一个大文件分成多个段,然后通过UDP发送到客户端。客户端必须在应用层重新组装接收到的段。然而,我想知道的是,如果UDP根据定义是不可靠的,为什么我必须在这里模拟不可靠? 我的第一个想法是,也许这仅仅

  • 我正在使用在我的客户端应用程序中执行以及 最大数据包大小限制也存在于中,即?但是我可以使用中的发送大于最大数据包大小的数据块 这是怎么运作的?这是因为是基于流的,负责在较低层创建数据包吗?有什么方法可以增加UDP中的最大数据包大小吗? 当我在客户端读取时,我从服务器端发送的UDP数据包的一些字节是否可能丢失?如果是,那么有没有办法只检测UDP客户端的损失?