這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
一、概述
上一篇實現了一個server和client通訊,完成了小寫轉大寫的功能,但是是一個單任務式的響應:用戶端發送串連接收響應,程式結束;服務端則接收資料響應資料也結束!就實際需要而言,並沒有很大的用處,所以現在我們就給用戶端和服務端添加上並發功能。
邏輯其實很簡單,就是利用golang的gorutine,一旦來新的串連,就開啟一個gorutine去處理,然後響應,直到用戶端關閉串連。
二、服務端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
package main import ( "net" "fmt" "strings" ) func handle(conn net.Conn){ defer conn.Close() //關閉串連 fmt.Println("Connect :", conn.RemoteAddr()) for { //只要用戶端沒有中斷連線,一直保持串連,讀取資料 data := make([]byte, 2048) n, err := conn.Read(data) //資料長度為0表示用戶端串連已經斷開 if n == 0{ fmt.Printf("%s has disconnect", conn.RemoteAddr()) break } if err != nil{ fmt.Println(err) continue } fmt.Printf("Receive data [%s] from [%s]", string(data[:n]), conn.RemoteAddr()) //轉大寫 rspData := strings.ToUpper(string(data[:n])) _, err = conn.Write([]byte(rspData)) if err != nil{ fmt.Println(err) continue } } } func main(){ listener, err := net.Listen("tcp", ":8899") if err != nil{ fmt.Println(err) return } fmt.Println("Start listen localhost:8899") for { //開始迴圈接收用戶端串連 conn, err := listener.Accept() if err != nil{ fmt.Println(err) return } //一旦收到用戶端串連,開啟一個新的gorutine去處理這個串連 go handle(conn) } }
|
三、用戶端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
import ( "net" "fmt" ) func main(){ conn, err := net.Dial("tcp", ":8899") //串連服務端 if err != nil{ fmt.Println(err) return } fmt.Println("Connect to localhost:8899 success") defer conn.Close() for{ //一直迴圈讀入使用者資料,發送到服務端處理 fmt.Print("Please input send data :") var a string fmt.Scan(&a) if a == "exit"{break} //添加一個退出機制,使用者輸入exit,退出 _, err := conn.Write([]byte(a)) if err != nil{ fmt.Println(err) return } data := make([]byte, 2048) n, err := conn.Read(data) if err != nil{ fmt.Println(err) continue } fmt.Println("Response data :", string(data[:n])) } }
|
四、運行
此時,我們開啟一個服務端,開啟兩個用戶端進行測試:
至此,一個完美的多並發服務端就完成了!