網路通訊2:TCP簡單通訊

尹成發表於2018-11-16

#首部格式
圖釋:
這裡寫圖片描述
各個段位說明:

  • 源埠和目的埠:各佔 2 位元組.埠是傳輸層與應用層的服務介面.傳輸層的複用和分用功能都要通過埠才能實現
  • 序號:佔 4 位元組.TCP 連線中傳送的資料流中的每一個位元組都編上一個序號.序號欄位的值則指的是本報文段所傳送的資料的第一個位元組的序號
  • 確認號:佔 4 位元組,是期望收到對方的下一個報文段的資料的第一個位元組的序號
  • 資料偏移/首部長度:佔 4 位,它指出 TCP 報文段的資料起始處距離 TCP 報文段的起始處有多遠.“資料偏移”的單位是 32位字(以 4 位元組為計算單位)
  • 保留:佔 6 位,保留為今後使用,但目前應置為 0
  • 緊急URG:當 URG=1 時,表明緊急指標欄位有效.它告訴系統此報文段中有緊急資料,應儘快傳送(相當於高優先順序的資料)
  • 確認ACK:只有當 ACK=1 時確認號欄位才有效.當 ACK=0 時,確認號無效
  • PSH(PuSH):接收 TCP 收到 PSH = 1 的報文段,就儘快地交付接收應用程式,而不再等到整個快取都填滿了後再向上交付
  • RST (ReSeT):當 RST=1 時,表明 TCP連線中出現嚴重差錯(如由於主機崩潰或其他原因),必須釋放連線,然後再重新建立運輸連線
  • 同步 SYN:同步 SYN = 1 表示這是一個連線請求或連線接受報文
  • 終止 FIN:用來釋放一個連線.FIN=1 表明此報文段的傳送端的資料已傳送完畢,並要求釋放運輸連線
  • 檢驗和:佔 2 位元組.檢驗和欄位檢驗的範圍包括首部和資料這兩部分.在計算檢驗和時,要在 TCP 報文段的前面加上 12 位元組的偽首部
  • 緊急指標:佔 16 位,指出在本報文段中緊急資料共有多少個位元組(緊急資料放在本報文段資料的最前面)
  • 選項:長度可變.TCP 最初只規定了一種選項,即最大報文段長度 MSS.MSS 告訴對方TCP:“我的快取所能接收的報文段的資料欄位的最大長度是 MSS 個位元組.” [MSS(Maximum Segment Size)是TCP 報文段中的資料欄位的最大長度.資料欄位加上 TCP 首部才等於整個的 TCP 報文段]
  • 填充:這是為了使整個首部長度是 4 位元組的整數倍
  • 其他選項:
    (1).視窗擴大:佔 3 位元組,其中有一個位元組表示移位值 S.新的視窗值等於TCP 首部中的視窗位數增大到(16 + S),相當於把視窗值向左移動 S 位後獲得實際的視窗大小
    (2).時間戳:佔10 位元組,其中最主要的欄位時間戳值欄位(4位元組)和時間戳回送回答欄位(4位元組)
    (3).選擇確認:接收方收到了和前面的位元組流不連續的兩2位元組.如果這些位元組的序號都在接收視窗之內,那麼接收方就先收下這些資料,但要把這些資訊準確地告訴傳送方,使傳送方不要再重複傳送這些已收到的資料
    #資料單位
    TCP 傳送的資料單位協議是 TCP 報文段(segment)
    #特點
    TCP 是面向連線的傳輸層協議 每一條 TCP 連線只能有兩個端點(endpoint),每一條 TCP 連線只能是點對點的(一對一) TCP 提供可靠交付的服務 TCP 提供全雙工通訊 面向位元組流
    #例項
    ###服務端實現
import (
	"fmt"
	"net"
	"os"
)

func CheckErrorS(err error){
	if  err !=nil{
		fmt.Println("網路錯誤",err.Error())
		os.Exit(1)
	}
}

func  Processinfo(conn net.Conn){
	buf :=make([]byte,1024)//開創緩衝區
	defer conn.Close() //關閉連線

	//與客戶端源源不斷地IO
	for{
		n,err:=conn.Read(buf) //讀取資料
		if err !=nil{
			break
		}

		if n !=0{
			msg := string(buf[:n])
			fmt.Println("收到訊息",msg)
			conn.Write([]byte("已閱:"+msg))

			if msg=="分手吧"{
				break
			}
		}
	}

}

func main() {
	//建立TCP伺服器
	listener,err:=net.Listen("tcp","127.0.0.1:8898")
	defer listener.Close() //關閉網路
	CheckErrorS(err)

	//迴圈接收,來者不拒
	for  {
		//接入一個客戶端
		conn,err:= listener.Accept() //新的客戶端連線
		CheckErrorS(err)

		//為每一個客戶端開一條獨立的協程與其IO
		go  Processinfo(conn)
	}


}

###客戶端實現

import (
	"fmt"
	"net"
	"os"
	"bufio"
)

func CheckErrorC(err error){
	if  err !=nil{
		fmt.Println("網路錯誤",err.Error())
		os.Exit(1)
	}
}

func main() {
	conn,err :=net.Dial("tcp","127.0.0.1:8898")//建立TCP伺服器
	defer conn.Close() //延遲關閉網路連線
	CheckErrorC(err)//檢查錯誤

	//建立一個黑視窗(標準輸入)的讀取器
	reader := bufio.NewReader(os.Stdin)
	buffer := make([]byte, 1024)

	for{
		lineBytes, _, err := reader.ReadLine()
		CheckErrorC(err)
		conn.Write(lineBytes)
		fmt.Println("傳送訊息")

		/*接收訊息*/
		n, err := conn.Read(buffer)
		CheckErrorC(err)

		msg := string(buffer[:n])
		fmt.Println("收到服務端訊息:",msg)
	}


}

學院Go語言視訊主頁
https://edu.csdn.net/lecturer/1928

[清華團隊帶你實戰區塊鏈開發]
(https://ke.qq.com/course/344443?tuin=3d17195d)
掃碼獲取海量視訊及原始碼 QQ群:721929980
在這裡插入圖片描述

相關文章