随着互联网的发展,越来越多的应用需要长连接通信来支持实时性和交互性,而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作为一个新兴的协议,已经被广泛应用于实时通信场景,希望本文能够对读者有所帮助。