/* Let the stack know that we have taken the data. */
msg.function = do_recv;
msg.msg.conn = conn;
if (buf != NULL) {
msg.msg.msg.r.len = buf->p->tot_len;
} else {
msg.msg.msg.r.len = 1;
}
TCPIP_APIMSG(&msg);
/* If the change in the right edge of window is significant (default
* watermark is TCP_WND/2), then send an explicit update now.
* Otherwise wait for a packet to be sent in the normal course of
* events (or more window to be available later) */
if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD)
tcp_ack_now(pcb);
到這里終于知道了,原來TCPWEINDOW在這里更新啊。不錯不錯。什么時候更新呢?那是有條件的
這就是條件。
于是解決了第一個疑惑那就WIN的UPDATA.
接下來就是WIN=0?為何?
其實上個問題已經解釋清楚了,我們只需要引深一下就好,那就是WIN只有在應用程序讀走TCP推上來的BUF后才會更新WIN,否則的話就會對WIN進行相應載荷的減操作。如果應用程序很忙,你叫他他并不響應,此時WIN就處于不斷下滑不斷減少的境地。然后WIN=0,最終用完了WIN,因為應用程序很忙嘛,他沒有時間了作別的他得處理,至于為什么忙,比如一個更改優先級的線程就緒了執行中而讀取他的線程掛起等待,這就是典型的。很多原因的。于是WIN=0了。HOST一看WIN=0,就想:我擦:竟然沒有空間了?好吧我停止吧。你沒地方讓我的人過去呆在那里?于是乎他等了一會就掛斷聊!一個RST隨之產生OK,這樣似乎很符合抓包獲取的流程。事實應該89不離十。這里面還有TCP的另一個概念,就是延時的概念,也就是PUSH和ACK并存的時候,在TCP數據發送的時候TCP并不是立即發送而是有規律的推遲發送,以利用一個包傳送更多的信息,這是另一個重要的模塊。不過這里不討論此方面的問題。
再回到最初的地方,如果按照以上所述則則應用層處理的越快UPDATA應該每次都很順利的更新。試試看
send(tcp_clint_sock, recv_data,bytes_received, 0);
去掉郵箱之后的此函數之后,再去開wireshak 抓取的包就是一個完美的情形,也就是預期的結果。tcp流一直持續,并沒有斷過了,這印證了之前的推論和實際情況之間是等價的。也就是說應用層只有盡快的處理完數據才可以流暢。這樣一個TCP流控就展現在面前:
今天和某君討論HTTP的問題,由于某君是裸奔的所以它不存在郵箱的問題。這樣就有點麻煩了,得使用底層丟上來的BUF,結果他又忘記了在APP程序中是free掉內存,最終WEB刷新幾下就死翹翹聊。如果這里采用郵箱就不會出現內存泄露這樣的情況,如下:
/* copy the contents of the received buffer into
the supplied memory pointer mem */
netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset);
系統會自動的吧BUF釋放掉并把數據COPY到應用層里面,這樣就實現了絕對的分層!這才是絕對的分層。否則就是偽分層的。應用層還是脫離不開底層的。這也是覆蓋OS和不覆蓋OS的區別之一吧。
但是使用OS時有代價的,要犧牲更多的內存和時間性。比無OS系統響應時間更慢,這是一定的。也是看應用而選擇的特殊考量。