Go语言中的网络编程:从TCP到HTTP

张开发
2026/4/16 9:53:38 15 分钟阅读

分享文章

Go语言中的网络编程:从TCP到HTTP
Go语言中的网络编程从TCP到HTTP引言网络编程是现代应用开发中的核心组成部分而Go语言凭借其简洁的语法、强大的并发模型和丰富的标准库成为了网络编程的理想选择。本文将从底层的TCP/IP协议开始逐步深入到HTTP等应用层协议全面介绍Go语言中的网络编程技术。1. 底层网络编程TCP和UDP1.1 TCP服务器和客户端Go语言的net包提供了丰富的网络编程接口使得创建TCP服务器和客户端变得非常简单。TCP服务器示例package main import ( bufio fmt log net ) func handleConnection(conn net.Conn) { defer conn.Close() reader : bufio.NewReader(conn) for { message, err : reader.ReadString(\n) if err ! nil { log.Println(Error reading:, err) break } fmt.Printf(Received: %s, message) // 回显消息 _, err conn.Write([]byte(Server: message)) if err ! nil { log.Println(Error writing:, err) break } } } func main() { listener, err : net.Listen(tcp, :8080) if err ! nil { log.Fatal(Error starting server:, err) } defer listener.Close() fmt.Println(Server started on port 8080) for { conn, err : listener.Accept() if err ! nil { log.Println(Error accepting connection:, err) continue } go handleConnection(conn) } }TCP客户端示例package main import ( bufio fmt log net os ) func main() { conn, err : net.Dial(tcp, localhost:8080) if err ! nil { log.Fatal(Error connecting:, err) } defer conn.Close() scanner : bufio.NewScanner(os.Stdin) for scanner.Scan() { message : scanner.Text() \n _, err : conn.Write([]byte(message)) if err ! nil { log.Println(Error writing:, err) break } response, err : bufio.NewReader(conn).ReadString(\n) if err ! nil { log.Println(Error reading:, err) break } fmt.Print(Response: , response) } }1.2 UDP服务器和客户端UDP是一种无连接的协议适用于对实时性要求较高但对可靠性要求较低的场景如视频流、游戏等。UDP服务器示例package main import ( fmt log net ) func main() { addr, err : net.ResolveUDPAddr(udp, :8080) if err ! nil { log.Fatal(Error resolving address:, err) } conn, err : net.ListenUDP(udp, addr) if err ! nil { log.Fatal(Error listening:, err) } defer conn.Close() fmt.Println(UDP server started on port 8080) buffer : make([]byte, 1024) for { n, clientAddr, err : conn.ReadFromUDP(buffer) if err ! nil { log.Println(Error reading:, err) continue } message : string(buffer[:n]) fmt.Printf(Received from %s: %s, clientAddr, message) // 发送响应 response : Server: message _, err conn.WriteToUDP([]byte(response), clientAddr) if err ! nil { log.Println(Error writing:, err) } } }UDP客户端示例package main import ( fmt log net os ) func main() { addr, err : net.ResolveUDPAddr(udp, localhost:8080) if err ! nil { log.Fatal(Error resolving address:, err) } conn, err : net.DialUDP(udp, nil, addr) if err ! nil { log.Fatal(Error connecting:, err) } defer conn.Close() message : Hello from UDP client! _, err conn.Write([]byte(message)) if err ! nil { log.Println(Error writing:, err) return } buffer : make([]byte, 1024) n, _, err : conn.ReadFromUDP(buffer) if err ! nil { log.Println(Error reading:, err) return } response : string(buffer[:n]) fmt.Println(Response:, response) }2. HTTP编程2.1 标准库HTTP服务器Go语言的标准库net/http提供了强大的HTTP服务器和客户端功能。基本HTTP服务器示例package main import ( fmt log net/http ) func helloHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, Hello, World!) } func userHandler(w http.ResponseWriter, r *http.Request) { userID : r.URL.Path[len(/user/):] fmt.Fprintf(w, Hello, User %s!) } func main() { http.HandleFunc(/, helloHandler) http.HandleFunc(/user/, userHandler) fmt.Println(Server started on port 8080) log.Fatal(http.ListenAndServe(:8080, nil)) }2.2 HTTP客户端package main import ( fmt io log net/http ) func main() { resp, err : http.Get(https://api.github.com/users/golang) if err ! nil { log.Fatal(Error making request:, err) } defer resp.Body.Close() body, err : io.ReadAll(resp.Body) if err ! nil { log.Fatal(Error reading response:, err) } fmt.Printf(Status: %s\n, resp.Status) fmt.Printf(Body: %s\n, body) }2.3 自定义HTTP服务器对于更复杂的场景我们可以创建自定义的HTTP服务器package main import ( fmt log net/http time ) func main() { server : http.Server{ Addr: :8080, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, Hello, Custom Server!) }), ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, } fmt.Println(Custom server started on port 8080) log.Fatal(server.ListenAndServe()) }3. WebSocket编程WebSocket是一种在单个TCP连接上进行全双工通信的协议适用于实时应用如聊天、游戏等。3.1 WebSocket服务器package main import ( fmt log net/http github.com/gorilla/websocket ) var upgrader websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true // 允许所有来源生产环境中应该限制 }, } func echoHandler(w http.ResponseWriter, r *http.Request) { conn, err : upgrader.Upgrade(w, r, nil) if err ! nil { log.Println(Error upgrading:, err) return } defer conn.Close() for { messageType, message, err : conn.ReadMessage() if err ! nil { log.Println(Error reading:, err) break } log.Printf(Received: %s, message) err conn.WriteMessage(messageType, message) if err ! nil { log.Println(Error writing:, err) break } } } func main() { http.HandleFunc(/ws, echoHandler) fmt.Println(WebSocket server started on port 8080) log.Fatal(http.ListenAndServe(:8080, nil)) }3.2 WebSocket客户端package main import ( fmt log net/url github.com/gorilla/websocket ) func main() { u : url.URL{Scheme: ws, Host: localhost:8080, Path: /ws} conn, _, err : websocket.DefaultDialer.Dial(u.String(), nil) if err ! nil { log.Fatal(Error connecting:, err) } defer conn.Close() message : Hello from WebSocket client! err conn.WriteMessage(websocket.TextMessage, []byte(message)) if err ! nil { log.Println(Error writing:, err) return } messageType, response, err : conn.ReadMessage() if err ! nil { log.Println(Error reading:, err) return } fmt.Printf(Received message type: %d\n, messageType) fmt.Printf(Received: %s\n, response) }4. 网络编程最佳实践4.1 错误处理网络编程中错误处理尤为重要func handleConnection(conn net.Conn) { defer conn.Close() // 读取数据 buffer : make([]byte, 1024) n, err : conn.Read(buffer) if err ! nil { if err io.EOF { log.Println(Connection closed by client) } else { log.Println(Error reading:, err) } return } // 处理数据... }4.2 超时设置设置适当的超时可以防止连接挂起// TCP连接超时 conn, err : net.DialTimeout(tcp, example.com:80, 5*time.Second) if err ! nil { log.Fatal(Error connecting:, err) } // HTTP请求超时 client : http.Client{ Timeout: 10 * time.Second, } resp, err : client.Get(https://example.com)4.3 连接池对于频繁的网络请求使用连接池可以提高性能// HTTP连接池 client : http.Client{ Transport: http.Transport{ MaxIdleConns: 100, MaxIdleConnsPerHost: 100, IdleConnTimeout: 90 * time.Second, }, }4.4 并发处理Go语言的并发特性非常适合网络编程func main() { listener, err : net.Listen(tcp, :8080) if err ! nil { log.Fatal(Error starting server:, err) } defer listener.Close() for { conn, err : listener.Accept() if err ! nil { log.Println(Error accepting connection:, err) continue } go handleConnection(conn) // 每个连接一个goroutine } }5. 高级网络编程5.1 TLS/SSL使用TLS/SSL可以加密网络通信// TLS服务器 cert, err : tls.LoadX509KeyPair(cert.pem, key.pem) if err ! nil { log.Fatal(Error loading certificates:, err) } config : tls.Config{Certificates: []tls.Certificate{cert}} listener, err : tls.Listen(tcp, :443, config) if err ! nil { log.Fatal(Error starting TLS server:, err) }5.2 代理和负载均衡Go语言可以轻松实现代理和负载均衡func proxyHandler(w http.ResponseWriter, r *http.Request) { director : func(req *http.Request) { req.URL.Scheme http req.URL.Host backend-server:8080 } proxy : httputil.ReverseProxy{Director: director} proxy.ServeHTTP(w, r) }6. 实际应用案例6.1 简单的HTTP API服务器package main import ( encoding/json log net/http strconv ) type User struct { ID int json:id Name string json:name Age int json:age } var users []User{ {ID: 1, Name: Alice, Age: 30}, {ID: 2, Name: Bob, Age: 25}, {ID: 3, Name: Charlie, Age: 35}, } func getUsersHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set(Content-Type, application/json) json.NewEncoder(w).Encode(users) } func getUserHandler(w http.ResponseWriter, r *http.Request) { idStr : r.URL.Path[len(/users/):] id, err : strconv.Atoi(idStr) if err ! nil { http.Error(w, Invalid user ID, http.StatusBadRequest) return } for _, user : range users { if user.ID id { w.Header().Set(Content-Type, application/json) json.NewEncoder(w).Encode(user) return } } http.Error(w, User not found, http.StatusNotFound) } func main() { http.HandleFunc(/users, getUsersHandler) http.HandleFunc(/users/, getUserHandler) log.Println(Server started on port 8080) log.Fatal(http.ListenAndServe(:8080, nil)) }6.2 实时聊天应用结合WebSocket和并发特性我们可以构建一个简单的实时聊天应用package main import ( log net/http github.com/gorilla/websocket ) var upgrader websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, } var clients make(map[*websocket.Conn]bool) var broadcast make(chan []byte) func handleWebSocket(w http.ResponseWriter, r *http.Request) { conn, err : upgrader.Upgrade(w, r, nil) if err ! nil { log.Println(Error upgrading:, err) return } defer conn.Close() clients[conn] true for { _, message, err : conn.ReadMessage() if err ! nil { log.Println(Error reading:, err) delete(clients, conn) break } broadcast - message } } func broadcastMessages() { for { message : -broadcast for client : range clients { err : client.WriteMessage(websocket.TextMessage, message) if err ! nil { log.Println(Error writing:, err) client.Close() delete(clients, client) } } } } func main() { go broadcastMessages() http.HandleFunc(/ws, handleWebSocket) http.HandleFunc(/, func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, index.html) }) log.Println(Chat server started on port 8080) log.Fatal(http.ListenAndServe(:8080, nil)) }7. 总结Go语言的网络编程能力非常强大从底层的TCP/UDP到高层的HTTP和WebSocket都有简洁而强大的API支持。通过本文的介绍我们了解了如何使用Go语言创建TCP和UDP服务器/客户端如何使用标准库net/http构建HTTP服务器和客户端如何使用WebSocket实现实时通信网络编程的最佳实践如错误处理

更多文章