最大UDP数据报长度
理论上,IP数据报的最大长度是65535字节,这是由IP首部(图IP协议格式)16比特总长度字段所限制。去除20字节的IP首部(图IP协议格式)和8字节的UDP(图UDP协议格式)首部,UDP数据报中用户的最长长度为65507.但是,大多数实现所提供的长度比这个最大值小。
我们将遇到两个限制因素。
第一,应用程序可能会受到其程序接口的限制。socket API提供了一个可供应用程序调用的函数,以设置接收和发送缓存的长度。对于UDP socket,这个长度与应用程序可以读写的最大UDP数据报的长度直接相关。现在的大部分系统都默认提供了可读写大于8192自己的UDP数据报。
第二个限制来自于TCP/IP的内核实现。可能存在一些实现特性(或差错),使IP数据报长度小于65535字节。
测试udp最大数据报长度代码
server.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>#define SERVER_PORT 8888
#define MAX_MSG_SIZE 1024void udps_respon(int sockfd)
{
struct sockaddr_in addr;
int addrlen,n;
char msg[MAX_MSG_SIZE];
while(1){
/*从网络上读,并写到网络上*/
bzero(msg,sizeof(msg)); //初始化,置0
addrlen = sizeof(struct sockaddr);
n = recvfrom(sockfd,msg,MAX_MSG_SIZE,0,(struct sockaddr*)&addr,&addrlen); //从客户端接收数据
msg[n] = '\0';
/*显示服务端已经收到了消息*/
fprintf(stdout,"Server have received %s",msg); //显示消息
}
}int main(int argc,char *argv[])
{
int sockfd;
struct sockaddr_in addr;
/*建立sockfd描述符*/
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0){
fprintf(stderr,"Socket Error:%s\n",strerror(errno));
exit(1);
}/*服务器端填充sockaddr结构*/
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port = htons(SERVER_PORT);
/*捆绑sockfd描述符*/
if(bind(sockfd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in)) < 0){
fprintf(stderr,"Bind Error:%s\n",strerror(errno));
exit(1);
}
printf("udp server start ......\n");
udps_respon(sockfd); //进行读写操作
close(sockfd);
}
client.c
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>#define SERVER_PORT 8888
#define MAX_BUF_SIZE 65508void udpc_requ(int sockfd,const struct sockaddr_in *addr,int len)
{
char buffer[MAX_BUF_SIZE+1];
int n;
int i = 0;
//while(1){
/*从键盘读入,写到服务器*/
printf("Please input char:\n");
memset(buffer,0,sizeof(buffer));
//fgets(buffer,MAX_BUF_SIZE,stdin);
for(i = 0; i<MAX_BUF_SIZE; i ++)
{
buffer[i]='a';
}
n = sendto(sockfd,buffer,strlen(buffer),0,(struct sockaddr*)addr,len);
//bzero(buffer,MAX_BUF_SIZE);
printf("send bytes:%d\n",n);
//}
}int main(int argc,char *argv[])
{
int sockfd;
struct sockaddr_in addr;
if(argc != 2){
fprintf(stderr,"Usage:%s server_ip\n",argv[0]);
exit(1);
}
/*建立sockfd描述符*/
sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0){
fprintf(stderr,"Socket Error:%s\n",strerror(errno));
exit(1);
}/*填充服务端的资料*/
bzero(&addr,sizeof(struct sockaddr_in)); //初始化,置0
addr.sin_family = AF_INET;
addr.sin_port = htons(SERVER_PORT);
if(inet_aton(argv[1],&addr.sin_addr) < 0){ /*inet_aton函数用于把字符串型的IP地址转化成网络类型IP地址*/
fprintf(stderr,"Ip Error:%s\n",strerror(errno));
exit(1);
}
udpc_requ(sockfd,&addr,sizeof(struct sockaddr_in)); //进行读写操作
close(sockfd);
}
MTU值
参考TCP/IP详解卷一,做的全球互联网实验
作为一个实验,我们多次运行修改以后的traceroute程序,目的端为世界各地的主机,可以到达15个国家(包括南极洲),使用了多个跨大西洋和跨太平洋的链路。但是,在这样做之前,作者所在子网与路由器netb之间的拨号SLIP链路MTU增加到1500与以太网相同。
在18次运行当中,只有其中2次发现的路径MTU小于1500。其中一个跨大西洋的链路MTU值为572,而路由器返回的的是新格式的ICMP差错报文。另外一条链路,在日本的两个路由器之间,不能处理1500字节的数据帧,并且路由器没有返回新格式的ICMP差错报文。把MTU值设成1006则可以正常工作。
从这个实验可以读出结论,现在许多但不是所有的广域网都可以处理大于512自己的分组,利用路径MTU发现机制,应用程序就可以充分利用更大的MTU来发送报文。
对于MTU值,要求主机必须能够接收至少576字节的IP数据报。在许多UDP应用程序设计中,其应用程序数据被限制成512字节或更小,因此比这个限制值小。当然,我们可以通过分析很多路由协议(DNS TFTP BOOTP SNMP)总是发送每份小于512字节的数据。