随着互联网的发展,越来越多的应用需要长连接通信来支持实时性和交互性,而WebSocket作为一个新兴的协议,已经被广泛应用于实时通信场景。本文将介绍Golang网络编程进阶实践,使用WebSocket实现长连接通信的具体实现。 一、WebSocket简介 WebSocket是一个基于TCP协议实现的应用层协议,旨在解决Web上实时通信的问题。相比较于HTTP协议,WebSocket有以下特点: 1、全双工通信,支持双向通信,客户端和服务器可以同时向对方发送数据; 2、支持跨域通信,可以允许不同源的客户端和服务器进行通信; 3、支持二进制数据,可传输任何数据类型,包括音频、视频、图片等; 4、更快的响应速度,WebSocket连接一旦建立,服务器可以主动向客户端推送数据。 二、Golang实现WebSocket Go语言原生支持WebSocket,为支持WebSocket,Go的标准库提供了net/http和net/http/httptest两个包,其中net/http包提供了对HTTP协议的支持,net/http/httptest包提供了HTTP测试框架,可以用于测试HTTP服务器。 1、服务器端实现 服务器端需要监听客户端的WebSocket握手请求,一旦握手成功,服务器端与客户端就可以进行长连接通信。下面是服务器端的代码实现: ```go package main import ( "fmt" "log" "net/http" "github.com/gorilla/websocket" ) var ( upgrader = websocket.Upgrader{} ) func main() { http.HandleFunc("/ws", handleWebSocket) log.Fatal(http.ListenAndServe(":8080", nil)) } func handleWebSocket(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println("upgrade error:", err) return } defer conn.Close() for { _, message, err := conn.ReadMessage() if err != nil { log.Println("read error:", err) break } log.Printf("recv: %s\n", message) err = conn.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("echo: %s", message))) if err != nil { log.Println("write error:", err) break } } } ``` 代码解释: 1、WebSocket处理函数handleWebSocket,首先调用Upgrader.Upgrade函数将普通的HTTP连接升级为WebSocket连接,这个函数会返回一个WebSocket的连接对象Conn。 2、使用for循环不断地读取客户端发送的消息,一旦读取到消息,就将其打印出来,并回复给客户端。 3、最后记得在函数退出之前,关闭WebSocket连接。 2、客户端实现 在客户端,需要连接WebSocket服务器,并不断地向服务器发送和接收消息。下面是客户端的代码实现: ```go package main import ( "fmt" "log" "net/url" "os" "os/signal" "time" "github.com/gorilla/websocket" ) var ( addr = "localhost:8080" schema = "ws" ) func main() { interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) u := url.URL{Scheme: schema, Host: addr, Path: "/ws"} log.Printf("connecting to %s", u.String()) conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { log.Fatal("dial error:", err) } defer conn.Close() done := make(chan struct{}) go func() { defer close(done) for { select { case <-interrupt: log.Println("interrupt") return default: _, message, err := conn.ReadMessage() if err != nil { log.Println("read error:", err) return } log.Printf("recv: %s\n", message) } } }() for { select { case <-interrupt: log.Println("interrupt") err := conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Println("write close error:", err) return } select { case <-done: case <-time.After(time.Second): } return default: err = conn.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("hello, world! timestamp: %d", time.Now().Unix()))) if err != nil { log.Println("write error:", err) return } time.Sleep(time.Second) } } } ``` 代码解释: 1、使用url.URL组合出WebSocket服务器的URL。 2、调用websocket.Dial函数与WebSocket服务器建立连接。 3、使用for循环不断地读取控制台输入,一旦读取到输入,就将其发送到WebSocket服务器上。 4、开启一个goroutine用于接收WebSocket服务器的回复消息。 5、在main函数的主goroutine中等待中断信号,一旦读到中断信号,则发送一个WebSocket关闭控制消息给服务器,并在发送后等待一秒钟,等待接收服务器的关闭回复消息。 三、总结 本文介绍了Golang网络编程进阶实践,使用WebSocket实现长连接通信的具体实现,包含了服务器端和客户端的代码实现。WebSocket作为一个新兴的协议,已经被广泛应用于实时通信场景,希望本文能够对读者有所帮助。