用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[]中再添加几个字节又能传送成功。这是为什么呢?系统分割数据包的方式是怎样的?当然我可以自己去分割,但是这样牵扯到太多了。所以只能希望有什么办法能够在现有的基础上作调整。
有谁遇到过这个问题没?精通网络编程的说说有什么想法,谢谢。这两天被这个问题折腾得够呛。
但是,在某些特定的情况下,会发生丢包。一边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[]中再添加几个字节又能传送成功。这是为什么呢?系统分割数据包的方式是怎样的?当然我可以自己去分割,但是这样牵扯到太多了。所以只能希望有什么办法能够在现有的基础上作调整。
有谁遇到过这个问题没?精通网络编程的说说有什么想法,谢谢。这两天被这个问题折腾得够呛。
另外为了UDP传输的安全性,每个数据包的前面第一个字节必须用来存放当前包序号,为了序号不连续的丢包现象能及时被发现并重传,而整个数据的大小应该在序号为0的数据包后仅跟着4字节长度(int类型)来指明。
用于文件传输的,Manager的决定。早就跟他说过用UDP不好了,无奈。
如果我没记错,TCP/IP详解里说了udp是可以自动分片的,因为udp是传输层,而分片是更底层的ip层做的,不是一个层级你的问题可能就是传输中丢包或乱序了
确实选技术选的不太好,如果用tcp,windows api一个函数就可以吧一个文件发出去,连读文件、缓冲区什么的都不用考虑,TransmitFile这个函数吧,传进去文件句柄和socket就行
他就一句“udp比tcp”好,然后我们就无奈了。
超时重发和CRC校验是有的。偶发性的丢包会是考虑到了的,现在遇到的是必然性的,所以这边不停地发那边不停地丢。好像这个跟数据长度有关,在某个特定值的整数倍之内必然丢包。
如果是这样的话可能跟缓存有关,用SetSocketOption设定下接收和发送缓存,改大点,看还出不出现用udp发送文件,如果能做的稳定高效,那实现者的水平可以去做tcp/ip协议了,随意还是不建议用
SetSocketOption怎么设置缓存大小?我试过设置udpClient.Client.SendBufferSize,没用。我发现数据长度在1512的整数倍10bytes的波动范围内就一定会丢。
自动控速算法要实现非常难,你可以参考下TCP的实现方式,由于发送方不知道带宽有多大,因此发送速度不能实现设定好,要在发送过程中实时调整速度已达到最大化利用带宽。
至于你说的可以自动拆包?我反正超过1500的情况都传输失败,100%丢包。即使可以又如何?如果要控制速度,丢包重传,你不自己拆包又如何控制?
这些我也知道,我只是在找有没有不动协议解决问题的办法,没有再说。udp传文件第一决定不是我做的第二代码不是我写的,现在出了问题叫我处理而已。
嗯,我也打算劝leader改tcp了。