【博客270】UDP报文数据大于MTU也不一定会分片
内容: 记录当UDP报文数据内容大于MTU大小的时候,其实不一定分片UDP什么时候分片?UDP报文中有长度的字段,是16位的,那么UDP报文的最大长度是65536字节,但是一般MTU的大小不会达到65536字节这么大,而是一般为1500字节,那么这时候就会引起分片UDP一定会分片吗?答案:不一定,当UDP报文是上交本地协议栈的时候,并不会引起分片的!原因:本地环回报文实际并不需要层层封装到链路层再
·
内容: 记录当UDP报文数据内容大于MTU大小的时候,其实不一定分片
UDP什么时候分片?
UDP报文中有长度的字段,是16位的,那么UDP报文的最大长度是65536字节,但是一般MTU的大小不会达到
65536字节这么大,而是一般为1500字节,那么这时候就会引起分片
UDP一定会分片吗?
答案:不一定,当UDP报文是上交本地协议栈的时候,并不会引起分片的!
原因:本地环回报文实际并不需要层层封装到链路层再物理层这个过程,也就不受MTU的影响。而是在IP层就
直接复制到本地协议栈目的连接的接受缓冲区了。
不分片的情况:
//服务端代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#define MAXBUF 70000
int main(int argc, char const *argv[])
{
int s = 0;
int n = 0;
int reuse = 1;
int cli_len = sizeof(struct sockaddr);
int port = 5555;
char buf[MAXBUF] = {0};
struct sockaddr_in addr, cli;
bzero(&addr, sizeof(addr));
addr.sin_family = PF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s<0)
{
perror("socket");
return -1;
}
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
return -1;
}
while(1){
memset(buf, 0, MAXBUF);
n = recvfrom(s, buf, MAXBUF, 0, (struct sockaddr *)&cli, &cli_len);
if(n<0){
perror("recvfrom");
return -1;
}else{
printf("receive msg from %s(port=%d) len %d: %s\n",inet_ntoa(cli.sin_addr), port, n, buf);
}
}
return 0;
}
//客户端代码:
/*client.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#define MAXBUF 60000
int main(int argc, char const *argv[])
{
int s = 0;
int n = 0;
int reuse = 1;
int port = 5555;
struct sockaddr_in srv;
char buf[MAXBUF] = {0};
for (int i = 0; i < 60000; i++)
{
buf[i] = 'k';
}
buf[59999] = '\0';
/*解析参数*/
if (argc != 2)
{
printf("Usage:%s ServerIP\n", argv[0]);
return -1;
}
bzero(&srv, sizeof(srv));
srv.sin_family = PF_INET;
srv.sin_addr.s_addr = inet_addr(argv[1]);
srv.sin_port = htons(port);
/*创建 UDP 套节字*/
s = socket(AF_INET, SOCK_DGRAM, 0);
if(s<0){
perror("socket");
return -1;
}
/*通过套节字 s 向服务器发送数据*/
if ((n = sendto(s, buf, strlen(buf), 0, (struct sockaddr *) &srv, sizeof(struct sockaddr))) < 0)
{
perror("sendto");
return -1;
}else{
printf("send to %s(port=%d) len %d:%s\n", argv[1], port, n, buf);
}
}
代码运行:
(注意:这里的ip地址为本地网卡的地址)
抓取报文:
报文分析:
1、报文的数据大小为59999字节,因为发送的数组是60000字节,但是最后一个字节我设置了'\0'
2、59999字节是大于MTU的,但是报文并没有分片,可以看到IP层的不分片标志位置1了,表示不允许分片,
因为这个是发给本地网卡的,那么可以直接在IP层就可以处理了,不需要往下再走其它层了
3、可以看到链路层及以下的层在报文中已经没有再封装了,采用了伪协议

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)