用UdpClient在两个设备之间传送byte[],一个Send,一个Receive,99%都OK。
但是,在某些特定的情况下,会发生丢包。一边Send之后,另一边Receive没反应。这种特定情况感觉很随机,与数据和设备有关,因为同样的设备把传送的byte[]换几个字节,或者同样的byte[]放到其他设备上传送,就没问题。
用WireShark查看,正常情况下在发送方和接收方都是一条同样的UDP包信息。而在异常的情况下,发送方的UDP包的报头里面Flags变成了0x01(More Fragments),但Fragment offset还是0。Data也被截掉了一部分。紧接着会产生一个IPv4包 Fragmented IP rotocol(proto=UDP 0x11,off=1480,ID=4573),Flags为0,Fragment offset为1480。此时WireShark显示接收方收到一个UDP包,但是整个Frame的Length比发送出来的要短得多,Flags为0,Fragment offset为1480。但Data里面却有完整的数据。这样的UDP包不能被UdpClient捕获到。
由此看来包被分割了。即使指定了UdpClient.Client.SendBufferSize为一个远大于byte[]长度的值也没用,而如果指定UdpClient.DontFragment = true则会报“一个在数据报套接字上发送的消息大于内部消息缓冲区或其他一些网络限制,或该用户用于接收数据报的缓冲区比数据报小”的错误。看来是受硬件设备的影响。但是奇怪的是似乎与byte[]的长度没关系,传送失败后在byte[]中再添加几个字节又能传送成功。这是为什么呢?系统分割数据包的方式是怎样的?当然我可以自己去分割,但是这样牵扯到太多了。所以只能希望有什么办法能够在现有的基础上作调整。
有谁遇到过这个问题没?精通网络编程的说说有什么想法,谢谢。这两天被这个问题折腾得够呛。

解决方案 »

  1.   

    UDP不会自动拆包,必须在发送前自行将数据拆分后发送,超过1500的必须拆分,安全起见设定为1400。
    另外为了UDP传输的安全性,每个数据包的前面第一个字节必须用来存放当前包序号,为了序号不连续的丢包现象能及时被发现并重传,而整个数据的大小应该在序号为0的数据包后仅跟着4字节长度(int类型)来指明。
      

  2.   

    如果你传超过以太网帧(1500字节左右)的数据,udp就不太适合,否则udp可能乱序,你自己维护序列号得烦死你
      

  3.   


    用于文件传输的,Manager的决定。早就跟他说过用UDP不好了,无奈。
      

  4.   


    如果我没记错,TCP/IP详解里说了udp是可以自动分片的,因为udp是传输层,而分片是更底层的ip层做的,不是一个层级你的问题可能就是传输中丢包或乱序了
      

  5.   


    确实选技术选的不太好,如果用tcp,windows api一个函数就可以吧一个文件发出去,连读文件、缓冲区什么的都不用考虑,TransmitFile这个函数吧,传进去文件句柄和socket就行
      

  6.   

    能说说你们manager用udp的理由么,如果说效率,那是杞人忧天,假设百兆以太网,极限速率12.5MB/s,你用tcp,即便协议开销大些,速度上11MB/s也是小意思
      

  7.   


    他就一句“udp比tcp”好,然后我们就无奈了。
      

  8.   

    彻底解决udp的丢包和乱序,需要有个流水号记录顺序和丢失状况,还有有超时重发机制,这个超时重发通常又是重发全部而不是一个包,因为你不知道哪个包丢了,让对端告诉你的话这个“通知”一样可能丢如果udp没开校验和,还需要加个crc之类的保证没有电磁干扰造成的错误最后就相当于自己实现tcp,开销往往比直接用tcp还大所以udp只适合不怕丢包,不怕乱序的场合
      

  9.   


    超时重发和CRC校验是有的。偶发性的丢包会是考虑到了的,现在遇到的是必然性的,所以这边不停地发那边不停地丢。好像这个跟数据长度有关,在某个特定值的整数倍之内必然丢包。
      

  10.   


    如果是这样的话可能跟缓存有关,用SetSocketOption设定下接收和发送缓存,改大点,看还出不出现用udp发送文件,如果能做的稳定高效,那实现者的水平可以去做tcp/ip协议了,随意还是不建议用
      

  11.   


    SetSocketOption怎么设置缓存大小?我试过设置udpClient.Client.SendBufferSize,没用。我发现数据长度在1512的整数倍10bytes的波动范围内就一定会丢。
      

  12.   

    那就超出鄙人经验范围了,因为我很清楚udp的问题,从不会拿他发大文件不值得为错误的设计和技术选型浪费太多心思,我觉得一个靠谱的团队leader应该能听进去正确意见
      

  13.   

    UDP要考虑的问题很多,除非是影音传输,不考虑丢包的场合,否则不建议使用,虽然QQ用它来传文件,但是人家技术力量雄厚,不是一般公司可以效仿的,这个UDP真要实现可靠传输,要考虑的问题很多,首先那个丢包重传要自己考虑,而TCP则是自动重传的。但这还不是最难的,最难的是速度控制,TCP有个自动控速算法,而UDP则没有,必须自己实现,否则当你的发送速度远大于对方的接收能力或大于网络传输能力,将导致大量丢包,重传都来不及,恶性循环。
    自动控速算法要实现非常难,你可以参考下TCP的实现方式,由于发送方不知道带宽有多大,因此发送速度不能实现设定好,要在发送过程中实时调整速度已达到最大化利用带宽。
    至于你说的可以自动拆包?我反正超过1500的情况都传输失败,100%丢包。即使可以又如何?如果要控制速度,丢包重传,你不自己拆包又如何控制?
      

  14.   


    这些我也知道,我只是在找有没有不动协议解决问题的办法,没有再说。udp传文件第一决定不是我做的第二代码不是我写的,现在出了问题叫我处理而已。
      

  15.   


    嗯,我也打算劝leader改tcp了。