Go 实现WebSocket,初步实操
什么是长连接和短连接?
在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。
而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:
Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
Go WebSocket
今天我们会用Go语言使用WebSocket,经过多方收集资料,整理了后端的服务端+客户端,然后服务端和前端的链接两个示例,下面是代码,供大家研究。
今天我们用的是Gin框架实现一个长链接。
1、服务端+客户端(后端)
服务端:
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{}
func main() {
// 使用gin框架,和普通的http协议的服务器没什么不一样
s := gin.Default()
s.GET("/sendMsg", echo)
_ = s.Run("127.0.0.1:8090")
}
func echo(c *gin.Context) {
//服务升级,对于来到的http连接进行服务升级,升级到ws
cn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
defer cn.Close()
if err != nil {
panic(err)
}
for {
mt, message, err := cn.ReadMessage()
fmt.Println("接受到消息", message)
if err != nil {
log.Println("server read:", err)
break
}
log.Printf("server recv msg: %s", message)
msg := string(message)
fmt.Println(msg, "msg")
if msg == "clent" {
message = []byte("客户端来了")
}
err = cn.WriteMessage(mt, message)
if err != nil {
log.Println(" server write err:", err)
break
}
}
}
客户端:
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: "127.0.0.1:8090", Path: "/sendMsg"}
log.Printf("client1 connecting to %s", u.String())
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial server:", err)
}
defer c.Close()
done := make(chan struct{})
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("client read err:", err)
return
}
log.Printf("client recv msg: %s", message)
}
}()
for {
select {
// if the goroutine is done , all are out
case <-done:
return
case <-time.Tick(time.Second * 5):
err := c.WriteMessage(websocket.TextMessage, []byte("clent"))
if err != nil {
log.Println("client write:", err)
return
}
case <-interrupt:
log.Println("client interrupt")
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("client1 write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}
}
分别启动服务端和客户端:服务端会根据客户端发来的消息回复
2、服务端+前端(前后端)
接下来,我们用前后端交互一下websocket
前端页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>websocket测试</title>
<script src="http://www.alingfeng.cn/js/jquery.min.js"></script>
</head>
<body>
<button id="clickButton">点击测试websocket</button>
<script>
$("#clickButton").click(function () {
var name = $("#name").val();
initWebpack(name);
});
</script>
<script>
var planWebsocket = null;
var planIP = "127.0.0.1"; // IP地址
var planPort = "8090"; // 端口号
function initWebpack(clickName) {
//初始化websocket
if ("WebSocket" in window) {
planWebsocket = new WebSocket(
"ws://" + planIP + ":" + planPort + "/sendMsg"
); // 通信地址
setInterval(
(planWebsocket.onopen = function (event) {
console.log("建立连接");
let sendData = {
command: "sendMsg",
data: [{ msg: "服务端,我发送了消息,注意查收!" }],
};
planWebsocket.send(JSON.stringify(sendData)); // 发送获取数据的接口
}),
2000
);
planWebsocket.onmessage = function (event) {
// console.log('收到消息:' + event.data)
let data = JSON.parse(event.data);
if (data.command == "sendMsg") {
var planData = data.data; //返回的数据
console.log(planData);
} else if (data.command == "getscenes") {
// 其他命令
}
};
planWebsocket.onclose = function (event) {
console.log("连接关闭");
};
planWebsocket.onerror = function () {
alert("websocket通信发生错误!");
};
} else {
alert("该浏览器不支持websocket!");
}
}
// initWebpack(); //调用
</script>
</body>
</html>
服务:
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
// var upgrader = websocket.Upgrader{}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
// 解决跨域问题
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func main() {
// 使用gin框架,和普通的http协议的服务器没什么不一样
s := gin.Default()
s.GET("/sendMsg", echo)
_ = s.Run("127.0.0.1:8090")
}
func echo(c *gin.Context) {
//服务升级,对于来到的http连接进行服务升级,升级到ws
cn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
defer cn.Close()
if err != nil {
panic(err)
}
for {
mt, message, err := cn.ReadMessage()
fmt.Println("接受到消息", message)
if err != nil {
log.Println("server read:", err)
break
}
log.Printf("server recv msg: %s", message)
msg := string(message)
fmt.Println(msg, "msg")
// if msg == "clent1" {
// message = []byte("客户端1来了")
// } else if msg == "clent2" {
// message = []byte("你好客户端2")
// }
message = []byte("客户端,我已接收")
for i := 0; i < 100; i++ {
time.Sleep(1000000000)
err = cn.WriteMessage(mt, message)
}
if err != nil {
log.Println(" server write err:", err)
break
}
}
}
测试:
我们初步了解Go语言做websocket就可以了。
还没有评论,快来发表第一个评论吧