mrkong 发表于 2025-9-5 14:05:31

Go语言Socket:TCP 和 UDP 示例详解

在网络编程中,Socket(套接字)是一个非常重要的概念。它是一个抽象的数据结构,用于表示网络中的一个端点,包含了 IP 地址、端口号以及协议类型等信息。Go 语言提供了强大的 net 包,使得 Socket 编程变得更加简便。本文将详细介绍 Go 语言如何实现 TCP 和 UDP Socket 编程。1. Socket 编程基本原理Socket 编程基于客户端-服务器模型,其中:
[*]客户端:发起请求的一方。
[*]服务器:提供服务的一方。
通过 Socket,客户端可以向服务器发送请求,服务器接收到请求后进行处理并返回响应。常见的协议类型
[*]TCP(传输控制协议):面向连接的协议,可靠、保证数据有序传输,适用于对数据传输有严格要求的场景。
[*]UDP(用户数据报协议):无连接的协议,不保证数据可靠传输,适用于对实时性要求较高的场景。
Go 语言通过 net 包提供了对这两种协议的支持,使得开发者能够轻松实现网络通信。2. TCP Socket 编程2.1 服务器端实现TCP 是一种面向连接的协议,适合需要可靠数据传输的场景。以下是一个简单的 TCP 服务器实现,它会监听指定端口并回显接收到的消息。package main

import (
    "bufio"
    "fmt"
    "net"
)

func handleConnection(conn net.Conn) {
    defer conn.Close()
    reader := bufio.NewReader(conn)
    for {
      // 读取客户端发送的数据
      message, err := reader.ReadString('\n')
      if err != nil {
            fmt.Println("读取数据错误:", err)
            break
      }
      fmt.Printf("收到消息: %s", message)
      // 回显消息给客户端
      conn.Write([]byte("Echo: " + message))
    }
}

func main() {
    // 监听本地 8080 端口
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
      fmt.Println("监听端口失败:", err)
      return
    }
    defer listener.Close()
    fmt.Println("服务器正在监听端口 8080...")

    for {
      // 接受客户端连接
      conn, err := listener.Accept()
      if err != nil {
            fmt.Println("接受连接失败:", err)
            continue
      }
      // 为每个连接启动一个新的 goroutine 进行处理
      go handleConnection(conn)
    }
}
说明:
[*]使用 net.Listen 监听指定的 IP 地址和端口。
[*]通过 listener.Accept 接受客户端的连接,返回一个 net.Conn 对象。
[*]每当接收到一个连接时,通过 goroutine 并发处理该连接。
2.2 客户端实现
以下是一个简单的 TCP 客户端示例,连接到服务器并发送消息。package main

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

func main() {
    // 连接到服务器(localhost:8080)
    conn, err := net.Dial("tcp", "localhost:8080")
    if err != nil {
      fmt.Println("连接服务器失败:", err)
      return
    }
    defer conn.Close()

    reader := bufio.NewReader(os.Stdin)
    for {
      // 从标准输入读取用户输入
      fmt.Print("请输入消息: ")
      message, _ := reader.ReadString('\n')
      // 发送消息到服务器
      _, err := conn.Write([]byte(message))
      if err != nil {
            fmt.Println("发送消息失败:", err)
            return
      }
      // 接收服务器回显的消息
      response, err := bufio.NewReader(conn).ReadString('\n')
      if err != nil {
            fmt.Println("接收消息失败:", err)
            return
      }
      fmt.Print("服务器回显: " + response)
    }
}
说明:
[*]使用 net.Dial 连接到服务器。
[*]从标准输入读取用户输入并将其发送到服务器。
[*]接收服务器回显的消息并显示。
3. UDP Socket 编程UDP 是一种无连接的协议,适合对实时性要求较高但对数据传输可靠性要求不高的场景。下面是如何在 Go 中实现 UDP 服务器和客户端。3.1 服务器端实现
以下是一个简单的 UDP 服务器实现,它监听指定端口,接收客户端发送的数据,并回显消息。package main

import (
    "fmt"
    "net"
)

func main() {
    // 监听本地 8081 端口的 UDP
    addr, err := net.ResolveUDPAddr("udp", ":8081")
    if err != nil {
      fmt.Println("解析地址失败:", err)
      return
    }

    conn, err := net.ListenUDP("udp", addr)
    if err != nil {
      fmt.Println("监听 UDP 失败:", err)
      return
    }
    defer conn.Close()
    fmt.Println("UDP 服务器正在监听端口 8081...")

    buffer := make([]byte, 1024)
    for {
      // 读取客户端发送的数据
      n, clientAddr, err := conn.ReadFromUDP(buffer)
      if err != nil {
            fmt.Println("读取数据错误:", err)
            continue
      }
      message := string(buffer[:n])
      fmt.Printf("收到来自 %s 的消息: %s", clientAddr, message)

      // 回显消息给客户端
      _, err = conn.WriteToUDP([]byte("Echo: "+message), clientAddr)
      if err != nil {
            fmt.Println("发送消息失败:", err)
      }
    }
}
说明:
[*]使用 net.ResolveUDPAddr 解析 UDP 地址。
[*]使用 net.ListenUDP 监听指定的端口。
[*]conn.ReadFromUDP 用于接收客户端数据,并返回客户端地址。
3.2 客户端实现
以下是一个简单的 UDP 客户端实现,发送消息到服务器并接收回显。package main

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

func main() {
    // 解析服务器地址
    serverAddr, err := net.ResolveUDPAddr("udp", "localhost:8081")
    if err != nil {
      fmt.Println("解析服务器地址失败:", err)
      return
    }

    // 创建一个 UDP 连接(实际上是无连接的)
    conn, err := net.DialUDP("udp", nil, serverAddr)
    if err != nil {
      fmt.Println("连接 UDP 服务器失败:", err)
      return
    }
    defer conn.Close()

    reader := bufio.NewReader(os.Stdin)
    for {
      // 从标准输入读取用户输入
      fmt.Print("请输入消息: ")
      message, _ := reader.ReadString('\n')
      // 发送消息到服务器
      _, err := conn.Write([]byte(message))
      if err != nil {
            fmt.Println("发送消息失败:", err)
            return
      }
      // 接收服务器回显的消息
      buffer := make([]byte, 1024)
      n, err := conn.Read(buffer)
      if err != nil {
            fmt.Println("接收消息失败:", err)
            return
      }
      fmt.Print("服务器回显: " + string(buffer[:n]))
    }
}
说明:
[*]使用 net.ResolveUDPAddr 解析服务器地址。
[*]使用 net.DialUDP 创建一个 UDP 连接(实际上是无连接的)。
[*]客户端向服务器发送消息并接收回显。
4. 总结
Go 语言通过其强大的 net 包,简化了 Socket 编程,支持常见的 TCP 和 UDP 协议。无论是需要可靠数据传输的 TCP,还是对实时性要求高的 UDP,Go 都能轻松实现。通过学习本文中的示例,你可以掌握基本的 Socket 编程技巧,并能够在实际应用中灵活运用这些技术。
页: [1]
查看完整版本: Go语言Socket:TCP 和 UDP 示例详解