轉(zhuǎn)載自:http://blog.csdn.net/leehark/article/details/7661271
對交互數(shù)據(jù)流的處理
TCP包含兩類數(shù)據(jù)流,交互數(shù)據(jù)流和成塊數(shù)據(jù)流。交互數(shù)據(jù)流的特點是每個報文數(shù)據(jù)字節(jié)數(shù)比較小,大部分是10字節(jié)一下,而成塊數(shù)據(jù)流的特點是大部分報文是滿長度的,一般能達到MSS。
本文先介紹一些TCP和PTCP對交互數(shù)據(jù)流的處理。
交互式輸入
Rlogin是典型的交互數(shù)據(jù)流應用,每一按鍵都會產(chǎn)生數(shù)據(jù)分組,使客戶端傳輸一個報文,接連總共產(chǎn)生4個報文:
a.C傳輸交互按鍵數(shù)據(jù)
b.S確認C的數(shù)據(jù)
c.S回顯C的按鍵
d.C確認S的回顯
上面的報文b,c可能會同時包含在一個報文段。而對于TCP報文-有40個字節(jié)的頭部的協(xié)議報文來說每次只傳輸一個字節(jié)是個極大的浪費,此外Rlogin這類應用會在短時間內(nèi)按N個字符,按如上的方式,至少要傳輸3*N個報文。
經(jīng)受時延的確認
經(jīng)受時延的確認考慮了時間有關(guān)的細微之處,對于交互類應用,短時間內(nèi)會產(chǎn)生多個報文。對于TCP,當接收數(shù)據(jù)時,并不立即發(fā)送確認,而先緩存,延遲發(fā)送,以便在短時間如果有該方向的數(shù)據(jù)需要發(fā)送,則一同發(fā)送,這樣能減少ACK報文的個數(shù),提高報文的利用率。TCP通常等待200ms后發(fā)送ACK。
對于PTCP來說,也支持延時確認,默認延時時長為100ms,可以通過選項OPT_ACKDELAY更改延時時間。不另外,如果出現(xiàn)連續(xù)兩個不含數(shù)據(jù)的ACK需要發(fā)送,則不會等到100ms,直接會發(fā)送ACK報文。PTCP發(fā)送ACK的時機如下:
A. 和SEND數(shù)據(jù)一起發(fā)送
B. 等到超時(100ms后沒有數(shù)據(jù)時)時發(fā)送
C. 出錯時發(fā)送(如發(fā)現(xiàn)對方傳來的數(shù)據(jù)和預期的不一致,或者ACK被丟失)
雖然PTCP是等到100ms后發(fā)送ACK,但沒有提供任何定時器,只提供了下次需要被提醒的時間(通過方法GetNextClock),然后由業(yè)務層來實現(xiàn)定時器并通知到時(通過方法NotifyClock)。這樣,業(yè)務層就會有靈活的方式設(shè)置定時器,比如通過消息循環(huán),等待事件,完成端口等等。
Nagle算法
Nagle算法是為了避免在廣域網(wǎng)上出現(xiàn)大量的TCP小分組報文段。該算法要求一個TCP連接上最多只有一個未被確認的小分組。當已經(jīng)發(fā)送的一個分組沒有被確認前,該算法積累所有需要發(fā)送的數(shù)據(jù),等到未被確認的分組確認了,一同發(fā)送,這樣在短時間內(nèi)出現(xiàn)的小分組合并成一個報文發(fā)送,提高了報文的利用率。這個算法是自適應的,得到確認越快,則發(fā)送頻率越高。偽代碼如下:
if there is new data to send
if the window size >= MSS and available data is >= MSS
send complete MSS segment now
else
if there is unconfirmed data still in the pipe
enqueue data in the buffer until an acknowledge is received
else
send data immediately
end if
end if
end if
PTCP也支持Nagle算法,可以通過選項OPT_NODELAY開啟或者關(guān)閉。Nagle算法的實現(xiàn)比較簡單,當嘗試發(fā)送數(shù)據(jù)時,發(fā)現(xiàn)如果有未確認的數(shù)據(jù)且等待發(fā)送的數(shù)據(jù)長度小于MSS,則延遲發(fā)送,如下:
- void PseudoTcp::attemptSend(SendFlags sflags) {
- ......
-
-
-
-
- if (m_use_nagling && (m_snd_nxt > m_snd_una) && (nAvailable < m_mss)) {
- return;
- }
- ......
- }
窗口大小通告
TCP和PTCP都通過頭部的window字段通告接收緩沖區(qū)的可用窗口大小。當客戶端收到服務器的數(shù)據(jù),并有等待發(fā)送的數(shù)據(jù)時(開啟Nagle算法時會經(jīng)常出現(xiàn)此情況),通告給服務器的窗口大小總是小于接收緩沖區(qū)的大小,是因為,應用層還沒有拿取剛從服務獲取的數(shù)據(jù)之前,就會嘗試發(fā)送被緩沖的數(shù)據(jù)。
PTCP的實現(xiàn)如下:
當PTCP接收對方發(fā)送的數(shù)據(jù)時會調(diào)用NofifyPacket->parse->process,在Process先調(diào)用attemptSend發(fā)送緩沖的數(shù)據(jù),然后通知應用層有可讀數(shù)據(jù)。
- bool PseudoTcp::process(Segment& seg) {
- ......
- attemptSend(sflags);
-
- if (bNewData && m_bReadEnable) {
- m_bReadEnable = false;
- if (m_notify) {
- m_notify->OnTcpReadable(this);
- }
-
- }
- return true;
- }