Golang進階——TCP網路程式設計詳解
介紹
Golang是谷歌設計開發的語言,在Golang的設計之初就把高併發的性能作為Golang的主要特性之一,也是面向大規模後端服務程式。在伺服器端網路通信是必不可少的也是至關重要的一部分。
這裡簡單介紹一下TCP。TCP(Transmission Control Protocol)傳輸控制協議,是一種連線導向的、可靠的、基於位元組流的傳輸層通信協議,也叫做可靠的傳輸協議。屬於OSI七層模型中的傳輸層協定。相比可靠的就會有不可靠的——UDP(User Datagram Protocol)使用者資料包通訊協定,也叫做不可靠的傳輸協議。這裡的可靠和不可靠只是它們的側重點不同。TCP強調資料的完整性,UDP注重資料的即時行。
模型
言歸正傳,今天主要介紹如何使用Go語言進行TCP socket程式設計。目前主流web server一般均採用的都是”Non-Block + I/O多工”。不過I/O多工使用起來依舊很複雜,以至於後續出現了許多高性能的I/O多工框架, 比如libevent、libev、libuv等大大降低了開發的成本。不過Go的設計者似乎認為I/O多工的這種通過回檔機制割裂控制流 的方式還是很複雜,
雖然用戶層眼中看到的goroutine中的“block socket”,實際上是通過Go runtime中的netpoller通過Non-block socket + I/O多工機制“模擬”出來的,
TCP連接建立
TCP Socket的連接的建立需要經歷用戶端和服務端的三次握手的過程。三次握手大致流程如下:
第一次
第一次握手:建立連接時,用戶端發送syn包(syn=j)到伺服器,並進入SYN_SENT狀態,等待伺服器確認;SYN:同步序列編號(Synchronize Sequence Numbers)。
第二次
第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),
第三次
第三次握手:用戶端收到伺服器的SYN+ACK包,向伺服器發送確認包ACK(ack=k+1),此包發送完畢,用戶端和伺服器進入ESTABLISHED(TCP連接成功)狀態,完成三次握手。
完成三次握手,用戶端與伺服器開始傳送資料
連接建立過程中,服務端是一個標準的Listen + Accept的結構(可參考上面的代碼),而在用戶端Go語言使用net.Dial()或net.DialTimeout()進行連接建立
阻塞Dial:
超時機制的Dial:
Socket通訊端讀寫
連接建立起來後,
TCPConn內嵌了一個unexported類型:conn,因此TCPConn”繼承”了conn的Read和Write方法,後續通過Dial返回值調用的Write和Read方法均是net.conn的方法:
基於goroutine的網路架構模型,存在在不同goroutine間共用conn的情況,那麼conn的讀寫是否是goroutine safe的呢?在深入這個問題之前,我們先從應用意義上來看read操作和write操作的goroutine-safe必要性。對於read操作而言,由於TCP是面向位元組流,conn.Read無法正確區分資料的業務邊界,因此多個goroutine對同一個conn進行read的意義不大,goroutine讀到不完整的業務包反倒是增加了業務處理的難度。對與Write操作而言,倒是有多個goroutine併發寫的情況。每次Write操作都是受lock保護,直到此次資料全部write完。因此在應用層面,要想保證多個goroutine在一個conn上write操作的Safe,需要一次write完整寫入一個“業務包”;一旦將業務包的寫入拆分為多次write,那就無法保證某個Goroutine的某“業務包”資料在conn發送的連續性
基於goroutine的網路架構模型,存在在不同goroutine間共用conn的情況,那麼conn的讀寫是否是goroutine safe的呢?在深入這個問題之前,我們先從應用意義上來看read操作和write操作的goroutine-safe必要性。對於read操作而言,由於TCP是面向位元組流,conn.Read無法正確區分資料的業務邊界,因此多個goroutine對同一個conn進行read的意義不大,goroutine讀到不完整的業務包反倒是增加了業務處理的難度。對與Write操作而言,倒是有多個goroutine併發寫的情況。每次Write操作都是受lock保護,直到此次資料全部write完。因此在應用層面,要想保證多個goroutine在一個conn上write操作的Safe,需要一次write完整寫入一個“業務包”;一旦將業務包的寫入拆分為多次write,那就無法保證某個Goroutine的某“業務包”資料在conn發送的連續性