(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
MacOS 发送buffer长度限制: 1024*9 = 9216 Bytes
CentroOS 发送buffer长度限制: 1024*64 - 28=65507 Bytes (推测应该介于55467-65507之间,取决于IP头部长度,如果IP头部长度>最小值20,带了附加头信息的话,支持长度应该会减少)
另外已知:Ethernet数据链路层的MTU(Maximum Transmisiion Unit)通常是1500Bytes,对于大于MTU的IP包需要拆分发送,发送方主机或路由器会对它进行拆分。所以测试最高支持码流时,大于MTU,IP包会进行拆分在链路上发送,然后会在接受端的主机上重新组转,使用Wireshark抓包时也可以看出来这一点,在底部会有一个reassembled页签。
码流说明:从一台外部的Centos系统的主机,发UDP消息到本机的UDP监听服务器
数据链路层(头部:8字节):Ethernet II, Src: Tp-LinkT_1e:16:0c (??:??:??:??:??:??), Dst: Apple_cd:dc:e9 (??:??:??:??:??:??)
目标Mac地址(本机Mac):Destination: Apple_cd:dc:e9 (??:??:??:??:??:??)
源Mac地址(本机所连路由器的Mac):Source: Tp-LinkT_1e:16:0c (??:??:??:??:??:??)
类型:Type: IPv4 (0x0800)
网络层-IP(头部:20个字节):Internet Protocol Version 4, Src: ???.???.???.???, Dst: ???.???.???.???
版本:0100 .... = Version: 4
头长度:.... 0101 = Header Length: 20 bytes (5) 根据头部长度的位数4,IP头部最长可以达到15*4=60个字节
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
头和数据总长度:Total Length: 415 根据位数限制8,头部与数据最大可以达到65535字节,当前值为最后一个分段的长度
分段标示:Identification: 0x6ce7 (27879)
Flags: 0x1fcc
保留0... .... .... .... = Reserved bit: Not set
不分段.0.. .... .... .... = Don't fragment: Not set
还有分段..0. .... .... .... = More fragments: Not set
分段偏移地址:...1 1111 1100 1100 = Fragment offset: 8140 当前分段偏移量为8140*8=65120 字节,代表已传送过的字节数
生命期:Time to live: 51
协议:Protocol: UDP (17)
校验和:Header checksum: 0x9e5d [validation disabled]
源IP:Source: ???.???.???.???
目标IP:Destination: ???.???.???.???
传输层UDP(头部:8字节):User Datagram Protocol, Src Port: 34749, Dst Port: 28881
源端口:Source Port: 34749
目标端口:Destination Port: 28881
长度:Length: 65515
校验和:Checksum: 0xc492 [unverified]
Data (数据部分:65507字节)(65507 bytes)
从协议上来看的话,网络层IP报文头中的Total Length总长度限制8位,为65535长度,当前值为415长度,代表本个分段的IP头及数据长度。
从当前IP报文中分段偏移地址-8140(该字段代表8字节倍数)存在,可以推测出报文被分段fragments传送了,因为展现的是最后一个分段的,所以可以推断出之前已经传送分段数据的长度为:8140 * 8 = 65120字节。
Total Length代表的415字节+分段偏移地址代表已传送数据的65120字节 = 65535字节。
Wireshark上对收到的分段标示Identification一致的分段进行相关的reassembled重新组装,对于IP上层的UDP协议或应用来说,多个分段消息,相当于收到了一个IP包,Total Length组装后修整为65535,已经达到了8位所能支持的极限值了。
协议上对IP包长度限制为65536,对与所发送消息的长度,需要考虑IP头和UDP头所占用长度,IP头介于(20-60字节)长度,UDP头占用8字节。那么所发数据部分的占用长度为65536-[20-40]-8=介于55467-65507之间,应为IP头部通常为最小值20字节,所以数据部分通常限制为为65507。
对于MacOS上限制为什么是9216字节,系统设置相关的参数如下,应该是系统做了一些特殊处理,因为对于UDP包来说,一个fragment分组传送有问题,整个package消息就会丢弃,所以采用较小的值,离MTU大小越近越好。
这个参数也可以通过sysctl来进行修改的,但据stackflow上别人讲cmd上的修改重启后就失效了。
command:sysctl -a|grep maxdgram
net.local.dgram.maxdgram: 2048
net.inet.udp.maxdgram: 9216
net.inet.raw.maxdgram: 8192
#include
#include
#include
#include
#include
#include "myerr.h"
#define REQUEST 1024*9
#define REPLY 256*256
int main(int argc, char **argv)
{
struct sockaddr_in serv;
char request[REQUEST], reply[REPLY];
int sockfd, n, errno;
int maxSendCount = 1;
if (argc < 3)
{
err_quit("usage: %s ipaddress port", argv[0]);
}
if ((sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
{
err_sys("socket error");
}
memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_addr.s_addr = inet_addr(argv[1]);
serv.sin_port = htons(atoi(argv[2]));
// send
{
sprintf(request, "hello world...");
if (sendto(sockfd, request, REQUEST, 0, (const sockaddr*)&serv, sizeof(serv)) != REQUEST)
{
err_sys("sendto error");
}
}
// receive
{
memset(&reply, 0, sizeof(reply));
if ((n = recvfrom(sockfd, reply, REPLY, 0, NULL, (unsigned int*) NULL)) < 0)
{
err_sys("recvfrom error");
}
fprintf(stdout, "recv: %s\n", reply);
}
return 0;
}
参考:https://stackoverflow.com/questions/3292281/udp-sendto-and-recvfrom-max-buffer-size
参考:《计算机网络(第三版)》
参考:https://stackoverflow.com/questions/22819214/udp-message-too-long
参考:TCP/IP详解
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)