4年前整理的PPT,现在重新再整理了下.
1 和TCP一样都是传输层协议
2 直接依赖IP协议
3 没有拥塞控制(太发快了会丢包)
4 没有重传机制
5 非面向连接(只管发包,协议包没有应答。部分错误回收到IP层的ICMP报文来通知有问题,如,网络不可达,端口不可达,主机不可用等)
6 没有连接超时,只有读超时
7 单向传播,没有任何协议本身的回包数据
发包过程>>>>>>>>>>>>>>>>
1.无需连接,只需指定IP和端口connect()方法其实只是记录下IP和端口,没有连接过程
2.然后这个包经过IP层,如果包超过了MTU,IP层会分片,分成的IP包,被链路层组成一帧一帧经过以太网网卡发到某个路由器的网卡上。
3.链路层有n种实现,有拥塞控制,错误重传机制(链路层ARQ协议),他理论上保证了从IP层发来的帧能够一定到达对端,但可惜不是链路层必备协议,链路层有n种实现,至少802.3以太省没有启动(或者不支持)ARQ,在复杂链路环境里,只要有一段链路不支持ARQ,就会导致端到端的ARQ失效。所里链路层不可靠,再个路由器不保证,路由器可以因为缓存区满了,CPU忙,而直接将某个IP包给悄悄的丢掉,当这个被分成多个IP包UDP包到达了对端的IP协议层,开始组包发现有一个分片找不到了,也会悄悄的丢掉.
4.最后包到达了UDP协议层了,UDP进行CRC校验数据,发现校验不通过,UDP协议层会也会将该包悄悄的丢掉了。
5.接收端内存吃紧,socket缓存满,内核把这个UDP包也丢了
6.如果你的应用程序收到了一个UDP包,那么恭喜你,这个一定是个好包。
特性2 (UDP分片)
1.UDP没有重传机制,所以他不像TCP那样有发送缓冲,直接将UDP包经由IP层,这就导致了对UDP进行write系统调用的时候,实际上应用层的数据是直接传输到IP层,由于IP层不管传输控制的事,本身也不会有缓冲区,数据就会直接写到链路层的输出队列中。
2.UDP是直接依赖IP层,一个IP包的数据区大小为65535(IP协议首部的16比特总长度决定了只能表示这么大),除去20字节的IP首部和8字节的UDP首部,理论上一个UDP的用户数据包大小为65507。实际上各种操作系统的TCP/IP内核都会对IP数据报长度有限制,但都会小于该理论值
3.UDP分片其实就是IP层对其进行分片,IP协议层发包时会向下层询问其最大的MTU,如果当前IP包超过MTU,IP层就会对其进行分包,使其包大小不超过链路层的MTU(链路层是一帧一帧的发),被分包后的IP包有可能会再在途中某个路由器的IP层再次被分包,网络环境中的硬件规格大多数都是不一样的,MTU可能不同. 发包的途中,路由器不会进行组包工作,只有当IP包达到了目的端的IP层才会进行组包,如果途中有一个IP分片被某个路由器给弃调了,或是某个传输很不稳定的链路给丢了一个帧,那么整个UDP包就被丢掉了.
4.所以UDP的发包大小很重要,一旦过大,很容易导致丢包率增高
UDP丢包
1.通过 /proc/sys/net/core/rmem_default和/proc/sys/net/core/rmem_max可以查看socket缓冲区的缺省值和最大值。rmem_default和rmem_max设置为多大合适呢?如果服务器的性能压力不大,对处理时延也没有很严格的要求,设置为1M左右即可。如果服务器的性能压力较大,或者对处理时延有很严格的要求,则必须谨慎设置rmem_default和rmem_max,如果设得过小,会导致丢包,如果设得过大,会出现滚雪球.
2. 服务器负载过高,占用了大量cpu资源,无法及时处理linux内核socket缓冲区中的udp数据包,导致丢包.
3. 磁盘IO忙, 服务器有大量IO操作, cpu都在等待磁盘IO,不能及时处理内核socket缓冲区中的udp数据包
4.收发包量太大,网卡中断太多,都分配在同一个CPU上,导致该CPU忙,丢包.
5.UDP包过大,被分片过多.导致丢包率上升
6.劣质路由器,非等频率丢包,一旦内部转包缓存爆满,马上暴力丢弃一定比例的包.一般CPU不忙,IO不忙,线程未阻塞,那一般就是缓存设置过小或包过大.
和TCP不同的应用
1.因为UDP收发包都是单向的,没有连接概念,所以有时候UDP的发包目的server会和回包server可以是不同的地址,比喻像A机器发包,收到的业务回包是B机器.
2.因为TCP的分组每个都需要对方端发来确认,有的当向传播业务,比如上报统计,上报非敏感数据时,可考虑用UDP,会和TCP更合适些,因为对方机器CPU忙,IO忙,线程阻塞时,如果是TCP,本地线程又是同步IO的话,将会严重影响本地线程