Go(Golang)中的网络编程具有易用性、强大性和乐趣。本指南深入探讨了网络编程的复杂性,涵盖了协议、TCP/UDP 套接字、并发等方面的内容,并附有详细的注释。
TCP(传输控制协议):确保可靠的数据传输。
UDP(用户数据报协议):更快,但不保证数据传递。
TCP 套接字:用于面向连接的通信。
UDP 套接字:用于无连接通信。
Goroutines(协程):允许在代码中实现并行处理。
Channels(通道):用于协程之间的通信。
TCP 服务器和客户端示例演示了TCP通信的基础。
服务器:
packagemainimport("net""fmt")funcmain(){// Listen on TCP port 8080 on all available unicast and// any unicast IP addresses.listen,err:=net.Listen("tcp",":8080")iferr!=nil{fmt.Println(err)return}defer listen.Close()// Infinite loop to handle incoming connectionsfor{conn,err:=listen.Accept()iferr!=nil{fmt.Println(err)continue}// Launch a new goroutine to handle the connectiongohandleConnection(conn)}}funchandleConnection(conn net.Conn){defer conn.Close()buffer:=make([]byte,1024)// Read the incoming connection into the buffer._,err:=conn.Read(buffer)iferr!=nil{fmt.Println(err)return}// Send a response back to the client.conn.Write([]byte("Received: "+string(buffer)))}
客户端:
packagemainimport("net""fmt")funcmain(){// Connect to the server at localhost on port 8080.conn,err:=net.Dial("tcp","localhost:8080")iferr!=nil{fmt.Println(err)return}defer conn.Close()// Send a message to the server.conn.Write([]byte("Hello, server!"))buffer:=make([]byte,1024)// Read the response from the server.conn.Read(buffer)fmt.Println(string(buffer))}
服务器在端口8080上等待连接,读取传入的消息并发送响应。客户端连接到服务器,发送消息并打印服务器的响应。
与TCP不同,UDP是无连接的。以下是UDP服务器和客户端的实现。
服务器:
packagemainimport("net""fmt")funcmain(){// Listen for incoming UDP packets on port 8080.conn,err:=net.ListenPacket("udp",":8080")iferr!=nil{fmt.Println(err)return}defer conn.Close()buffer:=make([]byte,1024)// Read the incoming packet data into the buffer.n,addr,err:=conn.ReadFrom(buffer)iferr!=nil{fmt.Println(err)return}fmt.Println("Received: ",string(buffer[:n]))// Write a response to the client's address.conn.WriteTo([]byte("Message received!"),addr)}
客户端:
packagemainimport("net""fmt")funcmain(){// Resolve the server's address.addr,err:=net.ResolveUDPAddr("udp","localhost:8080")iferr!=nil{fmt.Println(err)return}// Dial a connection to the resolved address.conn,err:=net.DialUDP("udp",nil,addr)iferr!=nil{fmt.Println(err)return}defer conn.Close()// Write a message to the server.conn.Write([]byte("Hello, server!"))buffer:=make([]byte,1024)// Read the response from the server.conn.Read(buffer)fmt.Println(string(buffer))}
服务器从任何客户端读取消息并发送响应。客户端发送消息并等待响应。
并发允许同时处理多个客户端。
packagemainimport("net""fmt")funcmain(){// Listen on TCP port 8080.listener,err:=net.Listen("tcp",":8080")iferr!=nil{fmt.Println(err)return}defer listener.Close()for{// Accept a connection.conn,err:=listener.Accept()iferr!=nil{fmt.Println(err)continue}// Handle the connection in a new goroutine.gohandleConnection(conn)}}funchandleConnection(conn net.Conn){defer conn.Close()buffer:=make([]byte,1024)// Read the incoming connection.conn.Read(buffer)fmt.Println("Received:",string(buffer))// Respond to the client.conn.Write([]byte("Message received!"))}
通过为每个连接使用新的 goroutine,多个客户端可以同时连接。
Gorilla Mux 库简化了 HTTP 请求路由。
packagemainimport("fmt""github.com/gorilla/mux""net/http")funcmain(){// Create a new router.r:=mux.NewRouter()// Register a handler function for the root path.r.HandleFunc("/",homeHandler)http.ListenAndServe(":8080",r)}funchomeHandler(w http.ResponseWriter,r*http.Request){// Respond with a welcome message.fmt.Fprint(w,"Welcome to Home!")}
这段代码设置了一个 HTTP 服务器,并为根路径定义了一个处理函数。
实现 HTTPS 服务器可以确保安全通信。
packagemainimport("net/http""log")funcmain(){http.HandleFunc("/",func(w http.ResponseWriter,r*http.Request){// Respond with a message.w.Write([]byte("Hello, this is an HTTPS server!"))})// Use the cert.pem and key.pem files to secure the server.log.Fatal(http.ListenAndServeTLS(":8080","cert.pem","key.pem",nil))}
服务器使用 TLS(传输层安全性)来加密通信。
可以使用自定义的 TCP 协议进行专门的通信。
packagemainimport("net""strings")funcmain(){// Listen on TCP port 8080.listener,err:=net.Listen("tcp",":8080")iferr!=nil{panic(err)}defer listener.Close()for{// Accept a connection.conn,err:=listener.Accept()iferr!=nil{panic(err)}// Handle the connection in a new goroutine.gohandleConnection(conn)}}funchandleConnection(conn net.Conn){defer conn.Close()buffer:=make([]byte,1024)// Read the incoming connection.conn.Read(buffer)// Process custom protocol command.cmd:=strings.TrimSpace(string(buffer))ifcmd=="TIME"{conn.Write([]byte("The current time is: "+time.Now().String()))}else{conn.Write([]byte("Unknown command"))}}
这段代码实现了一个简单的自定义协议,当客户端发送命令“TIME”时,它会回复当前时间。
WebSockets 提供了通过单一连接的实时全双工通信。
packagemainimport("github.com/gorilla/websocket""net/http")varupgrader=websocket.Upgrader{ReadBufferSize:1024,WriteBufferSize:1024,}funchandler(w http.ResponseWriter,r*http.Request){conn,err:=upgrader.Upgrade(w,r,nil)iferr!=nil{http.Error(w,"Could not open websocket connection",http.StatusBadRequest)return}defer conn.Close()for{messageType,p,err:=conn.ReadMessage()iferr!=nil{return}// Echo the message back to the client.conn.WriteMessage(messageType,p)}}funcmain(){http.HandleFunc("/",handler)http.ListenAndServe(":8080",nil)}
WebSocket 服务器会将消息回传给客户端。
可以使用 context 包来管理连接超时。
packagemainimport("context""fmt""net""time")funcmain(){// Create a context with a timeout of 2 secondsctx,cancel:=context.WithTimeout(context.Background(),2*time.Second)defercancel()// Dialer using the contextdialer:=net.Dialer{}conn,err:=dialer.DialContext(ctx,"tcp","localhost:8080")iferr!=nil{panic(err)}buffer:=make([]byte,1024)_,err=conn.Read(buffer)iferr==nil{fmt.Println("Received:",string(buffer))}else{fmt.Println("Connection error:",err)}}
这段代码为从连接读取数据设置了两秒的截止时间。
速率限制控制请求的速率。
packagemainimport("golang.org/x/time/rate""net/http""time")// Define a rate limiter allowing two requests per second with a burst capacity of five.varlimiter=rate.NewLimiter(2,5)funchandler(w http.ResponseWriter,r*http.Request){// Check if request is allowed by the rate limiter.if!limiter.Allow(){http.Error(w,"Too Many Requests",http.StatusTooManyRequests)return}w.Write([]byte("Welcome!"))}funcmain(){http.HandleFunc("/",handler)http.ListenAndServe(":8080",nil)}
此示例使用速率限制器,将请求速率限制为每秒两个请求,突发容量为五个。