TCP的流量控制機制與滑動視窗
一、滑動視窗實現
所謂的流量控制, 就是告誡對方傳送速率不要太快, 要讓接收來來得及接收資料。
形容如下;
甲向乙傳送資料。經過TCP三握手連線以後, 當乙告訴甲:“我的接受視窗rwnd = 400”(這裡rwnd表示receiver window的意思)。所以,傳送方的傳送視窗不能超過接收方給出的接受視窗的數值。而TCP視窗的單位是位元組, 而不是報文段。
例子解釋如下:
假設每個報文的長度為100位元組, 報文段的序號初始值設定為1。
1、主機乙對該傳輸過程進行了三次流量控制。(按道理說,seq 1 和 sql 101傳送後主機乙放回的rwnd = 200, 但是在該應答中返回的是300, 那可能是因為主機B呼叫recv函式讀取了100位元組, 後續若遇到此類情況, 皆是如此處理)。
2、seq因為沒有傳送成功,第一次流量控制ack= 201,rwnd = 300; 在經過三次傳送過, seq = 201, 再次傳送屬於超時重傳。
3、最後返回的ACK應答中, rwnd = 0, 表示甲主機不能再向乙主機傳輸資料了。 等待乙主機的程序讀取資料。
4、如果乙主機的快取空間又空閒了。 那麼乙主機將會向甲主機發送ACK = 1, rwnd = 400的應答, 如果該應答在傳輸的過程中丟失了。甲主機將會一直等待乙主機的非零視窗通知, 而乙主機也一直在等待甲主機發送的資料,在沒有其他措施的情況下, 這種相互等待將會一直死鎖下去
由4小點我們引入了一個新的措施, 叫做持續及時器:
*持續計時器:
TCP連線的任何一段, 如果收到了0視窗通知, 那麼將會啟動持續計時器。當持續計時器的時間到了後, 該端將會發送一個零視窗的探測報文段(攜帶一個位元組的資料),如果還是收到了零視窗通知, 將繼續重新啟動計時器, 重複該步驟, 直到打破死鎖位置。
二、滑動視窗機制
由上圖所示, 甲主機的傳送視窗為20, 乙主機的接受視窗是20.
1)、甲主機開始接收到了來自乙主機ack = 29, win = 20的視窗通知。 那麼甲主機就傳送序號為[29,49)裡面的資料, 理想乙主機希望接受[29,49)序號的資料。
2)、可能因為序號為31的位元組資料丟失、又或者是滯留在網路當中, 導致資料不能完全接受, 那麼乙主機發送ack = 31, win = 20的通知視窗給對端
3)、甲主機有接受ack = 31, win = 20,的通知視窗。 接受並且傳送序號為[31,51)裡面的資料, 又因為可能序號為35的位元組丟失重複以上操作
三、試驗分析
通過客戶端不斷向服務寫入資料, 但是伺服器端並不讀取任何資料進入睡眠狀態。
伺服器程式程式碼片段:
for(;;){
pause();
n = read(confd, buf, MAXLINE);
printf("n = %d\n", n);
if(n < 0){
if(errno == EINTR) continue;
else{
fprintf(stderr, "read error \n");
break;
}
}
else if(n == 0) break;
else{
buf[n] = 0;
write(confd, buf, n);
}
}
客戶端程式程式碼片段
for(;;){
write(sockfd, sendbuf, MAXLENGTH);
usleep(5);
}
抓包結果:
四、總結
1、瞭解滑動視窗的含義。
2、怎麼通過發動視窗來控制流量的(即工作流程)
3、拓展:在三中的試驗結果win = 295 275, 遠小於接受緩衝區的空閒快取區大小值(提示:wscale, 視窗大小偏移因子, 在TCP三路握手中, 可以看到這個值)