1. 程式人生 > 其它 >Go Net包的一些使用

Go Net包的一些使用

技術標籤:計算機網路

Golang net包

最近在專案日誌報警中,經常看到"broken pipe"這個報錯,經過詢問負責基礎架構的同事,是server正在處理的時候client主動關閉TCP連線導致的,可以忽略;於是我們的做法是,將這個報警項新增進了白名單。但本著刨根問底的心態,我自己按照網上的文章也嘗試本地復現了一下這個報錯。

1 Conn

Conn是一個基本的介面型別,以資料流為嚮導的網路連線接。注意是介面型別,不需要我們來手動構造實現Conn介面,生成滿足Conn介面的函式。

func Dial(network, address string) (Conn, error) // 用來建立TCP連線
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
func FileConn(f *os.File) (c Conn, err error)
func Pipe() (Conn, Conn)

服務端通過Accept()方法來接受Listen到的一個TCP連線;

客戶端通過Dial()方法來請求建立一個TCP連線。

在連線建立完成後,由於TCP是全雙工通訊的,所以兩端都可以使用conn.Read() conn.Write()函式來讀取內容到buffer中。

2 測試TCP建立連線和通訊的過程

為了方便觀察,把Server做成只會讀,Client只會寫。

服務端程式碼
func recvConnectionMsg(connection net.Conn) {
	buffer := make([]byte, 50)
	defer connection.Close()
	for {
		n,
err := connection.Read(buffer) if err != nil { // 一直讀到連線關閉 fmt.Println("connection closed") return } fmt.Println("recv msg: ", string(buffer[0:n])) } } func main() { listenSock, err := net.Listen("tcp", "localhost:10000") if err != nil { fmt.Println
("error: ", err) os.Exit(1) } defer listenSock.Close() for { newConn, err := listenSock.Accept() // 獲取到一個流式的Listener if err != nil { continue } go recvConnectionMsg(newConn) } }
客戶端程式碼
func main() {
	conn, err := net.Dial("tcp", "127.0.0.1:10000")
	if err != nil {
		fmt.Println("Error: ", err)
		os.Exit(1)
	}
	defer conn.Close()
	for {
		time.Sleep(100 * time.Millisecond)
    // 向TCP快取中寫入內容
		n, err := conn.Write([]byte("hello world")) 
		if err != nil {
			fmt.Printf("Error: %s, Index: %d\n", err, n)
		}
	}
}

3 Server異常場景

  • 服務端程序崩潰

    服務端程序崩潰後:

    • 如果client正在進行讀操作,會讀到一個空的buffer;
    • 如果client正在進行write操作,會引發一個panic: broken pipe
  • 服務端關機:

    這裡一般指的是正常關機,系統會向各個程序傳送SIGTERMSIGKILL訊號,server程序會推出,然後關閉相應的檔案描述符,給對應client傳送FIN報文。

  • 服務端重啟

    • 如果客戶端在server shutdown之前沒有傳送資料,client是無法感知server shutdown的;
    • 如果客戶端在重啟後繼續傳送資料,是無法使用原有的套接字傳送訊息的。