因為工作需要,要建立一種可靠的 UDP 數據傳輸的需求。而 UDP 是非可靠的連接,我的想法是用發送-應答的機制來讓數據可靠。而我的做法是定一個發送隊列,發送線程檢查發送隊列,有數據時就發送出去。
而接收線程收到數據後回復一個 ACK. 如果發送端收到這個 ACK 就把相應的發送隊列中的數據刪除,表示這個包已應收到了。而發送線程也會定時檢查看發送隊列裡的數據是否超時,超時就重發。而現在我遇到的問題是因為在發送時,隊列裡的數據可能比較多,一次發送時,會丟一大部份。我就像每發一次包 sleep(5) 也沒有解決多大的問題。而我在任務管理器中發現,網絡寬帶才被利用了一小部份。才 0.2% .為什麼只利用到如些小的寬帶,丟包還這樣嚴重呢?

解决方案 »

  1.   

    不准备自己设计的话,就先看看别人的做法
    www.codeproject.com/internet/udt.asp
    A UDP-based Reliable Data Transfer Library
      

  2.   

    利用UDP发送大块数据,在接收端必须检查接受到的数据是否完整再应答。因为中间网络可能出现IP分包,因此不能保证UDP的数据包一定以发送时数据包大小到达目的机器简易解决方案:
    1、在发送数据中包含数据包长度字段,接收端接收完整再应答。
    2、限制最大数据包大小,即将大数据分断发送。小数据包可以降低分包导致接收不完整的概率性。
      

  3.   

    要解决丢包就用TCP
    首先你要确定你的网络环境,看看是否与包的大小有关,一般的情况下在公网发UDP包大小不超过512字节
      

  4.   

    UDT ,是做得不錯,不過現在有兩個問題  
    1,它差不多是在 UDP 上再實現一個 TCP。  它必須先連接,再發送接收,再斷開。
    2. 它是用 C++ 來做的,生成一個 MFC DLL, 而我希望在 Delphi 裡用。我現在的需求。
     我想保持 UDP 的,一對多地址發送的功能。就是我只開一個端口就可以與多個地址通訊。但又要保證數據的穩定性。
    現在我做了一點。可靠性解決了,但效率還是不高。丟包率太高了。
      

  5.   

    简易解决方案:
    1、在发送数据中包含数据包长度字段,接收端接收完整再应答。
    2、限制最大数据包大小,即将大数据分断发送。小数据包可以降低分包导致接收不完整的概率性。-------------------
    現在我也是這樣做的,把數據分成很多小包,每個小包最大是  1400 字節負載
    因為IP 協議的最大分包是 1460,我這樣保證一個包可以不被分片。而現在的問題,是在大並發時,還是分有丟包的。
    因為我的設計是一個端口對應於多個地址,(可以同時對多個地址發數據)。這樣,我是定一個發送隊列,一個發送線程,發送線程檢查隊列裡的分包,打包後發送。
    接收端收到自己想要的包後回應 ACK. 
    發送端收到這個 ACK 後,發下一個分包。現在的問題是同時發多個分包時丟包比較多。
    比如同時發 1000個 100K 的數據包,在局址網裡要丟 100多個。而同時發 1000個 10K 的數據包要丟得更多。(這個我也不明白)但網絡的利用率,只是太開始發送時達到了最大值,而後面也就 最多30% 左右。我想是因為網絡擁塞造成的。太多小包的並發發送,讓自己或對方的系統 Socket 緩沖溢出,而造成的丟包。我看了一下別人的解決方法都有一個比較復雜的擁塞處理機制。誰能告訴我應該如何處理?
      

  6.   

    即使不并发,UDP报文还是要丢的
    在应用层需要加应答机制,发送放发送一个报文后,对方接收后要给一个应答,如果没有应答,发送放需要重发
      

  7.   

    使用别的方法检查丢包是发生在自己机器上还是发生在网络线路上. 如果发生在机器上, 比如 send 成功返回, 但是事实内核缓冲已满, 所以报文被内核丢弃. 这种情况你只能减慢发送速度, 增大发送缓冲. 上面你提到发送10K甚至100K的UDP包, 这是错误的作法. UDP报文最大64K, 不明白你是怎么做到100K的. 不要发送超过8K的UPD包. 但是你又提到分包为1400字节. 所以我无法理解你的说法.如果发生在网络线路, 不是编程能解决的.
      

  8.   

    使用别的方法检查丢包是发生在自己机器上还是发生在网络线路上. 如果发生在机器上, 比如 send 成功返回, 但是事实内核缓冲已满, 所以报文被内核丢弃. 这种情况你只能减慢发送速度, 增大发送缓冲. 上面你提到发送10K甚至100K的UDP包, 这是错误的作法. UDP报文最大64K, 不明白你是怎么做到100K的. 不要发送超过8K的UPD包. 但是你又提到分包为1400字节. 所以我无法理解你的说法.
    --------------------
    这位大侠说话,我爱听,的确是我没有说的太清楚。我是这样设计的。我把我的程序结构分成两层。最上面是用户层,下面是数据传输层|----------------------------|
    | 用户逻辑层                 |
    |                            |
    |----------------------------|
    | 数据传输层                 |      <-------- 我现在在做这部份
    |                            |
    ------------------------------用户层不管通讯的事,它只是告诉传输层,我有什么数据要传,传到哪个IP,哪个端口。数据传输层收到命令后就开始发送,发送成功或失败,再通知用户层.这样就有两种数据包,一种是用户发给传输层的,我把这叫用户数据包,最大我定成 120K 而真在发送时,会把用户数据包,分成一小个一小个的传输数据包,这个包我定成固定的 1400,定成1400是为了让数据包在 IP层不被分片。我在用户层,可以同时与多个IP之间通讯。这由传输层来控制。
    你说的丢包是发生在网络上还是机器上,这个才是我的确想要解决的问题,我认为现在丢包应该发生在机器上。
    就是我 send 成功,但可能被内核给丢了。但这时我如何知道内核缓冲满了呢? 我现在的 Socket 缓冲是定到 140k 左右。我这样说的原因是我在本机测试时,速度居然只有 400K 左右,而在网络上(公司),就可以到 2M 到 4M .说明在本机时大部份数据都是发送后确认超时等待上了。我想在想大侠给我个方法,如何得知内核 Socket 缓冲满了没?
      

  9.   

    呵呵,偶做过一个这样得程序,不能发一个包校验一次
    可以类似TCP或者得方式,要设置个窗口,每发送完一个窗口后,N个包后,
    等接收端反馈,看是否需要重传,我测试过,可以达到比较高得码率,
    同时实现丢包重传.呵呵。才发现,原来帖子这么老了啊,啊哈哈