Go语言网络编程:TCP、HTTP与UDP实战指南
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语言网络编程的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













