如果UDP数据包超过MTU,是否可以将其分段为几个较小的数据包?似乎MTU碎片是关于IP层的,所以我认为它可以。
如果是,建议的最大值是多少。通过UDP发送的数据包大小以避免碎片,为什么?
答案 0 :(得分:3)
如果IP数据报大于MTU,则可以对其进行分段。是否包含UDP,TCP,ICMP等并不重要。
大多数以太网网络支持1500字节MTU。 IPv4报头为20字节,UDP报头为8字节,UDP报文的有效载荷不应大于1500 - 20 - 8 = 1472字节,以避免碎片。
假设数据包中不存在IP选项。如果是这样,有效载荷将需要小于它的负载。
这仅适用于IPv4。 IPv6不支持分段。
答案 1 :(得分:0)
如果您希望以特定大小分片数据包,以下示例将很有帮助。
#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);
}