1. 程式人生 > >TCP的流量控制機制與滑動視窗

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三路握手中, 可以看到這個值)