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 客户端。

相关推荐
Grassto1 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto3 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室4 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题4 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo
啊汉6 天前
古文观芷App搜索方案深度解析:打造极致性能的古文搜索引擎
go·软件随想
asaotomo6 天前
一款 AI 驱动的新一代安全运维代理 —— DeepSentry(深哨)
运维·人工智能·安全·ai·go
码界奇点7 天前
基于Gin与GORM的若依后台管理系统设计与实现
论文阅读·go·毕业设计·gin·源代码管理
迷迭香与樱花7 天前
Gin 框架
go·gin
只是懒得想了7 天前
用Go通道实现并发安全队列:从基础到最佳实践
开发语言·数据库·golang·go·并发安全
fenglllle8 天前
使用fyne做一个桌面ipv4网段计算程序
开发语言·go