TCP Maximum Segment Size(MSS)
下图中看到的是TCP连接发送和接收的过程示意图,最大报文段长度(MSS)的作用是限制在TCP层产生的报文段的最大长度
(当然要在滑动窗口允许的前提下)。
比如如果MSS为1000个字节,每个TCP报文的最大长度为1020字节(附加20字节TCP头部),之后传递到IP层加装20字节IP头部封装成为IP报文利用链路层发送。
知其然更要知其所有然,知道了MSS的作用,那么为什么我们需要MSS的功能呢?难道不能生成一个任意大的TCP报文传递给IP层么? 要理解这个问题,就一定要牵扯到MTU的概念。MTU(最大传输单元)是链路层的概念,指的是一条路径上的允许传输的最大单元的大小。比如以太网的MTU为1500,这意味着以太网中通信的双方能够交互的最大单个报文的大小不能超过1500字节,在IP层由于有20字节的IP头部,则IP载荷不能超过1480。也就是说超过这个大小的IP报文必须经过分段才能够发送。
那么MTU和MSS又有什么必然联系呢?虽然MTU限制了IP层的报文大小,但分层网络模型本来不就是为了对上层提供透明的服务么?即使一个很大的TCP报文传递给IP层,IP层也应该可以经过分段等手段成功传输报文才对。理论上来说是没错的,UDP中就不存在
MSS,UDP生成任意大的UDP报文,然后包装成IP报文根据底层网络的MTU分段进行发送。MSS存在的本质原因就是TCP和UDP的根本不同:TCP提供稳定的连接。假设生成了很大的TCP报文,经过IP分段进行发送,而其中一个IP分段丢失了,则TCP协议需要重发整个TCP报文,造成了严重的网络性能浪费,而相对的由于UDP无保证的性质,即使丢失了IP分段也不会进行重发。
所以说,MSS存在的核心作用,就是避免由于IP层对TCP报文进行分段而导致的性能下降。
从上面的分析我们可以看到,挑选MSS的关键在于在避免IP层对TCP报文进行分段的基础上尽可能的提高传输效率。所谓传输效率,即数据载荷占整个报文大小的比重,比如如果MSS设置为40,则80字节长的IP报文中最多只有40字节的数据,传输效率仅为50%,因此,通常将MSS设置为MTU-40(20字节IP头部+20字节TCP头部)。
这一过程是在TCP连接建立时由连接双方商定的,需要注意的是:双方所得到的MSS可能并不相同。另外,建立MSS所基于的MTU的值基于路径MTU发现机制获取,这又是另外一个晦涩的主题了。
在进行UDP编程的时候,我们最容易想到的问题就是,一次发送多少bytes好?
当然,这个没有唯一答案,相对于不同的系统,不同的要求,其得到的答案是不一样的,我这里仅对像ICQ一类的发送聊天消息的情况作分析,对于其他情况,你或许也能得到一点帮助:
首先,我们知道,TCP/IP通常被认为是一个四层协议系统,包括链路层,网络层,运输层,应用层。UDP属于运输层,下面我们由下至上一步一步来看:以太网(Ethernet)数据帧的长度必须在46-1500字节之间,这是由以太网的物理特性决定的。这个1500字节被称为链路层的MTU(最大传输单元)。但这并不是指链路层的长度被限制在1500字节,其实这这个MTU指的是链路层的数据区,并不包括链路层的首部和尾部的18个字节。所以,事实上,这个1500字节就是网络层IP数据报的长度限制。
因为IP数据报的首部为20字节,所以IP数据报的数据区长度最大为1480字节。 而这个1480字节就是用来放TCP传来的TCP报文段或UDP传来的UDP数据报的。 又因为UDP数据报的首部8字节,所以UDP数据报的数据区最大长度为1472字节。
这个1472字节就是我们可以使用的字节数。
当我们发送的UDP数据大于1472的时候会怎样呢?
这也就是说IP数据报大于1500字节,大于MTU。这个时候发送方IP层就需要分片(fragmentation),把数据报分成若干片,使每一片都小于MTU。而接收方IP层则需要进行数据报的重组。这样就会多做许多事情,而更严重的是,由于UDP的特性,当某一片数据传送中丢失时,接收方便但无法重组数据报.将导致丢弃整个UDP数据报。因此,在普通的局域网环境下,我建议将UDP的数据控制在1472字节以下为好。
进行Internet编程时则不同,因为Internet上的路由器可能会将MTU设为不同的值。如果我们假定MTU为1500来发送数据的,而途经的某个网络的MTU值小于1500字节,那么系统将会使用一系列的机制来调整MTU值,使数据报能够顺利到达目的地,这样就会做许多不必要的操作。鉴于Internet上的标准MTU值为576字节,所以我建议在进行Internet的UDP编程时,最好将UDP的数据长度控件在548字节(576-8-20)以内。建议您在设计程序的时候选择小于 PMTU 的 IP 分组大小,因为大于这个数值的分组可能被分片(否则无法发送),而分组交换的网络是不可靠的,存在着丢包。接收方只有在收到全部的分片后才能 reassemble 并送至上层协议处理代码,否则在应用程序看来这些分组已经被丢弃。
假定同一时刻网络丢包的概率是均等的,那么较大的 IP datagram 必然有更大的概率被丢弃,因为只要丢失了一个 fragment,就导致整个 IP datagram 接收不到。不超过 PMTU 的分组是没有这个问题的。
一般地,在局域网中,UDP 分组的大小限制在 1472 字节内是安全的;在距离较近(100km 以内)的广域网中,1400 字节较为安全;距离较远的时候(如中美之间),我建议控制在 1300 字节,甚至 1200 字节。需要根据实际网络情况做出进一步的调整。
Enjoy it !