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

​

相关推荐
我的div丢了肿么办2 天前
go语言中管道 channel的使用
后端·go
海宇数科2 天前
Go数据工程:利用海宇婚恋风险报告优化实名制严肃婚恋交友合规体验
人工智能·go
用户125758524362 天前
Golang Web后台管理框架推荐:Gin、GoFrame与数据面板项目怎么分
go
我的div丢了肿么办2 天前
进程和线程以及go语言中的协程
后端·go
福兮说3 天前
Go time 包的九个坑:== 判断相等、Parse 差 8 小时、1 月 31 日加一个月变成 3 月 3 日
go
我的div丢了肿么办4 天前
go语言中的空接口和类型断言
后端·go
Thinker QAQ4 天前
并发编程(七):volatile——从语言规则到 CPU
java·python·go·并发编程·volatile·memory model
ZealSinger4 天前
Go1.25 FlightRecorder慢请求截trace
网络·数据库·go
福兮说4 天前
Go 迭代器的七个坑:break 后 panic、一次性迭代器、iter.Pull 不 stop,还有一个跑错地方的 defer
go
ThinkerQAQ_4 天前
并发编程(七):volatile——从语言规则到 CPU
java·python·go