Go 语言网络编程

网络编程是现代互联网中不可或缺的一个技术领域。在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)
}

此示例使用速率限制器,将请求速率限制为每秒两个请求,突发容量为五个。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值