go语言Socket

Socket编程基本原理

Socket编程是指在网络编程中使用Socket接口进行应用程序开发的过程。Socket(套接字)是网络通信中的一个基本概念,是一个抽象的数据结构,用于描述网络中的一个端点。Socket包含了IP地址、端口号、协议类型等信息,用于标识网络中的一个特定的进程或设备。

Socket编程基于两个概念:客户端和服务器。客户端是指发起请求的一方,服务器是指提供服务的一方。通过在网络上建立连接,客户端可以向服务器发送请求,服务器则处理请求并将响应返回给客户端。

Socket编程需要使用一种特殊的协议,这种协议包含了一系列规定的数据格式和交互方式。目前主流的Socket协议有TCP和UDP。TCP协议是一种面向连接的协议,提供数据传输的可靠性。UDP协议则是一种无连接的协议,数据传输不可靠但速度快。

  • TCP(传输控制协议)​:面向连接,可靠,有序,基于字节流。
  • UDP(用户数据报协议)​:无连接,不可靠,无序,基于数据报。

Go 语言提供了强大的 net 包,简化了 Socket 编程,使得开发者无需直接操作底层的系统调用即可实现网络通信。


TCP Socket 编程

TCP 是一种面向连接的协议,适用于需要可靠数据传输的场景。

服务器端实现

以下是一个简单的 TCP 服务器示例,它监听指定端口,接受客户端连接,并回显接收到的消息。

go 复制代码
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
        }
        // 处理连接(可以并发处理多个连接)
        go handleConnection(conn)
    }
}

说明

  1. 使用 net.Listen 监听指定地址和端口。
  2. 使用 listener.Accept 接受客户端连接,返回一个 net.Conn 对象。
  3. 为每个连接启动一个新的 goroutine 处理,实现并发处理多个客户端。

客户端实现

以下是一个简单的 TCP 客户端示例,它连接到服务器并发送消息。

go 复制代码
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)
    }
}

说明

  1. 使用 net.Dial 连接到服务器。
  2. 从标准输入读取用户输入并发送到服务器。
  3. 接收服务器的回显消息并显示。

UDP Socket 编程

UDP 是一种无连接的协议,适用于对实时性要求高但对可靠性要求不高的场景。下面将分别介绍如何使用 Go 实现 UDP 服务器和客户端。

服务器端实现

以下是一个简单的 UDP 服务器示例,它监听指定端口,接收客户端发送的数据,并回显消息。

go 复制代码
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)
        }
    }
}

说明

  1. 使用 net.ResolveUDPAddr 解析 UDP 地址。
  2. 使用 net.ListenUDP 监听 UDP 端口。
  3. 使用 ReadFromUDP 接收数据,并获取客户端地址。
  4. 使用 WriteToUDP 发送数据回客户端。

客户端实现

以下是一个简单的 UDP 客户端示例,它发送消息到服务器并接收回显。

go 复制代码
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]))
    }
}

说明

  1. 使用 net.ResolveUDPAddr 解析服务器地址。
  2. 使用 net.DialUDP 创建一个 UDP 连接(实际上是无连接的)。
  3. 发送和接收数据类似于 TCP 客户端。

相关推荐
corpse20108 小时前
FastMonitor - 网络流量监控与威胁检测工具--各种报错!!!
go
源代码•宸3 天前
Leetcode—1929. 数组串联&&Q1. 数组串联【简单】
经验分享·后端·算法·leetcode·go
nil3 天前
记录protoc生成代码将optional改成omitepty问题
后端·go·protobuf
Way2top3 天前
Go语言动手写Web框架 - Gee第五天 中间件
后端·go
Way2top3 天前
Go语言动手写Web框架 - Gee第四天 分组控制
后端·go
Grassto3 天前
从 `go build` 开始:Go 第三方包加载流程源码导读
golang·go·go module
源代码•宸4 天前
Golang基础语法(go语言结构体、go语言数组与切片、go语言条件句、go语言循环)
开发语言·经验分享·后端·算法·golang·go
華勳全栈4 天前
两天开发完成智能体平台
java·spring·go
stark张宇6 天前
Go语言核心三剑客:数组、切片与结构体使用指南
后端·go
Aevget6 天前
智能高效Go开发工具GoLand v2025.3全新上线——新增资源泄漏分析
开发语言·ide·后端·golang·go