TCP提供了一種面向連接的、可靠的字節流服務。面向連接比較好理解,就是連接雙方在通信前需要預先建立一條連接,這猶如實際生活中的打電話。助於可靠性,TCP協議中涉及了諸多規則來保障通信鏈路的可靠性,總結起來,主要有以下幾點:
(1)應用數據分割成TCP認爲最適合發送的數據塊。這部分是通過“MSS”(最大數據包長度)選項來控制的,通常這種機制也被稱爲一種協商機制,MSS規定了TCP傳往另一端的最大數據塊的長度。值得注意的是,MSS只能出現在SYN報文段中,若一方不接收來自另一方的MSS值,則MSS就定爲536字節。一般來講,在不出現分段的情況下,MSS值還是越大越好,這樣可以提高網絡的利用率。
(2)重傳機制。設置定時器,等待確認包。
(3)對首部和數據進行校驗。
(4)TCP對收到的數據進行排序,然後交給應用層。
(5)TCP的接收端丟棄重複的數據。
(6)TCP還提供流量控制。
TCP報文:
(1)TCP封裝數據的格式:
(2)TCP首部的格式:
TCP首部報文格式的說明:
(1)每個TCP段都包括源端和目的端的端口號,用於尋找發送端和接收端的應用進程。這兩個值加上IP首部的源端IP地址和目的端IP地址唯一確定一個TCP連接。
(2)序號用來標識從TCP發送端向接收端發送的數據字節流,它表示在這個報文段中的第一個數據字節。如果將字節流看作在兩個應用程序間的單向流動,則TCP用序號對每個字節進行計數。
(3)當建立一個新連接時,SYN標誌變1。序號字段包含由這個主機選擇的該連接的初始序號ISN,該主機要發送數據的第一個字節的序號爲這個ISN加1,因爲SYN標誌使用了一個序號。
(4)既然每個被傳輸的字節都被計數,確認序號包含發送確認的一端所期望收到的下一個序號。因此,確認序號應當時上次已成功收到數據字節序號加1。只有ACK標誌爲1時確認序號字段纔有效。
(5)發送ACK無需任何代價,因爲32位的確認序號字段和ACK標誌一樣,總是TCP首部的一部分。因此一旦一個連接建立起來,這個字段總是被設置,ACK標誌也總是被設置爲1。
(6)TCP爲應用層提供全雙工的服務。因此,連接的每一端必須保持每個方向上的傳輸數據序號。
(7)TCP可以表述爲一個沒有選擇確認或否認的華東窗口協議。因此TCP首部中的確認序號表示發送方已成功收到字節,但還不包含確認序號所指的字節。當前還無法對數據流中選定的部分進行確認。
(8)首部長度需要設置,因爲任選字段的長度是可變的。TCP首部最多60個字節。
(9)6個標誌位中的多個可同時設置爲1
URG-緊急指針有效
ACK-確認序號有效
PSH-接收方應儘快將這個報文段交給應用層
RST-重建連接
SYN-同步序號用來發起一個連接
FIN-發送端完成發送任務
(10)TCP的流量控制由連接的每一端通過聲明的窗口大小來提供。窗口大小爲字節數,起始於確認序號字段指明的值,這個值是接收端期望接收的字節數。窗口大小是一個16爲的字段,因而窗口大小最大爲65535字節。
(11)檢驗和覆蓋整個TCP報文端:TCP首部和TCP數據。這是一個強制性的字段,一定是由發送端計算和存儲,並由接收端進行驗證。TCP檢驗和的計算和UDP首部檢驗和的計算一樣,也使用僞首部。
(12)緊急指針是一個正的偏移量,黃蓉序號字段中的值相加表示緊急數據最後一個字節的序號。TCP的緊急方式是發送端向另一端發送緊急數據的一種方式。
(13)最常見的可選字段是最長報文大小MMS,每個連接方通常都在通信的第一個報文段中指明這個選項。它指明本端所能接收的最大長度的報文段。
TCP三次握手與四次揮手全過程:
1、建立連接協議(三次握手)
(1)客戶端發送一個帶SYN標誌的TCP報文到服務器。這是三次握手過程中的報文1。
(2) 服務器端迴應客戶端的,這是三次握手中的第2個報文,這個報文同時帶ACK標誌和SYN標誌。因此它表示對剛纔客戶端SYN報文的迴應;同時又標誌SYN給客戶端,詢問客戶端是否準備好進行數據通訊。
(3) 客戶必須再次迴應服務段一個ACK報文,這是報文段3。
TCP的三次握手可以通過報文來分析:
(1)客戶端向服務器端發起同步請求,服務器側端口固定爲 102,客戶端端口由 socket 隨機產生
(2)服務器端向客戶端響應,同時也向客戶端發起同步請求
(3)客戶端予以確認
2 連接終止協議(四次揮手)
由於TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向的連接。收到一個 FIN只意味着這一方向上沒有數據流動,一個TCP連接在收到一個FIN後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
(1) TCP客戶端發送一個FIN,用來關閉客戶到服務器的數據傳送(報文段4)。
(2) 服務器收到這個FIN,它發回一個ACK,確認序號爲收到的序號加1(報文段5)。和SYN一樣,一個FIN將佔用一個序號。
(3) 服務器關閉客戶端的連接,發送一個FIN給客戶端(報文段6)。
(4) 客戶段發回ACK報文確認,並將確認序號設置爲收到序號加1(報文段7)。
通過Java代碼實現TCP連接三次握手和四次揮手的過程:
package com.zhaoming.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ClientConnect extends Thread
{
//定義一個Client的對象
private Client client;
private Socket socket;
//定義IP和端口號是常量
private static final String IP = "192.168.1.190";
private static final int PORT = 20108;
//聲明str是一個靜態變量,
public static String str = null;
//進行構造(持有另一個類對象的引用)
public ClientConnect(Client client)
{
this.client = client;
}
//啓用線程,處理連接
public void run()
{
try
{
//初始化要連接的socket套接字
socket = new Socket(IP,PORT);
client.getjButton1().setEnabled(false);
}
catch (UnknownHostException e1)
{
e1.printStackTrace();
}
catch (IOException e1)
{
e1.printStackTrace();
}
//從服務器端通過socket讀取信息
BufferedReader br = null;
try
{
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//把讀到的信息顯示到TextArea中
while (true)
{
str = br.readLine();
client.getjTextArea1().append(str + "\n");
//建一個新的文本文檔,用於存儲從服務器讀到的信息
File file = new File("E:/temperatrue.txt");
PrintWriter out = null;
String date = null;
//修改時間顯示的格式
SimpleDateFormat sdf = null;
try
{
//把讀到的信息,寫到到文本文件中存儲起來
out = new PrintWriter(new FileOutputStream(file, true));
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
date = sdf.format(new Date());
out.println(date+"\t"+str);
out.flush();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
finally
{
out.close();
}
}
} catch (IOException e)
{
e.printStackTrace();
}
//進行流關閉處理,先進行判斷,然後再關閉
finally
{
try
{
if(br != null)
{
br.close();
br =null;
}
if(socket != null)
{
socket.close();
socket = null;
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
由於TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向的連接。收到一個 FIN只意味着這一方向上沒有數據流動,一個TCP連接在收到一個FIN後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
TCP協議的連接是全雙工連接,一個TCP連接存在雙向的讀寫通道。
簡單說來是 “先關讀,後關寫”,一共需要四個階段。以客戶機發起關閉連接爲例:
1.服務器讀通道關閉
2.客戶機寫通道關閉
3.客戶機讀通道關閉
4.服務器寫通道關閉
關閉行爲是在發起方數據發送完畢之後,給對方發出一個FIN(finish)數據段。直到接收到對方發送的FIN,且對方收到了接收確認ACK之後,雙方的數據通信完全結束,過程中每次接收都需要返回確認數據段ACK。