使用TCP協議連續傳輸大量數據時,是否會丟包,應如何避免?
比如發送文件。記得有人提過可能會發生什么堆棧溢出。怎樣避免呢?是不是可以收到數據后發送確認包,收到確認包后再繼續發送。或是發送方發送了一些數據后sleep一下。
還有,我們都知道,使用UDP協議發送包時需要確認,但TCP協議時面向連接的可靠傳輸,是不是發出的包肯定可以收到,不需要確認呢?
1 樓netsys2(來電!)回復於 2003-09-23 13:31:44 得分 0 比如發送文件。記得有人提過可能會發生什么堆棧溢出。怎樣避免呢?
------->分段發送,定長接收,正確接收后響應前台。
例如:
前台-->后台:先發文件名,長度等信息,
后台-->前台:發OK,0(這個0表示期待接收的文件偏移)
。。
前台-->后台:發一段
后台-->前台:發OK,下一段偏移。
。。
重復。。到發完
使用UDP協議發送包時需要確認,但TCP協議時面向連接的可靠傳輸,是不是發出的包肯定可以收到,不需要確認呢?
--->不一定,雖然TCP保證你的數據傳輸,但是萬一接收方突然拆線,或者中間交換設備掉線,那么數據完全可能到不到后台,因此得發接收響應包確認。
2 樓shilong(銀羽 www.ylog.net)回復於 2003-09-23 13:44:04 得分 0 丟包是因為發送端發送太快時,接收端會把后面的包和前面的包疊起來了,例如
發送端:發送包1,發送包2
接收端只收到一個包,內容是:包1+包2
我以前也遇到個這種情況,后來用下面的方法解決了替每個包加一個包頭,接收緩沖區建足夠大,然后把接收緩沖區里解出來的包放到一個消息隊列里
PS:最好發送時就在包頭里標下整個包的長度,方便解包
隊列可以用STL中的deque容器解決
3 樓shilong(銀羽 www.ylog.net)回復於 2003-09-23 13:47:50 得分 0
如果TCP的發送函數返回成功 那么就是一定發送成功了,這是TCP協議的特征掉線后發送函數肯定會返回錯誤
4 樓youngwhz(sunbird)回復於 2003-09-23 13:58:19 得分 20
比如發送文件。記得有人提過可能會發生什么堆棧溢出。???
TCP傳輸是可以保證數據交換的可靠性的,但這是指一方的主機將數據正確的傳輸到目標機器中,目標機器的協議棧的堆棧是有一定限制的,如果在目標機器中不及時處理接收到的數據,有可能堆棧會溢出!而這種溢出並不是因為TCP協議本身,而是因為系統的IP協議棧的緩沖區溢出造成!
5 樓navy125(navy)回復於 2003-09-23 18:40:42 得分 0 應該說來是可以避免的,在發送端需要加入Select()選項,等待Select()返回后才會發送下一個包。
Select()作用判斷當前網絡是否可讀或者可寫,如果不可讀或者不可寫函數會被阻塞。
雖然這樣可能會影響一些速度,但是一般不會造成堆棧溢出的。
6 樓Fly1980(飛)回復於 2003-09-23 22:38:29 得分 0
youngwhz(sunbird) 說得非常對。
建議的解決方法:
將文件分塊發送,接收端每收到一塊數據就發送一個收到確認給發送方(包括收到的數據長度)
發送方在收到接收方發送的“收到確認”后才接着發送下一塊數據。。。。
直到整個文件發送完畢。
每塊數據都加一個包頭,里面可以包含一些標志信息,如:是否所有數據發送完畢(即最后一個包了)
Top
7 樓ypos(葉開)回復於 2003-09-28 15:13:16 得分 0
TCP連接在不斷開的情況下可以保證不丟數據
系統的IP協議棧的緩沖區溢出不叫溢出,只能說是丟棄包,屬於正常現象,只是會影響性能,而且TCP自己就有流控,你做TCP時可以不用考慮
至於“收到確認”完全不必要,為了對付連接斷開,可以每個包都帶序號,斷開連接時,發送端重發未發送完的包
8 樓wwwdfq1977(qswl)回復於 2003-09-28 23:58:18 得分 30
我覺得很多人沒有理解tcp/ip的分層概念
用tcp協議時,用send函數發送數據成功,應該指的是應用層向本機tcp那一層傳遞數據成功,而並非指這些數據已經得到對方tcp層確認.
如果連接正常,你向本機tcp層傳遞的數據,對方tcp層絕對可以正確收到,這是tcp協議可以保證的,否則tcp的可靠就沒有意義了.但是如果網絡突然中斷了,那么尚還在本機tcp協議棧中未發完的數據將可能被丟棄,因此如果連接中斷后你又重新連接發送數據時,你發送數據的依據不能由你傳給本機tcp層多少數據來決定,而是應該詢問對方應用層已經收到了多少數據
如果你的程序要求發送的數據必須一字不漏的被接受方收到,那么你必須把發送的數據存為文件,然后發送,發送的規則如上所述,另外,文件傳完時也應該確認,但是你沒必要每個包都確認。
如果沒有這個必要,那么你就用不着確認
9 樓zihan(子寒)回復於 2003-09-29 22:55:06 得分 0 同意樓上的了.的確,tcpip會幫你確認你的包信息,但是如果由於網絡異常引起的,有些時候tcpip也不能夠幫你解決,所以建議把東西保存為一個文件,然后分塊發送,然后自己添加頭尾信息,
不過一般情況下沒有這個必要了.
10 樓asklxf(xuefeng)回復於 2003-09-29 23:32:48 得分 30
使用TCP協議在任何時候都不會丟包,因為:
TCP/IP模型中,IP層負責發送包但不保證正確接收,而TCP層在IP層上,保證每個包正確接收。
在應用程序中,如果用Socket的send發送一段數據,只要函數返回OK,對方肯定正確接收了。
使用TCP傳送數據不用關心數據是否正確接收(TCP保證做到)更不用自己寫應答機制(TCP對每個包都作應答)否則就成udp了。
如果網絡故障,socket會有錯誤報告,tcp連接會斷開,但是已發送的數據肯定正確發送了,你所需要的就是試圖重新連接,然后把沒有發送的數據接着發送出去。
11 樓wwwdfq1977(qswl)回復於 2003-09-30 01:48:11 得分 0
樓上:我不太同意你關於send函數的說法
首先必須明確send函數究竟作了什么,他是負責將數據傳遞給本地tcp層后返回,還是同時負責將應用層傳遞的數據得到接受方tcp層確認后才返回
如果是后者你說的無疑是正確的,但是,事實上完全不是這樣,這是因為如果這樣,那么nagle算法就沒用了,因為這個算法就是將多次send函數的傳入的小數據拼湊成為一個較大的包,然后再發送。
可見,即使是send函數ok了,對方也不一定可以接受到,因為tcp協議只是在tcp層上盡他的義務,而send函數只不過扮演了一個應用層向tcp層傳遞數據的角色,除此之外,他和tcp層沒有任何關系。
還有一種特殊情況,雖說非常罕見,但是並非不可能發生,那就是:如果接受方tcp層確實接受到數據並向發送方發送了確認信息,但是,在他向應用層傳遞數據時,應用層程序突然崩潰,那么接受方的應用程序也是無法接受到數據的,而此時,發送方tcp層得到了確認信息認為這些數據已經發送成功了,這是一書里舉的極端例子,不信的話你可以看一看這本書吧
總之,不要把send函數和tcp協議混在一起,send函數並不是tcp協議里面的東西,send函數並不能保證任何東西,而這些保證是由tcp來完成的
12 樓wwwdfq1977(qswl)回復於 2003-09-30 01:51:36 得分 0 再說一句,tcp不會丟包和send返回ok接受方一定收到沒有任何關系,前者並不意味着后者
13 樓netsys2(來電!)回復於 2003-09-30 10:20:47 得分 0
沒有任何一個函數,協議可以保證完全不丟包,
只不過TCP要好得多,因為它是具有連接和錯誤重發的協議。
在極端情況下(通信線路突然中斷),那么TCP可以報錯,應用程序可以重新建立連接再重傳。
但是中間如果有第三方攻擊(如竊聽者或者線路故障),那么TCP也不能保證你的數據完全到了對方,因此在關鍵的數據交互場合(如網上交易),必須通過應用層的協議加以控制。
14 樓asklxf(xuefeng)回復於 2003-10-06 23:32:22 得分 0
每種語言的send函數都不一樣啊
如果是異步調用,不保證正確發送
但是我用的是java.net.Socket
只要不發生IOException,那肯定正確發送出去了
15 樓awjx(啦啦啦)回復於 2003-10-11 16:30:23 得分 0
我在tcp/ip上學的,怎么與上樓上,上的有很多不同呀?
16 樓xlfrd(顯亮.net)回復於 2003-10-11 19:54:37 得分 0 如果是blocking模式send應該是得到對方TCP協議確認后才返回而不是僅僅得到本機TCP模塊回應就返回,否則send永遠都返回成功,可以如下測試一下,建立連接后斷開物理線路,操作系統不會立即得知物理鏈路已斷開(如撥號),程序再調用send,如果返回失敗說明send是等待確認后才返回,如果返回成功就說明send只需要發到本機TCP就返回。
、
17 樓ypos(葉開)回復於 2003-10-13 08:59:41 得分 0
在TCP上再實現一個窗口控制,緩沖區,確認發送如何?
18 樓deva(zhyi)回復於 2003-10-13 18:07:23 得分 0
tcp的作用就是可靠性傳播
但如果是大量數據而且網絡很快就會出現sequence的重復
這才是最主要的問題!!
19 樓esdn(easy)回復於 2003-10-14 11:32:10 得分 10
關於wwwdfq1977(qswl) 和asklxf(xuefeng)的討論,在網絡編程里這樣的深入不很多見,我想發表一下我的看法。
首先,tcp協議send函數調用后,應用程序里的數據肯定是被傳到TCP/IP協議占的TCP的發送緩沖區里了。
然后,當send函數返回到應用程序時,數據是否發送出去要看Nagle算法開沒開。
1.如果不開Nagle算法,發送方的TCP/IP協議占則執行發送動作。
2.如果開了,看看發送條件是否滿足(如緩沖區是否有一個MSS的數據),不滿足則不發送而返回
滿足則發送之后再返回。
至於對方是否收到並進一步發確認,僅就此無法判斷。
基本原理這樣了,具體系統實現可能還有機制
20 樓asklxf(xuefeng)回復於 2003-10-15 18:40:24 得分 0
我認為樓主的問題是:是否應該使用應答機制來保證不丟包
但是設計tcp協議的目的就是使用應答機制來確保可靠傳輸,tcp已經在傳輸層實現了這一機制,如果自己在應用層在實現一次,有什么意義呢?還不如改用udp。
tcp本身就是用滑動窗口模型,對每個包都會確認,使用tcp連接關心的是處理建立連接和關閉連接,以及連接中斷引發的異常,對傳送數據你就應該完全交給tcp。
我們在學校下電影常常一個文件600-700M,傳輸速度500k-2MB/s,如果tcp不可靠,用ftp怎么保證一次下載幾個G不出錯?ftp協議是基於tcp的。
21 樓xiaohyy(醉大餓極)回復於 2003-10-17 20:34:02 得分 0 想說說關於send函數的問題。send應該是對方收到確認后才返回的,很簡單,從send函數的返回錯誤信息就可以看出,這里隨便舉幾個WSAETIMEDOUT:該錯誤是由於網絡故障或遠程主機當機等原因導致的異常中止連接還有WSAECONNRESET錯誤,這是由遠程主機上的程序強行退出或死掉引起的。 ,如果按照wwwdfq1977(qswl) 的說法只是把數據發送到本機的傳輸層,又怎么能檢測出這些問題?
還有大家在send函數處設置斷點,如果緩沖區夠大,也不是立即返回,還是有一定的時延的。這也說明send函數做了一些底層的工作,接收了對方的確認信息
22 樓wwwdfq1977(qswl)回復於 2003-10-17 21:08:58 得分 0
能不能檢測到錯誤和我的說法有矛盾嗎?
send函數確實不是僅僅把數據傳遞給傳輸層,但是,他一定要等待對方應答后才返回嗎?難道有錯誤就不能在下一次調用時返回
緩沖區太大,有時延,這和他收到了確認信息有什么關系,因為它完全可能作其他工作
注意tcp協議所在的線程和應用程序不再同一個線程內,並不是send一返回tcp就什么都不干了,在此期間他完全可能作一些諸如設置錯誤或正常狀態一類工作,以便程序下次調用send或者closeSocket時返回這些錯誤
我覺得你還是好好看一看前面的所有貼子吧。
23 樓pc200300(只想混碗飯吃...)回復於 2003-10-18 22:05:49 得分 10我想發表一下自己的看法:
(1)如果網線等硬件出現故障,比如網線斷了、一方的SOCKET沒有任何反映,所以檢驗一個連接是否正常,通常采用心跳測試;
(2)send()等函數只是把你要發送的數據寫入你的SOCKET緩沖區,並不保證對方能正確接收到;
(3)TCP是一個可靠的連接,它有自己的一套安全機制,但也不能保證對方能正確接收到;
(4)我的解決方案:自己定義一套應用層的數據傳輸規約,通過摟上幾位提供的方法,可以定義一套安全性很好的規約。
24 樓chengwei_xj(ylxz.blogbus.com)回復於 2003-12-02 13:41:31 得分 0 很高興自己的帖子能夠引起大家廣泛深入的討論,謝謝大家.