加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

[转]linux下UDP单次发送大小限制是多少?

(2014-07-28 11:09:13)
标签:

udp协议

包大

缓冲区

字节

消息格式

来源http://www.it2down.com/it-network/246990.htm

linux下UDP单次发送大小限制是多少?
我的理解是,只要不超过发送缓冲区设的大小,就可以一次sendto出去,然后协议负责拆包组包.

但今天实际代码中,单次只能发送最大65507字节,即便是我设置了发送缓冲区的大小为6M,并且函数返回0,也只能最多发送65507字节.

简略代码如下:
sockThis = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockThis == INVALID_SOCKET)
{
  printf("socket sockThis error! ");
  break;
}

valueTemp = MAX_IMG_FRAMESIZE + 100;//MAX_IMG_FRAMESIZE = 1600*1200*3
ret = setsockopt(sockThis, SOL_SOCKET, SO_SNDBUF, &valueTemp, sizeof(valueTemp));
if (ret != 0)
{
  printf("setsockopt SO_SNDBUF error! %d", errno);
}
valueTemp = 1;
ret = setsockopt(sockThis, SOL_SOCKET, SO_REUSEADDR, &valueTemp, sizeof(valueTemp));
if (ret != 0)
{
  printf("setsockopt SO_REUSEADDR error! %d", errno);
}

memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = PF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(8881);
if (bind(sockThis, (struct sockaddr*)&addr, sizeof(addr)) == -1)
{
  printf("bind sockThis error! ");
  break;
}

addr.sin_addr.s_addr = m_TargetAddr;
sendto(sockThis, pData, frameSize, 0, (struct sockaddr*)&addr, sizeof(addr));

请大家指点一下!

------解决的方法--------------------------------------------------------
就是64K嘛。
由UDP协议决定。UDP协议的消息格式里头,长度字段只有两个字节,16位,可以表示的就是2^16 = 64K。所以一个UDP大小不能超过65535,不然包大小表示不了。。。

不过你用UDP实际中是不应该发那么大的包的,包大了 拆包之后容易丢包。包大小要适中。
一般以下层的最大包大小为限。避免下层的拆包。


- 千里孤行
第二篇
 UDP和TCP协议利用端口号实现多项应用同时发送和接收数据。数据通过源端口发送出去,通过目标端口接收。有的网络应用只能使用预留或注册的静态端口;而另外一些网络应用则可以使用未被注册的动态端口。因为UDP和TCP报头使用两个字节存放端口号,所以端口号的有效范围是从0到65535。动态端口的范围是从1024到65535。  

    MTU最大传输单元,这个最大传输单元实际上和链路层协议有着密切的关系,EthernetII帧的结构DMAC+SMAC+Type+Data+CRC由于以太网传输电气方面的限制,每个以太网帧都有最小的大小64bytes最大不能超过1518bytes,对于小于或者大于这个限制的以太网帧我们都可以视之为错误的数据帧,一般的以太网转发设备会丢弃这些数据帧。

    由于以太网EthernetII最大的数据帧是1518Bytes这样,刨去以太网帧的帧头(DMAC目的MAC地址48bit=6Bytes+SMAC源MAC地址48bit=6Bytes+Type域2bytes)14Bytes和帧尾CRC校验部分4Bytes那么剩下承载上层协议的地方也就是Data域最大就只能有1500Bytes这个值我们就把它称之为MTU。

UDP 包的大小就应该是 1500 – IP头(20) – UDP头(8) = 1472(BYTES)
TCP 包的大小就应该是 1500 – IP头(20) – TCP头(20) = 1460 (BYTES)

注*PPPoE所谓PPPoE就是在以太网上面跑“PPP”。随着宽带接入(这种宽带接入一般为Cable Modem或者xDSL或者以太网的接入),因为以太网缺乏认证计费机制而传统运营商是通过PPP协议来对拨号等接入服务进行认证计费的,所以引入PPPoE。PPPoE导致MTU变小了以太网的MTU是1500,再减去PPP的包头包尾的开销(8Bytes),就变成1492。不过目前大多数的路由设备的MTU都为1500。

   如果我们定义的TCP和UDP包没有超过范围,那么我们的包在IP层就不用分包了,这样传输过程中就避免了在IP层组包发生的错误;如果超过范围,既IP数据报大于1500字节,发送方IP层就需要将数据包分成若干片,而接收方IP层就需要进行数据报的重组。更严重的是,如果使用UDP协议,当IP层组包发生错误,那么包就会被丢弃。接收方无法重组数据报,将导致丢弃整个IP数据报。UDP不保证可靠传输;但是TCP发生组包错误时,该包会被重传,保证可靠传输。

    UDP数据报的长度是指包括报头和数据部分在内的总字节数,其中报头长度固定,数据部分可变。数据报的最大长度根据操作环境的不同而各异。从理论上说,包含报头在内的数据报的最大长度为65535字节(64K)。

    我们在用Socket编程时, UDP协议要求包小于64K,TCP没有限定。

    不过鉴于Internet上的标准MTU值为576字节,所以建议在进行Internet的UDP编程时,最好将UDP的数据长度控制在548字节 (576-8-20)以内。

就具体函数而言:

    用UDP协议发送时,用sendto函数最大能发送数据的长度为:65535- IP头(20) – UDP头(8)=65507字节。用sendto函数发送数据时,如果发送数据长度大于该值,则函数会返回错误。 

    用TCP协议发送时,由于TCP是数据流协议,因此不存在包大小的限制(暂不考虑缓冲区的大小),这是指在用send函数时,数据长度参数不受限制。而实际上,所指定的这段数据并不一定会一次性发送出去,如果这段数据比较长,会被分段发送,如果比较短,可能会等待和下一次数据一起发送。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有