一、連接建立
當兩台計算機建立TCP連接時,需要進行三次握手。首先客戶端向服務端發送連接請求報文,如果服務端收到了請求報文,會向客戶端發送一個確認報文,表示可以建立連接。客戶端收到確認之後還會向服務器發送一個確認報文,表示連接已經建立。
// TCP連接建立的示例代碼 // 客戶端發送連接請求報文 struct tcp_header request; request.destination_port = SERVER_PORT; request.source_port = CLIENT_PORT; request.sync = 1; // 同步位設置為1 send_tcp_packet(request); // 服務端發送確認報文 struct tcp_header response; response.source_port = SERVER_PORT; response.destination_port = CLIENT_PORT; response.ack = 1; // 確認位設置為1 response.acknowledgment_number = request.sequence_number + 1; send_tcp_packet(response); // 客戶端發送確認報文 struct tcp_header confirm; confirm.source_port = CLIENT_PORT; confirm.destination_port = SERVER_PORT; confirm.ack = 1; // 確認位設置為1 confirm.acknowledgment_number = response.sequence_number + 1; send_tcp_packet(confirm);
二、數據傳輸
在TCP連接建立之後,數據傳輸分為兩個部分:發送方將數據拆分成多個報文段(segment),每個報文段都有一個序號和確認號,表示該報文段所包含的數據在整個數據流中的位置,接收方接收到報文段後需要按序號重新組裝成完整的數據。
當發送方發送了一個報文段之後,會等待接收方發送確認消息,表示已經成功接收到數據。如果沒有收到確認消息,說明數據包丟失,發送方會重新發送該數據包,接收方收到重發的數據包後會判斷該數據包是否已經收到過,如果收到過就可以丟棄,否則就可以重新組裝成完整的數據。
// TCP數據傳輸的示例代碼 // 發送方代碼 struct tcp_header segment; segment.source_port = CLIENT_PORT; segment.destination_port = SERVER_PORT; segment.sequence_number = send_base; // 發送基準序號 segment.acknowledgment_number = receive_base; // 確認基準序號 while (not_all_sent) { // 發送所有數據 if (next_byte_to_send receive_base) { // 接收到了缺失的數據 send_ack(receive_base); // 發送確認消息 } else { // 接收到了已經接收過的數據 send_ack(receive_base); // 發送確認消息 }
三、流量控制
TCP連接中的每一方都有一個緩存區,可以存儲已經接收到的數據或者等待發送的數據。為了防止發送方發送過多數據導致接收方無法及時處理,TCP使用了滑動窗口的技術進行流量控制。發送方不可以發送超出窗口大小的數據,接收方需要在處理完窗口內的數據之後向發送方發送確認消息,告知發送方可以發送更多的數據。
// TCP流量控制的示例代碼 // 發送方代碼 struct tcp_header segment; segment.source_port = CLIENT_PORT; segment.destination_port = SERVER_PORT; segment.sequence_number = send_base; // 發送基準序號 segment.acknowledgment_number = receive_base; // 確認基準序號 while (not_all_sent) { if (next_byte_to_send = receive_base && received_segment.sequence_number < receive_base + receive_window) { // 接收窗口內的數據 append_data(received_segment.payload); receive_base = received_segment.sequence_number + received_segment.payload.length(); receive_window = get_receive_window_size(); send_ack(receive_base); // 發送確認消息 } else { // 接收窗口外的數據 send_ack(receive_base); // 發送確認消息 }
四、擁塞控制
TCP使用了四種擁塞控制算法,分別是慢開始(slow start)、擁塞避免(congestion avoidance)、快速重傳(fast retransmit)、快速恢復(fast recovery)。
慢開始是指在連接建立時,發送方先以指數級別增加發送窗口的大小,直到達到某個閾值,然後再以線性級別增長發送窗口。如果在發送數據的過程中出現了亂序或者丟失的數據包,就需要採用快速重傳和快速恢復的技術,快速重傳就是在連續收到三個重複的確認消息之後立即重傳數據包,快速恢復是在重傳數據包之後將發送窗口減半然後進行擁塞避免。
// TCP擁塞控制的示例代碼 // 發送方代碼 struct tcp_header segment; segment.source_port = CLIENT_PORT; segment.destination_port = SERVER_PORT; segment.sequence_number = send_base; // 發送基準序號 segment.acknowledgment_number = receive_base; // 確認基準序號 int cwnd = 1; // 初始發送窗口大小為1 while (not_all_sent) { if (next_byte_to_send = 3) { // 收到三個重複確認消息,觸發快速重傳和快速恢復 resend_segment(); cwnd /= 2; receive_window = get_receive_window_size(); cwnd = cwnd + 1; } else if (next_byte_to_send - send_base == cwnd) { // 發送窗口滿了,進入擁塞避免狀態 cwnd ++; } } // 接收方代碼 struct tcp_header received_segment; received_segment = wait_for_segment(); if (received_segment.sequence_number >= receive_base && received_segment.sequence_number send_base) { // 收到新的確認消息,更新發送窗口大小 cwnd = min(received_segment.acknowledgment_number - send_base, cwnd * 2); send_base = received_segment.acknowledgment_number; }
原創文章,作者:RXQNS,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/372088.html