from http://www.ideawu.net/blog/archives/528.html
2010.07
TCP 協(xié)議是大量重要的網(wǎng)絡(luò)和通訊的思想和技術(shù)的集合體. 這些思想和技術(shù)被應(yīng)用在 TCP 身上, 另一方面, 學(xué)習(xí) TCP 可以了解這些思想和技術(shù). 通訊的思想和技術(shù)不僅僅可以應(yīng)用狹義的數(shù)據(jù)通訊上, 也可以應(yīng)用在廣義的信息通訊上, 后者一般可以理解為應(yīng)用層的交互協(xié)議, 例如即時(shí)通訊(IM)的聊天協(xié)議.
首先, TCP 協(xié)議是一種可靠的傳輸協(xié)議. 這種可靠性可以從兩方面理解: 1. TCP 保證數(shù)據(jù)的有序性和無差錯(cuò); 2. TCP 盡最大努力確保數(shù)據(jù)被接收.
有序和無差錯(cuò)可能比較好理解, 但"最大努力"則和我們一般理解的"可靠"有較大差別. 首先, TCP 盡最大努力傳輸數(shù)據(jù), 一旦發(fā)送方無法保證數(shù)據(jù)傳輸?shù)浇邮辗? 它將通過斷開連接(使連接失效)來聲明這一點(diǎn). 其次, TCP 可以明確地告訴一個(gè)數(shù)據(jù)分段已經(jīng)被對(duì)方接收, 但無法準(zhǔn)確的斷定未被確認(rèn)的數(shù)據(jù)沒有被對(duì)方接收, 也就是說, 數(shù)據(jù)可能沒有被對(duì)方接收, 也能已經(jīng)被對(duì)方接收. 這種對(duì)傳輸失敗的不確定性, 顯然是對(duì)可靠性的一個(gè)重大打擊. "兩軍隊(duì)問題(Two Army Problem)"說明了這一點(diǎn), 事實(shí)上, 我們無法判斷一個(gè)確認(rèn)(ACK)是丟失了還是沒有發(fā)出.
大部分可靠協(xié)議使用"帶重傳的正面確認(rèn)(PAR, Positive Acknowledgment with Re-Transmission)"機(jī)制, TCP 協(xié)議也不例外. TCP 的如下特點(diǎn)可以在我們?cè)O(shè)計(jì)可靠傳輸協(xié)議時(shí)參考:
連接的建立是面向連接的協(xié)議所必須的. 連接建立的過程雙方可進(jìn)行某些變量的協(xié)商, 如序號(hào). 更高層次的應(yīng)用層協(xié)議還協(xié)商版本號(hào), 處理速度等.
分段也即是一般所說的"分包", 也即消息和報(bào)文的概念. 序號(hào)是為了保證消息的有序性, 用于亂序重排.
分段方式有3種: 1. 固定長(zhǎng)度; 2. 報(bào)文自聲明長(zhǎng)度; 3. 分隔符.
基于 TCP 這樣可靠傳輸?shù)膮f(xié)議而設(shè)計(jì)的上層協(xié)議往往不需要序號(hào)機(jī)制, 但分段大部分情況都是必須的. 序號(hào)也是確認(rèn)和重傳的基礎(chǔ). 基于 TCP 的 HTTP, FTP, SMTP 等協(xié)議, 沒有序號(hào)概念. 這是因?yàn)? 底層的 TCP 已經(jīng)保證了有序和數(shù)據(jù)不會(huì)丟失. 基于 TCP 設(shè)計(jì)的協(xié)議也可能需要序號(hào)機(jī)制, 使用 TCP 的協(xié)議需要序號(hào)機(jī)制的條件為: 1. 協(xié)議不依賴連接, 一次上層的會(huì)話可能經(jīng)歷 TCP 的斷開和重連; 2. 協(xié)議不是停止等待式的"請(qǐng)求-響應(yīng)"模式.
確認(rèn)和重傳消息報(bào)文丟失影響的方法. 確認(rèn)有立即確認(rèn)和延時(shí)確認(rèn). 重傳的觸發(fā)時(shí)機(jī)不僅僅是超時(shí), TCP 還設(shè)計(jì)了立即重傳機(jī)制.
簡(jiǎn)單的停止等待機(jī)制是一種退化了的滑動(dòng)窗口. TCP 的最大傳輸速度是 wnd_size/rtt, 因?yàn)?RTT 一般主要受物理?xiàng)l件影響, 所以通過增加窗口大小來提高 TCP 的速度.
發(fā)送方至少有 4 個(gè)變量: snd_una, snd_nxt, snd_max, snd_wnd.
snd_una: 未被確認(rèn)的第一個(gè)序號(hào). TCP 的 ACK 確認(rèn)的是已收到的最大序號(hào)+1.
snd_nxt: 下一個(gè)要進(jìn)行發(fā)送(包括重傳)的序號(hào), 如果不是重傳, 則與 snd_max 相等.
snd_max: 下一個(gè)要進(jìn)行第一次發(fā)送的序號(hào), 即已發(fā)送的最大序號(hào)+1.
snd_wnd: 窗口大小.
接收方至少有 2 個(gè)變量: rcv_nxt, rcv_wnd.
rcv_nxt: 下一個(gè)要接收的序號(hào), 也即要發(fā)送(或已發(fā)送的 ACK).
rcv_wnd: 窗口大小.
擁塞控制, 流量控制, 選擇ACK, 序號(hào)回繞等等, 都是可以學(xué)習(xí)的東西.
IM 的聊天協(xié)議需要面向連接嗎? 以騰訊 QQ 為例, 它并沒有使用應(yīng)用層的面向連接機(jī)制(即會(huì)話機(jī)制), 而是發(fā)送方確保發(fā)送到中轉(zhuǎn)服務(wù)器, 中轉(zhuǎn)服務(wù)器確保發(fā)送到接收方.
騰訊的 QQ 缺少序號(hào)機(jī)制, 無法保證有序性(可完全避免). 而且缺少完善的應(yīng)用層的確認(rèn)和重傳機(jī)制, 常常出現(xiàn)發(fā)送方提示發(fā)送失敗, 但接收方事實(shí)上已經(jīng)收到了的現(xiàn)象(無法完全避免但可減少出現(xiàn)概率到極小).
我認(rèn)為, QQ 應(yīng)該解決消息的無序性問題, 并且完善確認(rèn)和重傳機(jī)制. 聊天消息應(yīng)該實(shí)現(xiàn)這些狀態(tài): 發(fā)送中, 取消中, 發(fā)送成功, 未發(fā)送.
聯(lián)系客服