当前位置: 首页 > news >正文

Go语言的网络编程进阶

Go语言的网络编程进阶

网络编程基础

Go语言提供了强大的网络编程支持,包括TCP/IP、UDP、HTTP等协议。本文将介绍Go语言网络编程的进阶概念和技巧,帮助开发者编写更复杂、更高效的网络应用。

TCP服务器和客户端

基本TCP服务器

package main import ( "fmt" "net" "os" ) func handleConnection(conn net.Conn) { defer conn.Close() buffer := make([]byte, 1024) for { n, err := conn.Read(buffer) if err != nil { fmt.Println("Error reading:", err) break } message := string(buffer[:n]) fmt.Printf("Received: %s", message) // 回显消息 _, err = conn.Write([]byte("Echo: " + message)) if err != nil { fmt.Println("Error writing:", err) break } } } func main() { port := "8080" listener, err := net.Listen("tcp", ":"+port) if err != nil { fmt.Println("Error listening:", err) os.Exit(1) } defer listener.Close() fmt.Printf("Server listening on port %s\n", port) for { conn, err := listener.Accept() if err != nil { fmt.Println("Error accepting:", err) continue } go handleConnection(conn) } }

基本TCP客户端

package main import ( "fmt" "net" "os" "bufio" ) func main() { serverAddr := "localhost:8080" conn, err := net.Dial("tcp", serverAddr) if err != nil { fmt.Println("Error connecting:", err) os.Exit(1) } defer conn.Close() fmt.Println("Connected to server") // 读取用户输入并发送到服务器 scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { message := scanner.Text() _, err := conn.Write([]byte(message + "\n")) if err != nil { fmt.Println("Error writing:", err) break } // 读取服务器响应 buffer := make([]byte, 1024) n, err := conn.Read(buffer) if err != nil { fmt.Println("Error reading:", err) break } fmt.Printf("Server response: %s", string(buffer[:n])) } }

UDP服务器和客户端

基本UDP服务器

package main import ( "fmt" "net" "os" ) func main() { port := "8080" addr, err := net.ResolveUDPAddr("udp", ":"+port) if err != nil { fmt.Println("Error resolving address:", err) os.Exit(1) } conn, err := net.ListenUDP("udp", addr) if err != nil { fmt.Println("Error listening:", err) os.Exit(1) } defer conn.Close() fmt.Printf("UDP server listening on port %s\n", port) buffer := make([]byte, 1024) for { n, clientAddr, err := conn.ReadFromUDP(buffer) if err != nil { fmt.Println("Error reading:", err) continue } message := string(buffer[:n]) fmt.Printf("Received from %s: %s", clientAddr, message) // 回显消息 _, err = conn.WriteToUDP([]byte("Echo: " + message), clientAddr) if err != nil { fmt.Println("Error writing:", err) continue } } }

基本UDP客户端

package main import ( "fmt" "net" "os" "bufio" ) func main() { serverAddr := "localhost:8080" addr, err := net.ResolveUDPAddr("udp", serverAddr) if err != nil { fmt.Println("Error resolving address:", err) os.Exit(1) } conn, err := net.DialUDP("udp", nil, addr) if err != nil { fmt.Println("Error connecting:", err) os.Exit(1) } defer conn.Close() fmt.Println("Connected to UDP server") // 读取用户输入并发送到服务器 scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { message := scanner.Text() _, err := conn.Write([]byte(message + "\n")) if err != nil { fmt.Println("Error writing:", err) break } // 读取服务器响应 buffer := make([]byte, 1024) conn.SetReadDeadline(time.Now().Add(2 * time.Second)) n, _, err := conn.ReadFromUDP(buffer) if err != nil { fmt.Println("Error reading:", err) continue } fmt.Printf("Server response: %s", string(buffer[:n])) } }

HTTP服务器进阶

自定义HTTP服务器

package main import ( "fmt" "net/http" "os" ) func helloHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) w.Write([]byte("Hello, HTTP!")) } func statusHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write([]byte(`{"status": "ok", "message": "Server is running"}`)) } func main() { http.HandleFunc("/", helloHandler) http.HandleFunc("/status", statusHandler) port := "8080" fmt.Printf("HTTP server starting on port %s\n", port) if err := http.ListenAndServe(":"+port, nil); err != nil { fmt.Println("Error starting server:", err) os.Exit(1) } }

使用ServeMux

package main import ( "fmt" "net/http" "os" ) func main() { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Home Page")) }) mux.HandleFunc("/about", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("About Page")) }) mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`[{"id": 1, "name": "John"}, {"id": 2, "name": "Jane"}]`)) }) port := "8080" fmt.Printf("HTTP server starting on port %s\n", port) if err := http.ListenAndServe(":"+port, mux); err != nil { fmt.Println("Error starting server:", err) os.Exit(1) } }

网络编程技巧

超时处理

package main import ( "fmt" "net" "os" "time" ) func main() { // TCP连接超时 conn, err := net.DialTimeout("tcp", "localhost:8080", 5*time.Second) if err != nil { fmt.Println("Error connecting:", err) os.Exit(1) } defer conn.Close() // 设置读写超时 conn.SetReadDeadline(time.Now().Add(10 * time.Second)) conn.SetWriteDeadline(time.Now().Add(5 * time.Second)) fmt.Println("Connected with timeout settings") }

连接池

package main import ( "fmt" "net" "sync" "time" ) type ConnectionPool struct { connections chan net.Conn mu sync.Mutex closed bool } func NewConnectionPool(size int, addr string) (*ConnectionPool, error) { pool := &ConnectionPool{ connections: make(chan net.Conn, size), closed: false, } // 初始化连接池 for i := 0; i < size; i++ { conn, err := net.Dial("tcp", addr) if err != nil { // 关闭已创建的连接 for conn := range pool.connections { conn.Close() } return nil, err } pool.connections <- conn } return pool, nil } func (p *ConnectionPool) Get() (net.Conn, error) { p.mu.Lock() if p.closed { p.mu.Unlock() return nil, fmt.Errorf("pool closed") } p.mu.Unlock() select { case conn := <-p.connections: // 检查连接是否有效 conn.SetReadDeadline(time.Now().Add(1 * time.Second)) _, err := conn.Read(make([]byte, 1)) if err != nil { // 连接无效,创建新连接 newConn, err := net.Dial("tcp", conn.RemoteAddr().String()) if err != nil { // 放回无效连接,让调用者处理 p.connections <- conn return nil, err } conn.Close() return newConn, nil } // 连接有效,重置超时 conn.SetReadDeadline(time.Time{}) return conn, nil case <-time.After(5 * time.Second): return nil, fmt.Errorf("timeout waiting for connection") } } func (p *ConnectionPool) Put(conn net.Conn) { p.mu.Lock() defer p.mu.Unlock() if p.closed { conn.Close() return } select { case p.connections <- conn: // 连接已放回池 default: // 池已满,关闭连接 conn.Close() } } func (p *ConnectionPool) Close() { p.mu.Lock() defer p.mu.Unlock() if p.closed { return } p.closed = true close(p.connections) for conn := range p.connections { conn.Close() } } func main() { pool, err := NewConnectionPool(5, "localhost:8080") if err != nil { fmt.Println("Error creating pool:", err) return } defer pool.Close() // 使用连接池 conn, err := pool.Get() if err != nil { fmt.Println("Error getting connection:", err) return } defer pool.Put(conn) // 使用连接... fmt.Println("Got connection from pool") }

示例:聊天服务器

服务器端

package main import ( "fmt" "net" "os" "strings" "sync" ) type Client struct { conn net.Conn name string messages chan string } var ( clients = make(map[*Client]bool) broadcast = make(chan string) register = make(chan *Client) unregister = make(chan *Client) mu sync.Mutex ) func handleClient(client *Client) { defer func() { unregister <- client client.conn.Close() }() // 读取客户端消息 buffer := make([]byte, 1024) for { n, err := client.conn.Read(buffer) if err != nil { break } message := strings.TrimSpace(string(buffer[:n])) if message != "" { broadcast <- fmt.Sprintf("%s: %s", client.name, message) } } } func broadcastMessages() { for { select { case client := <-register: mu.Lock() clients[client] = true mu.Unlock() broadcast <- fmt.Sprintf("%s joined the chat", client.name) case client := <-unregister: mu.Lock() if _, ok := clients[client]; ok { delete(clients, client) close(client.messages) broadcast <- fmt.Sprintf("%s left the chat", client.name) } mu.Unlock() case message := <-broadcast: mu.Lock() for client := range clients { select { case client.messages <- message: default: close(client.messages) delete(clients, client) } } mu.Unlock() } } } func main() { go broadcastMessages() port := "8080" listener, err := net.Listen("tcp", ":"+port) if err != nil { fmt.Println("Error listening:", err) os.Exit(1) } defer listener.Close() fmt.Printf("Chat server starting on port %s\n", port) for { conn, err := listener.Accept() if err != nil { fmt.Println("Error accepting:", err) continue } // 获取客户端名称 conn.Write([]byte("Enter your name: ")) buffer := make([]byte, 1024) n, err := conn.Read(buffer) if err != nil { conn.Close() continue } name := strings.TrimSpace(string(buffer[:n])) if name == "" { conn.Close() continue } // 创建客户端 client := &Client{ conn: conn, name: name, messages: make(chan string, 256), } // 注册客户端 register <- client // 启动客户端处理协程 go handleClient(client) // 启动消息发送协程 go func() { for message := range client.messages { conn.Write([]byte(message + "\n")) } }() } }

客户端

package main import ( "bufio" "fmt" "net" "os" ) func main() { serverAddr := "localhost:8080" conn, err := net.Dial("tcp", serverAddr) if err != nil { fmt.Println("Error connecting:", err) os.Exit(1) } defer conn.Close() // 读取服务器提示并输入名称 buffer := make([]byte, 1024) n, err := conn.Read(buffer) if err != nil { fmt.Println("Error reading:", err) return } fmt.Print(string(buffer[:n])) scanner := bufio.NewScanner(os.Stdin) scanner.Scan() name := scanner.Text() conn.Write([]byte(name + "\n")) // 启动读取协程 go func() { for { n, err := conn.Read(buffer) if err != nil { fmt.Println("Connection closed") os.Exit(0) } fmt.Print(string(buffer[:n])) } }() // 发送消息 for scanner.Scan() { message := scanner.Text() conn.Write([]byte(message + "\n")) } }

网络编程最佳实践

  • 使用超时处理避免连接阻塞
  • 使用连接池提高连接复用率
  • 合理设置缓冲区大小
  • 处理网络错误和重试机制
  • 使用goroutine处理并发连接
  • 监控网络性能和错误率
  • 实现优雅关闭

总结

Go语言的网络编程功能强大且易于使用,通过掌握TCP/UDP服务器、HTTP服务器和网络编程技巧,可以编写高效、可靠的网络应用。在实际开发中,应该根据具体场景选择合适的网络协议和编程模式,确保应用的性能和可靠性。

http://www.cnnetsun.cn/news/1944273.html

相关文章:

  • 别只记命令了!用树莓派+Raspberry Pi OS实战理解Linux文件权限和用户管理
  • 从物理应用到图形绘制:用Matlab/Desmos可视化理解考研高数中的定积分与微分方程
  • SAP PP实战解析:用户状态(User Status)的进阶应用与订单分割中的成本收集器
  • Matter协议如何借力Thread与Wi-Fi重塑智能家居体验?
  • Windows 11终极兼容指南:Locale Remulator区域模拟工具完全适配方案
  • AvaloniaUI跨平台播放器实战:从RTSP到MPV的避坑指南(附Linux/Windows/Android配置)
  • 电动车转把不稳定?全新线性霍尔应用方案直击痛点
  • Bluesky 负责人卸任,临时 CEO 上任,小众社交平台能否突破困境?
  • Allegro 17.4 + Samacsys Library Loader 避坑全记录:从安装到成功调用3D模型的完整流程
  • FanControl中文设置终极指南:5分钟让你的Windows风扇控制说中文
  • js内存泄露与垃圾回收机制
  • 别再死记公式了!用Multisim 14.2仿真带你直观理解RLC并联谐振(附仿真文件)
  • VUE实战:amfe-flexible + postcss-pxtorem 打造跨设备移动端自适应布局
  • 3个步骤搞定Windows PDF处理难题:Poppler零依赖解决方案
  • AI生成算法的“可信度衰减曲线”首次建模(基于SITS2026 17家头部厂商实测数据),第8轮迭代后准确率断崖式下跌!
  • VMware17黑苹果虚拟机搭建全攻略:从零开始运行macOS13
  • 终极Windows运行时库管理方案:VisualCppRedist AIO完整指南
  • Java项目集成Tesseract OCR:从环境搭建到跨平台部署实战
  • 别再手动改配置了!用Docker Compose一键部署Pikachu靶场,5分钟搞定渗透测试环境
  • 手眼标定界面不显示?别慌,一个pip install PySide2搞定easy_handeye的rqt窗口问题
  • 从CubeMX工程到ROS2节点:一份给STM32开发者的MicroROS集成实战指南
  • Windhawk:像安装App一样轻松定制Windows,告别复杂的系统修改
  • D2RML终极指南:暗黑破坏神2重制版多开工具完全解析
  • 别再手动编译了!CentOS 7下一键脚本搞定Tinyproxy 1.11.1带密码验证的代理服务器
  • 从搜索引擎到ChatBot:深入浅出聊聊余弦相似度在AI产品里的那些‘隐藏’用法
  • SBT 1.4.4 镜像配置踩坑实录:从 `repositories` 文件格式到 `overrideBuildResolvers` 参数详解
  • Ansys Maxwell实战:电机磁芯损耗建模全流程(附避坑指南)
  • 【企业级AI应用落地生死线】:SITS2026定义的3个不可妥协SLA指标及实时监控方案
  • 地平线DiffusionDrive v1和v2的细节对比解读
  • 7-Zip完整指南:如何用这款免费开源压缩工具提升工作效率 [特殊字符]