tcp協議可靠嗎? 怎麼知道自己發出的消息已經被是否被成功接收?
在使用基於tcp編程的時候,客戶端發送消息給伺服器,伺服器收到消息後會提交處理並給出應答。 如果極端情況下,網路使得ack一直不到客戶端,這時tcp關閉連接。客戶端收不到ack認為發送失敗, 服務端處理了客戶端認為失敗的消息。 是不是存在這樣的情況?本人大三,最近整理以前寫的即時通信的項目,發現好像tcp無法保證消息可靠的到達對方! 上面的說法如果有不對的地方,請大家指正
~~~~~~~~~~~~~~~~華麗的分割線~~~~~~~~~~~~~~~~
補充問題:
我們知道http協議是基於tcp的, 假設我們上網購物付款 付款環節中通信過程恰好發生前面我們講的tcp可能出現的事情。那麼在這裡就是客戶認為付款失敗,而實際服務端已經處理這個事務,連接因為超時而斷了。(有同學可能會說 成不成功有簡訊通知,這裡我們假定手機此時完全沒信號 ) 那麼客戶可能是急需要這個商品的(比如搶票), 他也許會登錄並繼續購物,那麼是否會存在客戶重複購買?(一般情況下,不會在客戶登錄的時候告訴他 他以前買的東西成不成功吧! 或者用戶使用另外的帳號 ,所以業務也沒法解決這個問題) 不知道http, 或者淘寶怎麼來考慮這個問題。 如果說應用層來給應答的話那麼應答無論加幾層 都無法完全避免這個問題! 也就是說我們的很多網路活動都是在極大概率下沒有問題的信任上進行的么 ? 希望大家 不要怪我較真! 如果上述表達有不準確的地方 希望大夥給點指導
樓主這個問題很有想法,看了三遍才弄明白你的意思,談談我的看法:
1)TCP保證可靠傳輸毋庸置疑,TCP對傳輸的每一個位元組都需要確認,如果沒有在timeout 時間內收到確認,將繼續retransmit,直到獲得ACK為止
2)樓主提到的這種情況是有可能發生的,比如客戶端網上購票,點擊確認按鈕,請求發送出去,到達伺服器端,伺服器返回ACK,但是因為網路故障,ACK沒有到達客戶端,但是有沒有想到和ACK一起出去的也有伺服器的數據,什麼數據?HTTP也是一個互動式協議,有客戶端的HTTP Request請求,就會有伺服器端的HTTP Reply應答,這些HTTP Reply 也需要客戶端來ACK,由於這些HTTP Reply無法到達客戶端,超時重傳,直到TCP連接被reset,也沒有收到客戶端的ACK,於是伺服器對沒有確認的HTTP Reply 回滾Rollback,同時對客戶端的HTTP Request請求也rollback,這個交易transaction失敗!
所以客戶端的HTTP購票請求最終還是伺服器做回滾rollback處理,交易失敗!不會出現客戶端認為交易失敗,而伺服器端認為交易成功的情況。
讓對方收到之後回個話唄。
什麼是可靠傳輸?打個比方:你說了什麼話,我就聽到什麼。我不會把你的一句話聽成兩句(重複幀),也不會把你的兩句話順序顛倒(亂序幀),更不會把你的話聽漏了(丟幀)。
但不能保證你說的話我一定能聽完,我可能聽一半就走了。這種情況相當於強制斷開連接。
下面舉個例子:
A:你好!(syn)
B:嗯。你好!(ack syn)
A:嗯。(ack,三次握手)
A:今天天氣不錯
B:嗯
A:然後我去打球
B:嗯
(這時B一聲不吭走了,A沒看到)
A:發現球場人好多
A:發現球場人好多(你怎麼不嗯?)
A:發現球場人好多
A:發現球場人好多
A:(沒意思,不說了)再見(Fin信號)
B聽到了兩句話:今天天氣不錯,然後我去打球。這兩句話是完整的,沒有重複而且順序也沒亂,所以是可靠的消息傳輸,雖然沒有聽完。
題主可能想問:如果A說話說到一半突然走了,會發生什麼。那麼對話會是這樣的:
A:你好!
B:嗯。你好!
A:嗯。
A:哎,請告訴我今天溫度是幾度。我問完了。
B:嗯。27度。回答完畢。
A:嗯。哎,請告訴我世界上最
(A一聲不吭走了,B沒看見)
B:(等你說完)
B:(等你說完)
B:(不說算了)再見。
B沒聽到「我問完了」,所以不會做出回應。這種機制保證了伺服器不會處理只接收一半的請求。
補充:那如果A沒聽見「嗯」會發生什麼呢?
省略三次握手。
A:第一句話:今天天氣不錯
B:嗯。我聽到第一句話了。
A:第二句話:然後我去打球
B:嗯。我聽到第二句話了。(A沒聽到這句)
A:第二句話重複:然後我去打球
B:嗯。我聽到第二句話了。
至少tcp告訴你說到達了他一定到達,如果中間出了錯,結果一定是斷開連接。我覺得這個很可靠啊,不會有什麼奇怪的中間狀態,譬如說丟了幾個byte你還不知道什麼的。
1.無論什麼協議,只是為了解決某些問題。
2.你需要解決的問題有ABCD,但TCP協議只解決AB,因此你自己要解決CD。
3.不要相信協議。關鍵業務,要自己在程序里做好驗證。
TCP負責數據流控制,IP負責路由。
TCP控制的是數據流,能保證順序和內容的正確性;UDP控制數據報,只能保證內容的正確性,不保證多個數據報的可到達和到達順序。
TCP能保證數據
1.無法到達,並且雙方知道連接異常斷開;
2.按發送順序正確,內容正確的到達;
以上兩者中的一個。
只要線路沒有問題,連接異常斷開可被檢測,否則數據流按順序到達對方套接字。
如果對延時敏感,建議選擇UDP,並在應用層加入數據報到達後回送通知。
先說結論:需要應用層增加ACK
《tcp/ip協議詳解 v1》在第17章的開始就說
T C P通過下列方式來提供可靠性:
? 應用數據被分割成T C P認為最適合發送的數據塊。
? 當T C P發出一個段後,它啟動一個定時器,等待目的端確認收到這個報文段。如果不能及時收到一個確認,將重發這個報文段。
? 當T C P收到發自T C P連接另一端的數據,它將發送一個確認。這個確認不是立即發送的。
? T C P將保持它首部和數據的檢驗和。這是一個端到端的檢驗和,目的是檢測數據在傳輸過
程中的任何變化。如果收到段的檢驗和有差錯,T C P將丟棄這個報文段和不確認收到此
報文段(希望發端超時並重發)。
? 既然T C P報文段作為I P數據報來傳輸,而 I P數據報的到達可能會失序,因此 T C P報文段的到達也會失序。如果必要, T C P將對收到的數據進行重新排序,將收到的數據以正確的順序交給應用層。
? 既然I P數據報會發生重複,T C P的接收端必須丟棄重複的數據。
但上述這些TCP的可靠性解釋都是針對操作系統內核態來說的,因為tcp層,ip層以及鏈路層都位於內核態。當然,也有用戶態的tcp實現,但你在通用操作系統上面通過 socket api來編程肯定是內核態的tcp。
雖然內核保證你的數據一定是可靠的,你的應用程序卻不一定能做到這一點,所以在應用層還是要有一層ACK。
所謂可靠,並不是說數據一定能送達。而是表示如果消息不能送達,能返回失敗或中斷連接,讓收發方感知到。不至於中間丟了一些數據而收發方毫無覺察。
A發送的消息時候,同時會把數據拷貝放入一個重傳的隊列裡面,並啟動一個定時器;如果這個定時時間後得不到ack確認,則A會嘗試重傳,並重置定時器。這個重傳的超時時間,Retransmission Timeout, 協議裡面給了一個簡單演算法,其實可以根據情況,不同TCP/IP協議棧可以有自己演算法。
那麼A一直在重傳,B並不知道這個事情,B由於已經收到數據,就會上報應用程序進行處理。處理完後,如果要返回結果給A, 則進入B-&>A的傳輸流程。當然,如果在處理業務過程中,連接被A主動斷開(其實A的應用層感知不到TCP重傳,斷開的話可能是協議棧斷開,比如keep-alive超時),那麼B會受到FIN請求,就會上報事件,應用層發現這個異常可以中斷業務處理,也可以繼續進行,這是你自己的應用層來決定的。
這裡A,B如果是C-S模式,主動發起的A可以看做是Client,B看作是Server。
TCP的可靠是保證消息可以有序的到達對端,如果到達不了,用重傳機制來嘗試,或者通知上層應用消息無法傳達。並不是一定保證消息必須到達對端。 UDP就不保證消息有序對的到達對端,只管發出去,甚至連對端有沒有開啟服務都不用知道,本身也沒有重傳機制來保證。TCP並不保證數據一定會被對方端點接收,因為這是不可能做到的。如果有可能,TCP就把數據遞送到對方端點,否則就通過放棄重傳並中斷連接這一手段通知用戶。從這個角度來說,TCP也不能被描述成是百分百可靠的協議,它提供的是數據的可靠遞送或故障的可靠通知。
tcp是可靠傳輸協議,可以理解為
發送方發送信息時,如果傳輸層告訴你我發送成功了,那麼它一定發送成功了!!
發送方告訴你未發送成功,那麼它不一定沒有發送成功。很有可能只成功發送了部分信息。也可能完全發送給了接收方只是沒有收到應答。
tcp在我看來還是十分可靠的。並且接收方對收到的數據還會進行和校驗。
我覺得題主在即時聊天中遇到了問題,它的原因是多樣化的,不要僅僅只懷疑tcp的問題。比如是否與NAT有關,做即時通訊在同一個區域網是不會存在NAT的,但是既然是區域網,網路狀況不至於很差。所以我推遲題主的測試不是在同一個區域網中。那麼這時就必須考慮NAT了。
單純談論「可靠」是沒有意義的。在你的場景中確實存在這種問題,需要在上層應用中解決。
最好讓你的API是冪等的,即同一消息重複發送給服務進程,效果跟只發送一次一樣。如果不能,要有協議識別重複的消息。恩,TCP 確實不能保證消息的萬無一失,你必須要在你的業務上,去實現消息可靠性,也就是要在應用層的基礎上去做消息的確認重傳和去重,應用層面上的消息確認重傳和tcp層協議上的概念不是一樣的,在應用層面上實現的時候,需要服務端或者客戶端返迴響應的ack,在一個網路波動非常大的連接上,有的時候你發送消息成功了,但是中途ack丟失了,或者伺服器根本就沒有接收到,這個時候需要對端的重傳機制,來保證消息的可靠傳遞,具體的實現可以私聊我。
TCP被認為是可靠傳輸,是被認為,不是就是可靠傳輸。三次握手已經保證了足夠的可靠性。四次握手,五次握手可以提供更高的可靠性,但和三次握手相比,提高的不多,而且代價增大。再多的握手也不能保證完全可靠。
你描述的問題在傳輸層確實存在,這個你改變不了,你在應用層需要去做保護。當然要看需求了,聊天QQ啥的就算了,借錢付款啥的就不能馬虎了。TCP是傳輸層協議,可靠工作的前提是雙向可達。問題中的Ack丟失可以簡單等同一個方向的線斷了。
你這個情況非常像打網遊的時候,比如說你客戶端的角色前進了,伺服器收到了你前進的信息,然後你客戶端又以為伺服器沒收到,於是沒前進。網路卡的時候會發現角色突然位置跳變了,可能是伺服器直接把角色的實際位置傳回來了。
三次握手四次揮手,如果現實中有個人和你噓寒問暖多次,你是不是覺得他是安全的。先別管他是不是裝的。另外,tcp的三次握手也有點類似於偽裝安全。
tcp是可靠的傳輸協議,除非網路斷線,否則一定是可以正確把數據送過去的。但其建立連線比較耗時,所以會犧牲部分速度。還有你說的即時通信,一般是用udp的。
很多人都理解錯了。
Tcp,調用socket的send函數, 只是把數據發送到網路,無法保證對方收到。原因是理論上無法做到。
關於這個,可以看「兩軍問題」。
Tcp保證的是順序。接收方如果收到了第100個位元組 ,那麼前面99個位元組都沒有丟。
send函數, 調用成功,只是數據進入了本機協議棧的緩衝區,如果緩衝區未滿,一般都可以立即進入緩衝區。這個可用代碼實驗證實。
無論是用同步,非同步,完成埠,發送之後的都是同樣的作用,讓數據進入協議棧的緩衝區。它們都無法保證數據 一定被對方收到。
孩子,TCP協議是可靠的。僅限於傳輸控制可靠。
基於TCP協議上層的應用,還要自己保證應用業務的可靠。必須的。
只有在程序和網路發生異常的情況下才不可靠, 主要表現為最後的部分數據可能無法正常處理或被丟失. 除此情況之外, 則都是可靠的.
單從TCP層面來講, 只要經過正常的斷開握手, 那麼這一整個通信過程, tcp是完全可靠的完成了任務. 至於上層應用程序有沒有讀完就crash掉了, 這已經不關TCP的事了.
另外, TCP在遇到網路故障的時候, 丟失的可能也只是最後部分的數據, 在這種情況下講TCP不可靠, 我認為是不對的, 因為這對於TCP來說, 可以看成不可抗拒的力量導致的數據丟失.
結論, TCP是可靠的.首先tcp的可靠性已經說的很明白了。你說的借錢那種場景一般是這樣:客戶端B向伺服器A發送請求,A收到了,但是應答ack沒有正確返回,於是客戶端B認為自己請求失敗(實際上A已經處理完請求)。於是B再次發送一個請求,這裡A就應該做一個處理,發現這個請求和上一個請求一樣(或者通過查詢發現有一個處理結果),那麼就應該重置上一次請求或者忽略當前請求並把上一次的結果返回。
推薦閱讀:
※tcp上傳文件時的ack變化?
※怎樣生動描述 TCP 的「三次握手」?
※tcp協議握手為什要各隨機一個數字並加一?
※在TCP里可以讓數個Application共享一個Port么?
※在以TCP為連接方式的伺服器中,為什麼在服務端設計當中需要考慮心跳?