1. 程式人生 > >GO語言使用之網路程式設計(TCP程式設計)

GO語言使用之網路程式設計(TCP程式設計)

一、基本介紹

Golang的主要設計目標之一就是面向大規模後端服務程式,網路通訊這塊是服務端 程式必不可少也是至關重要的一部分。
1、 網路程式設計有兩種:
1) TCP socket程式設計,是網路程式設計的主流。之所以叫Tcp socket程式設計,是因為底層是基於Tcp/ip協議的. 比如: QQ聊天
2) b/s結構的http程式設計,我們使用瀏覽器去訪問伺服器時,使用的就是http協議,而http底層依舊是用tcp socket實現的。 比如: 京東商城 【這屬於go web 開發範疇 】
2、協議(tcp/ip)
CP/IP(Transmission Control Protocol/Internet Protocol)的簡寫,中文譯名為傳輸控制協議/因特網互聯協議,又叫網路通訊協議,這個協議是Internet最基本的協議、Internet國際網際網路絡的基礎,簡單地說,就是由網路層的IP協議和傳輸層的TCP協議組成的。
這裡寫圖片描述


3、OSI與Tcp/ip參考模型 (推薦tcp/ip協議3卷)
這裡寫圖片描述
這裡寫圖片描述
4、ip地址
概述:每個internet上的主機和路由器都有一個ip地址,它包括網路號和主機號,ip地址有ipv4(32位)或者ipv6(128位). 可以通過ipconfig 來檢視
這裡寫圖片描述
5、 埠(port)-介紹
我們這裡所指的埠不是指物理意義上的埠,而是特指TCP/IP協議中的埠,是
邏輯意義上的埠。

如果把IP地址比作一間房子,埠就是出入這間房子的門。真正的房子只有幾個
門,但是一個IP地址的埠 可以有65536(即:256×256)個之多!埠是通過端
口號來標記的,埠號只有整數,範圍是從0 到65535(256×256-1)
這裡寫圖片描述

6、埠(port)-分類

  • 0號是保留埠.

  • 1-1024是固定埠(程式設計師不要使用)

    又叫有名埠,即被某些程式固定使用,一般程式設計師不使用.
    22: SSH遠端登入協議 23: telnet使用 21: ftp使用
    25: smtp服務使用 80: iis使用 7: echo服務

  • 1025-65535是動態埠

    這些埠,程式設計師可以使用.

7、埠(port)-使用注意
1) 在計算機(尤其是做伺服器)要儘可能的少開埠
2) 一個埠只能被一個程式監聽
3) 如果使用 netstat –an 可以檢視本機有哪些埠在監聽
4) 可以使用 netstat –anb 來檢視監聽埠的pid,在結合工作管理員關閉不安全的埠

二、 tcp socket程式設計的客戶端和伺服器端

下圖為Golang socket程式設計中客戶端和伺服器的網路分佈
這裡寫圖片描述

三、TCP快速入門案例

1、服務端
服務端的處理流程:

  • 監聽埠 8888
  • 接收客戶端的tcp連結,建立客戶端和伺服器端的連結.
  • 建立goroutine,處理該連結的請求(通常客戶端會通過連結傳送請求包)

    2、客戶端

客戶端的處理流程:

  • 建立與服務端的連結
  • 傳送請求資料[終端],接收伺服器端返回的結果資料
  • 關閉連結

3、簡單的程式示意圖
這裡寫圖片描述

4、伺服器端功能:

  1. 編寫一個伺服器端程式,在8888埠監聽
  2. 可以和多個客戶端建立連結
  3. 連結成功後,客戶端可以傳送資料,伺服器端接受資料,並顯示在終端上.
  4. 先使用telnet 來測試,然後編寫客戶端程式來測試

服務端的程式碼:

package main

import (
    "fmt"
    "log"
    _"io"
    "net"//做網路socket開發時,net包含有網路相關的方法和函式
)

func Server()  {
        // Listen函式建立的服務端
        //tcp : 網路協議
        //192.168.191.1:8888 / :8888 本機IP和埠
        l, err := net.Listen("tcp", "192.168.20.23:8888")
        if err != nil {
            log.Fatal(err)
        }
        defer l.Close()//延時關閉listen
        ////迴圈等待客戶端訪問
        for {

            conn, err := l.Accept()
            if err != nil {
                log.Fatal(err)
            }
            fmt.Printf("訪問客戶端資訊: con=%v 客戶端ip=%v\n", conn, conn.RemoteAddr().String())

            go handleConnection(conn)

            // go func(c net.Conn) {

            //  io.Copy(c, c)

            //  c.Close()
            // }(conn)

        }
}
//服務端處理從客戶端接受的資料
func handleConnection(c net.Conn){  
    defer c.Close()//關閉conn

    for {

        //1. 等待客戶端通過conn傳送資訊
        //2. 如果客戶端沒有wrtie[傳送],那麼協程就阻塞在這裡
        fmt.Printf("伺服器在等待客戶端%s 傳送資訊\n", c.RemoteAddr().String())
        buf := make([]byte, 1024 )
        n, err := c.Read(buf)
        if err != nil {
            log.Fatal(err)
            break
        }

        //3. 顯示客戶端傳送的內容到伺服器的終端
        fmt.Print(string(buf[:n]))
    }
}

func main()  {
    Server()
}

5、客戶端功能:
1. 編寫一個客戶端端程式,能連結到 伺服器端的8888埠
2. 客戶端可以傳送單行資料,然後就退出
3. 能通過終端輸入資料(輸入一行傳送一行), 併發送給伺服器端 []
4. 在終端輸入exit,表示退出程式.

客戶端的程式碼:

package main

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

func Client()  {

    conn, err := net.Dial("tcp", "192.168.20.23:8888")
    if err != nil {
        log.Fatal(err)
    }

    //客戶端可以傳送單行資料,然後就退出
    reader := bufio.NewReader(os.Stdin) //os.Stdin 代表標準輸入[終端]
    for {
        //從終端讀取一行使用者輸入,並準備傳送給伺服器
        line, err := reader.ReadString('\n')
        if err != nil {
            log.Fatal(err)
        }
        line = strings.Trim(line,"\r\n")

        if line == "exit" {
            fmt.Println("使用者退出客戶端")
            break
        }
        //再將line 傳送給 伺服器
        conent, err := conn.Write([]byte(line + "\n"))
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("客戶端傳送了 %d 位元組的資料到服務端\n", conent)
    }
}


func main()  {
    Client()
}