websocket是什么
WebSocket是一种计算机通信协议,它提供了在单个TCP连接上进行全双工通信的能力。它允许客户端和服务器之间进行实时数据交换,可以用于实现在线游戏、聊天室、股票市场等需要实时通信的应用程序。WebSocket协议是HTML5规范的一部分,支持大部分现代浏览器。
如何建立长连接
使用Golang建立长连接可以使用标准库中的net
和websocket
包。
以下是一个基本的示例,它创建一个WebSocket服务器并接受客户端连接:
package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func echo(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
for {
// 读取客户端发来的消息
_, message, err := conn.ReadMessage()
if err != nil {
log.Println(err)
break
}
// 将消息原样返回给客户端
err = conn.WriteMessage(websocket.TextMessage, message)
if err != nil {
log.Println(err)
break
}
}
}
func main() {
http.HandleFunc("/echo", echo)
log.Fatal(http.ListenAndServe(":8080", nil))
}
在此示例中,我们使用Upgrader
结构体将HTTP请求升级为WebSocket连接。然后,我们在一个无限循环中读取客户端发送的消息,并将消息原样发送回客户端。
客户端如何跟服务器建立长连接
在Golang中,客户端可以使用gorilla/websocket
包来与WebSocket服务器建立长连接。以下是一个示例代码:
package main
import (
"log"
"net/url"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
func main() {
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
u := url.URL{Scheme: "ws", Host: "localhost:8080", Path: "/echo"}
log.Printf("connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
done := make(chan struct{})
// 接收来自服务器的消息
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
log.Printf("recv: %s", message)
}
}()
// 发送消息给服务器
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-done:
return
case <-ticker.C:
err := c.WriteMessage(websocket.TextMessage, []byte("hello"))
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt")
// 优雅关闭连接
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}
}
在此示例中,我们使用websocket.DefaultDialer
拨号WebSocket服务器,并使用ReadMessage
和WriteMessage
方法发送和接收消息。使用interrupt
通道进行优雅关闭。
要注意的是,此示例中的路径/echo
是服务器端实现的WebSocket处理程序的路径。
这个错误通常是由于客户端没有正确设置请求头引起的。WebSocket连接需要使用HTTP请求升级协议,这需要在请求头中指定Upgrade
和Connection
头字段。
在Golang中,可以使用net/http
包中的Header
类型来设置请求头。以下是一个示例代码:
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("upgrade:", err)
return
}
defer conn.Close()
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
err = conn.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("echo: %s", message)))
if err != nil {
log.Println("write:", err)
break
}
}
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
在客户端代码中,需要使用http.Header
类型来设置请求头。以下是一个示例代码:
package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
func main() {
url := "ws://localhost:8080/"
header := http.Header{}
header.Add("Connection", "upgrade")
header.Add("Upgrade", "websocket")
conn, _, err := websocket.DefaultDialer.Dial(url, header)
if err != nil {
log.Fatal("dial:", err)
}
defer conn.Close()
err = conn.WriteMessage(websocket.TextMessage, []byte("hello"))
if err != nil {
log.Println("write:", err)
return
}
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
log.Printf("recv: %s", message)
}
在此示例中,我们使用http.Header
类型设置了Upgrade
和Connection
头字段,以使客户端请求被正确升级为WebSocket连接。
如何验证websocket是否已经建立
在Golang中,可以使用*websocket.Conn
类型的ReadMessage()
和WriteMessage()
方法来发送和接收WebSocket消息。这些方法将返回error
类型的值,如果在发送或接收过程中出现错误,则返回非nil
的错误。
如果需要验证WebSocket连接是否已经建立,可以使用WriteMessage()
方法向服务器发送一个握手消息,并在发送之后读取服务器的响应消息。以下是一个示例代码:
package main
import (
"log"
"github.com/gorilla/websocket"
)
func main() {
url := "ws://localhost:8080/"
conn, _, err := websocket.DefaultDialer.Dial(url, nil)
if err != nil {
log.Fatal("dial:", err)
}
defer conn.Close()
// 发送握手消息并等待响应
if err := conn.WriteMessage(websocket.TextMessage, []byte("hello")); err != nil {
log.Fatal("write:", err)
}
_, message, err := conn.ReadMessage()
if err != nil {
log.Fatal("read:", err)
}
// 验证WebSocket连接已经建立
if string(message) == "connected" {
log.Println("WebSocket连接已经建立")
} else {
log.Println("WebSocket连接未能建立")
}
}
在此示例中,我们使用WriteMessage()
方法向服务器发送一个包含"hello"
消息体的WebSocket消息,并使用ReadMessage()
方法等待服务器的响应。如果服务器返回的消息是"connected"
,则表明WebSocket连接已经建立。