网络编程是现代互联网中不可或缺的一个技术领域。在Golang中,我们可以轻松地构建高效的网络通信应用程序。
在 Golang 中,我们可以使用标准库中的net包
来实现网络编程。net包
有许多常见的网络协议和功能,如 TCP、UDP、HTTP等。
1. TCP 服务器和客户端
服务端:
package main
import (
"net"
"fmt"
)
func main() {
listen, err := net.Listen("tcp", ":8080")
if err != nil {
fmt.Println(err)
return
}
defer listen.Close()
for {
conn, err := listen.Accept()
if err != nil {
continue
}
go handleConnection(conn) // 每个连接使用新的 goroutine, 提高并发
}
}
func handleConnection(conn net.Conn) {
defer conn.Close()
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
return
}
msg := string(buf[:n])
fmt.Println("Received message:", msg)
// 发送数据到客户端
conn.Write([]byte("Server response"))
}
我们可以使用 telnet工具来连接该服务端
$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello, server!
Server response
客户端发送了一条消息到服务器,服务器接收到该消息并发送了一条响应。
客户端:
func main() {
// 连接 8080 端口
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
// 发送数据到服务器
conn.Write([]byte("Hello, server!"))
buffer := make([]byte, 1024)
// 读取服务器的响应信息
conn.Read(buffer)
fmt.Println(string(buffer))
}
2. UDP 服务器和客户端
与TCP不同,UDP是无连接的。以下是UDP服务器和客户端的实现。
服务器:
package main
import (
"net"
"fmt"
)
func main() {
conn, err := net.ListenPacket("udp", ":8080")
if err != nil {
fmt.Println(err)
return
}
defer conn.Close()
buffer := make([]byte, 1024)
// 读取数据
n, addr, err := conn.ReadFrom(buffer)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Received: ", string(buffer[:n]))
// 发送数据到指定地址
conn.WriteTo([]byte("Message received!"), addr)
}
客户端:
func main() {
addr, err := net.ResolveUDPAddr("udp", "localhost:8080")
if err != nil {
fmt.Println(err)
return
}
conn, err := net.DialUDP("udp", nil, addr)
if err != nil {
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))
}
服务器从任何客户端读取消息并发送响应。客户端发送消息并等待响应。
3. HTTP编程
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, client!")
})
err := http.ListenAndServe(":1234", nil)
if err != nil {
fmt.Println("Error:", err)
return
}
}
使用curl工具来向该服务器发送HTTP请求:
$ curl http://localhost:1234
Hello, client!
Gorilla Mux 库简化 HTTP 请求路由:
package main
import (
"fmt"
"github.com/gorilla/mux"
"net/http"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/", homeHandler)
http.ListenAndServe(":8080", r)
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Welcome to Home!")
}
4. HTTPS 服务器
package main
import (
"net/http"
"log"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, this is an HTTPS server!"))
})
// Use the cert.pem and key.pem files to secure the server.
http.ListenAndServeTLS(":8080", "cert.pem", "key.pem", nil)
}
实现 HTTPS 服务器可以确保安全通信。服务器使用 TLS(传输层安全性)来加密通信。
5. WebSocket 通讯
使用 Gorilla websocket库
WebSockets 提供了通过单一连接的实时全双工通信。
package main
import (
"github.com/gorilla/websocket"
"net/http"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func handler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
return
}
defer conn.Close()
for {
messageType, p, err := conn.ReadMessage()
if err != nil {
return
}
conn.WriteMessage(messageType, p)
}
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
6. 连接超时
可以使用 context
包来管理连接超时。
package main
import (
"context"
"fmt"
"net"
"time"
)
func main() {
// Create a context with a timeout of 2 seconds
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
// Dialer using the context
dialer := net.Dialer{}
conn, err := dialer.DialContext(ctx, "tcp", "localhost:8080")
if err != nil {
panic(err)
}
buffer := make([]byte, 1024)
_, err = conn.Read(buffer)
if err == nil {
fmt.Println("Received:", string(buffer))
} else {
fmt.Println("Connection error:", err)
}
}
7. 速率限制
使用 golang.org/x/time/rate
进行速率限制
package main
import (
"golang.org/x/time/rate"
"net/http"
"time"
)
var limiter = rate.NewLimiter(2, 5)
func handler(w http.ResponseWriter, r *http.Request) {
if !limiter.Allow() {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
return
}
w.Write([]byte("Welcome!"))
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
此示例使用速率限制器,将请求速率限制为每秒两个请求,突发容量为五个。