UDP踩坑——为啥老阻塞?

众所周知,UDP是尽力而为的服务,也就是传输是不可靠的,丢包不会给你重传,只会做一些简单的查错。最最最重要的是UDP没有TCP的三次握手机制!如果大家想要通过UDP传输一些文件之类的话,就需要模拟TCP三次握手,让UDP能够“活”起来,不然就会造成丢包,或者造成因为丢包而产生的阻塞。

  1. 踩坑①:


    UDP踩坑——为啥老阻塞?_第1张图片
    图中左侧的流程中,Client端按照文件大小除以packet大小来确定while循环的次数,这是比较致命的,因为在UDP中极有可能出现丢包的情况,那么循环的次数就不是正确的次数了,从而造成阻塞。而丢包在以太网中还是比较少见的,但是还是发生了丢包,这是为什么呢?八成就是在在Socket建立之前就丢了!所以进而造成循环次数不对,Client苦苦等待,Server端已经发完运行之后的程序了。

    那么我们应该如何解决这样的问题呢?

    • 不用循环次数来退出while循环!而用自定的一种说明,比如Server端传完数据之后再额外发一个终止信息,Client接收到终止信息之后退出while循环,那么这样依旧可能造成终止信号丢失,Client又阻塞了...这时一个办法是采用可靠传输的TCP传送终止信号,或者通过setSoTimeout来设置超时时间,一旦超过这个时间就退出。
    • 让Server端等待Client建立Socket,建立完之后再给爷传!也是采用可靠的数据传输TCP,告知Server我已经建立连接了,您可以传输了。也就是图中右侧部分的流程。
    • 图中还有第三种解决方法就是直接让Server端sleep,但是因为时间不太好确定,所以不太推荐。
  2. 踩坑②:

    在server端,我们创建固定大小(如512B)的byte[] b封装我们的dataPacket,但是文件往往不是能被完整划分的,所以最后一个文件的实际信息大小可能会小于512B。此时在Client,我们将传输之后的文件写进本地的文件中,dp是dataPacket,里面存储着传输过来的信息byte[] b =dp.getData(),在将b写入文件时,我们应该取0-b的实际有效信息的长度,不然会产生实际有效信息长度小于512B时,b会被自动填充前面一个dp的信息以使得b的大小达到512,这就产生了冗余

    具体结果如下:

    正确接收文件:

    UDP踩坑——为啥老阻塞?_第2张图片
    产生冗余之后的:

    UDP踩坑——为啥老阻塞?_第3张图片
    可以明显看到重复的文字,所以我猜测dataPacket是排队连起来的,若信息长度不够时,会拿前面一个数据包信息填充。

你可能感兴趣的:(udp网络传输协议)