Go语言网络编程:TCP、HTTP与UDP实战指南

Finn
Finn
发布时间:2026-10-13 | 5人浏览过
原创

Go语言凭借goroutine在并发网络编程中的优势,能轻松应对大量客户端连接。本文详细介绍使用Go标准库net包实现TCP客户端/服务端、基础HTTP请求及UDP双向通讯的代码结构、执行逻辑与关键API用法。

一、使用Go实现TCP通讯

TCP是一种面向连接的协议,确保数据传输的可靠性。在Go中,主要涉及服务端的端口监听与连接处理,以及客户端的连接建立与数据交互。利用Goroutine,服务端可以轻松处理成百上千个并发连接,无需像传统C/S架构那样为每个连接消耗一个系统线程。

第1步:搭建TCP服务端

目的:创建监听器接收客户端连接,并为每个新连接启动独立的Goroutine进行处理。

入口:导入 fmt 和 net 包。

操作:使用 net.Listen("tcp", "地址:端口") 绑定监听端口,进入无限循环调用 Accept() 获取连接。一旦接受连接,立即调用 go process(conn) 启动协程,使主循环继续等待新连接。

package main

import (
    "fmt"
    "net"
)

func main() {
    //1.建立监听端口,监听所有IPv4地址的20000端口
    listen, err := net.Listen("tcp", "0.0.0.0:20000")
    if err != nil {
        fmt.Println("listen failed, err:", err)
        return
    }

    fmt.Println("listen Start...:")

    for {
        //2.阻塞等待并接受客户端链接
        conn, err := listen.Accept()
        if err != nil {
            fmt.Printf("accept failed, err:%v\n", err)
            continue
        }
        //3.开启一个Goroutine并发处理该链接
        go process(conn)
    }
}

//处理单个客户端的请求
func process(conn net.Conn) {
    //函数退出时关闭连接
    defer conn.Close()

    for {
        var buf [128]byte
        //从客户端读取数据
        n, err := conn.Read(buf[:])
        if err != nil {
            fmt.Printf("read from conn failed, err:%v\n", err)
            break
        }
        fmt.Printf("recv from client, content:%s\n", string(buf[:n]))
    }
}

第2步:编写TCP客户端

目的:与服务端建立长连接,并通过标准输入发送指令或数据。

操作:使用 net.Dial("tcp", "地址:端口") 发起连接。使用 bufio.NewReader(os.Stdin) 读取控制台输入的字符串,去除首尾空格后,通过 conn.Write() 将字节切片发送给服务端。

package main

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

func main() {
    //1.拨号(Dial)与服务端建立TCP链接
    conn, err := net.Dial("tcp", "127.0.0.1:20000")
    if err != nil {
        fmt.Printf("dial failed, err:%v\n", err)
        return
    }
    defer conn.Close()

    fmt.Println("Conn Established...")

    //准备从标准输入读取
    reader := bufio.NewReader(os.Stdin)
    for {
        data, err := reader.ReadString('\n')
        if err != nil {
            fmt.Printf("read from console failed, err:%v\n", err)
            break
        }

        //处理行尾的空格或换行符
        data = strings.TrimSpace(data)
        if len(data) == 0 { continue }

        //将字符串转换为[]byte写入连接
        _, err = conn.Write([]byte(data))
        if err != nil {
            fmt.Printf("write failed, err:%v\n", err)
            break
        }
    }
}

在实际测试中,先运行服务端代码,再运行客户端代码。客户端输入内容后,服务端终端会打印出“recv from client”及对应内容,反之亦然。

二、理解基于TCP的HTTP协议通讯

HTTP协议本质上是建立在TCP连接之上的应用层文本协议。理解其底层原理有助于排查网络问题。在HTTP/1.1中,每一行报文头以 \r\n 结尾;当出现连续两个 \r\n (即空行)时,表示请求头部结束,后续为请求体(GET请求通常无请求体)。以下演示如何通过纯TCP Socket发送一个标准的HTTP GET请求并接收响应。

package main

import (
    "fmt"
    "io"
    "net"
)

func main() {
    //连接到百度首页
    conn, err := net.Dial("tcp", "www.baidu.com:80")
    if err != nil {
        fmt.Printf("dial failed, err:%v\n", err)
        return
    }
    defer conn.Close()

    //构造符合HTTP协议的请求报文
    request := "GET / HTTP/1.1\r\n"
    request += "Host: www.baidu.com\r\n"
    request += "Connection: close\r\n" //显式要求断开连接
    request += "\r\n"

    //写入数据到TCP连接
    _, err = io.WriteString(conn, request)
    if err != nil {
        fmt.Printf("wirte string failed, err:%v\n", err)
        return
    }

    //读取服务器返回的Response
    buf := make([]byte, 4096)
    for {
        n, err := conn.Read(buf)
        if err != nil || n == 0 {
            break
        }
        fmt.Println(string(buf[:n]))
    }
}

三、使用Go创建UDP连接

与TCP不同,UDP是无连接的传输协议。服务端不需要进行类似TCP的 Accept() 过程,只需监听指定端口等待数据包到达。由于没有固定连接,每次接收数据都必须附带来源地址信息,以便回传数据。

第1步:搭建UDP服务端

入口:使用 net.ListenUDP("udp", &addr) 初始化监听。

动作:在循环中调用 ReadFromUDP() 接收数据。该方法不仅返回读取的数据量,还会返回客户端的 *net.UDPAddr。随后使用相同的方法对象调用 WriteToUDP() 向该地址回写消息。

package main

import (
    "fmt"
    "net"
)

func main() {
    //创建一个UDP监听,绑定本地所有IPv4地址和8080端口
    udpConn, err := net.ListenUDP("udp", &net.UDPAddr{
        IP:   net.IPv4(0, 0, 0, 0),
        Port: 8080,
    })
    if err != nil {
        fmt.Printf("listen failed, err:%v\n", err)
        return
    }
    defer udpConn.Close()

    for {
        var data [1024]byte
        //阻塞直到收到数据,同时获取发送方地址
        count, remoteAddr, err := udpConn.ReadFromUDP(data[:])
        if err != nil {
            fmt.Printf("read udp failed, err:%v\n", err)
            continue
        }

        fmt.Printf("Received from %v: %s\n", remoteAddr, string(data[0:count]))

        //向收到的地址回复数据
        replyMsg := []byte("Hello Client! This is UDP Server.")
        _, _, err = udpConn.WriteToUDP(replyMsg, remoteAddr)
        if err != nil {
            fmt.Printf("write udp failed, err:%v\n", err)
        }
    }
}

第2步:编写UDP客户端

操作:使用 net.DialUDP() 建立本地到目标服务器的连接(此时并无三次握手)。通过 Write() 发送数据后,使用 ReadFromUDP() 接收服务端的响应。

package main

import (
    "fmt"
    "net"
)

func main() {
    //创建UDP客户端连接至本地8080端口
    socket, err := net.DialUDP("udp4", nil, &net.UDPAddr{
        IP:   net.IPv4(127, 0, 0, 1),
        Port: 8080,
    })
    if err != nil {
        fmt.Println("connection failed!", err)
        return
    }
    defer socket.Close()

    //1. 发送数据
    senddata := []byte("hello server!")
    if _, err := socket.Write(senddata); err != nil {
        fmt.Println("send failed!", err)
        return
    }

    //2. 接收服务端回应的数据
    data := make([]byte, 4096)
    readCount, remoteAddr, err := socket.ReadFromUDP(data)
    if err != nil {
        fmt.Println("read failed!", err)
        return
    }
    
    fmt.Printf("Received %d bytes from %v: %s\n", readCount, remoteAddr, string(data[:readCount]))
}

测试时,先启动UDP服务端,再运行UDP客户端。客户端控制台应显示接收到的回显消息。

以上就是Go语言实现UDP协议及TCP通讯的详细内容,更多关于Go语言网络编程的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表