TCP 用戶端#

import "net"

func main() {
    // 建立連線
    conn, err := net.Dial("tcp", "example.com:80")
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    // 傳送請求
    fmt.Fprintf(conn, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")

    // 讀取回應
    response, _ := io.ReadAll(conn)
    fmt.Println(string(response))
}

TCP 伺服器#

func main() {
    // 監聽埠口
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        log.Fatal(err)
    }
    defer listener.Close()

    fmt.Println("伺服器啟動於 :8080")

    for {
        // 接受連線
        conn, err := listener.Accept()
        if err != nil {
            log.Println("Accept error:", err)
            continue
        }

        // 處理連線(併發)
        go handleConnection(conn)
    }
}

func handleConnection(conn net.Conn) {
    defer conn.Close()

    reader := bufio.NewReader(conn)
    for {
        message, err := reader.ReadString('\n')
        if err != nil {
            return
        }
        fmt.Printf("收到: %s", message)
        conn.Write([]byte("收到訊息\n"))
    }
}

設定逾時#

// 連線逾時
conn, err := net.DialTimeout("tcp", "example.com:80", 5*time.Second)

// 讀寫逾時
conn.SetDeadline(time.Now().Add(10 * time.Second))      // 同時設定
conn.SetReadDeadline(time.Now().Add(5 * time.Second))   // 讀取逾時
conn.SetWriteDeadline(time.Now().Add(5 * time.Second))  // 寫入逾時

在生產環境中,務必設定逾時。沒有逾時的網路操作可能導致 goroutine 永久阻塞。

UDP 通訊#

// UDP 用戶端
conn, _ := net.Dial("udp", "example.com:53")
defer conn.Close()
conn.Write([]byte("hello"))

// UDP 伺服器
addr := net.UDPAddr{Port: 8080}
conn, _ := net.ListenUDP("udp", &addr)
defer conn.Close()

buf := make([]byte, 1024)
n, remoteAddr, _ := conn.ReadFromUDP(buf)
fmt.Printf("收到來自 %s: %s\n", remoteAddr, buf[:n])
HTTP 伺服器範例
import "net/http"

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
    })

    http.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{
            "status": "ok",
        })
    })

    log.Fatal(http.ListenAndServe(":8080", nil))
}

Context 與網路操作#

import "context"

func fetchData(ctx context.Context, url string) ([]byte, error) {
    req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    return io.ReadAll(resp.Body)
}

func main() {
    // 建立帶逾時的 context
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    data, err := fetchData(ctx, "https://example.com/api")
    if err != nil {
        if ctx.Err() == context.DeadlineExceeded {
            log.Println("請求逾時")
        }
        return
    }

    fmt.Println(string(data))
}

網路操作中使用 context.Context 是最佳實務:

  1. 可以設定逾時與取消
  2. 可以傳遞請求範圍的值
  3. 可以優雅地終止整個請求鏈