当前位置:网站首页>On using go language to create websocket service
On using go language to create websocket service
2022-04-23 12:06:00 【ysds20211402】
from : Micro reading https://www.weidianyuedu.com
How to use it today Go Language establish WebSocket service , The first two parts of the article briefly introduce WebSocket Agreement and use Go How to create a standard library WebSocket service . The third part is the practice link we used gorilla/websocket Libraries help us build quickly WebSocket service , It helps to encapsulate the use of Go Standard library implementation WebSocket Basic logic of service , Let's get rid of the tedious underlying code , Build quickly according to business requirements WebSocket service .
WebSocket Introduce
WebSocket Communication protocol through a single TCP Connection provides full duplex communication channel . And HTTP comparison ,WebSocket You don't need to send a request to get a response . It allows two-way data flow , So you just need to wait for messages from the server . When Websocket When available , It will send you a message . For services requiring continuous data exchange ( For example, instant messaging program , Online games and real-time trading system ),WebSocket Is a good solution . WebSocket Connection requested by browser , And the server responds , Then establish a connection , This process is often referred to as handshaking . WebSocket The special header in requires only one handshake between the browser and the server to establish a connection , The connection will remain active throughout its lifecycle . WebSocket Solved many real-time problems Web Development challenges , And with the traditional HTTP comparison , It has many advantages :
Lightweight header reduces data transmission overhead .
Single Web Client only needs one TCP Connect .
WebSocket The server can push data to Web client .
WebSocket Protocol implementation is relatively simple . It USES HTTP Protocol initial handshake . Establish the connection after the handshake is successful ,WebSocket Essentially using the original TCP Read / Write data .
Client requests are as follows :
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
This is the server response :
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
How to be in Go Created in WebSocket application
Based on Go Language built in net/http Library writing WebSocket The server , You need :
Shake hands
Receive data frame from client
Send data frame to client
Close handshake
Shake hands
First , Let's create a WebSocket End point's HTTP The handler :
// HTTP server with WebSocket endpoint
func Server() {undefined
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {undefined
ws, err := NewHandler(w, r)
if err != nil {undefined
// handle error
}
if err = ws.Handshake(); err != nil {undefined
// handle error
}
…
Then initialize WebSocket structure .
The initial handshake request always comes from the client . The server has determined WebSocket After the request , A handshake response is required to respond .
please remember , You can't use http.ResponseWriter Write response , Because once you start sending responses , It will close the TCP Connect ( This is a HTTP Determined by the operation mechanism of the agreement , Close connection after sending response ).
therefore , You need to use HTTP hijacked (hijack). By hijacking , Can take over the foundation TCP Connection handlers and bufio.Writer. This enables the TCP Read and write data when connected .
// NewHandler initializes a new handler
func NewHandler(w http.ResponseWriter, req *http.Request) (*WS, error) {undefined
hj, ok := w.(http.Hijacker)
if !ok {undefined
// handle error
} .....
}
To complete the handshake , The server must respond with the appropriate headers .
// Handshake creates a handshake header
func (ws *WS) Handshake() error {undefined
hash := func(key string) string {undefined
h := sha1.New()
h.Write([]byte(key))
h.Write([]byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}(ws.header.Get("Sec-WebSocket-Key"))
.....
}
Client initiated WebSocket For connection requests Sec-WebSocket-key It's randomly generated , And is Base64 Coded . After accepting the request , The server needs to attach this key to a fixed string . Suppose the secret key is x3JJHMbDL1EzLkh9GBhXDw==. In this case , have access to SHA-1 Calculate binary value , And use Base64 Code it . obtain HSmrc0sMlYUkAGmm5OPpG2HaGWk=. Then use it as Sec-WebSocket-Accept Value of response header .
Transmit data frame
After successful handshake , Your application can read data from or write data to clients .WebSocket The specification defines a specific frame format to be used between a client and a server . This is the bit pattern of the framework :
chart : Bit mode of data frame transmission
Use the following code to decode the client payload :
// Recv receives data and returns a Frame
func (ws *WS) Recv() (frame Frame, _ error) {undefined
frame = Frame{}
head, err := ws.read(2)
if err != nil {undefined
// handle error
}
In turn, , These lines allow data to be encoded :
// Send sends a Frame
func (ws *WS) Send(fr Frame) error {undefined
// make a slice of bytes of length 2
data := make([]byte, 2)
// Save fragmentation & opcode information in the first byte
data[0] = 0x80 | fr.Opcode
if fr.IsFragment {undefined
data[0] &= 0x7F
}
.....
Close handshake
When one of the parties sends a closed frame with the status of closed as the payload , Handshake will close . Optional , The party sending the shutdown frame can send the shutdown reason in the payload . If the shutdown is initiated by the client , Then the server should send the corresponding shutdown frame in response .
// Close sends a close frame and closes the TCP connection
func (ws *Ws) Close() error {undefined
f := Frame{}
f.Opcode = 8
f.Length = 2
f.Payload = make([]byte, 2)
binary.BigEndian.PutUint16(f.Payload, ws.status)
if err := ws.Send(f); err != nil {undefined
return err
}
return ws.conn.Close()
}
Use third-party library to build quickly WebSocket service
As can be seen from the above chapters Go Self contained net/http Library implementation WebSocket Service is still too complicated . Fortunately, there are many right WebSocket Support a good third-party library , Can reduce a lot of our underlying coding work . Here we use gorilla web toolkit Another library of the family gorilla/websocket To achieve our WebSocket service , Build a simple one Echo service (echo It means echo , What does the client send , The server sends the message back to the client ).
We are http_demo Project handler Create a new one in the directory ws Subdirectories are used to store WebSocket Request handler for service related routing .
Add two routes :
/ws/echo echo Applied WebSocket Routing of services .
/ws/echo_display echo Routing of the client page of the application .
establish WebSocket Server side
// handler/ws/echo.go
package ws
import (
"fmt"
"github.com/gorilla/websocket"
"net/http"
)
var upgrader = websocket.Upgrader{undefined
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func EchoMessage(w http.ResponseWriter, r *http.Request) {undefined
conn, _ := upgrader.Upgrade(w, r, nil) // Remember to do error handling in practical application
for {undefined
// Read messages from clients
msgType, msg, err := conn.ReadMessage()
if err != nil {undefined
return
}
// Print messages to standard output
fmt.Printf("%s sent: %s\n", conn.RemoteAddr(), string(msg))
// Write messages back to the client , Complete echo
if err = conn.WriteMessage(msgType, msg); err != nil {undefined
return
}
}
}
conn The type of variable is *websocket.Conn, websocket.Conn Type is used to represent WebSocket Connect . Server application from HTTP Request handler call Upgrader.Upgrade Method to get *websocket.Conn
Call connected WriteMessage and ReadMessage Method to send and receive messages . above msg After receiving it, it is sent back to the client below .msg The type is []byte.
establish WebSocket client
The request handler corresponding to the front-end page routing is as follows , Go straight back to views/websockets.html Just render the page to the browser .
// handler/ws/echo_display.go
package ws
import "net/http"
func DisplayEcho(w http.ResponseWriter, r *http.Request) {undefined
http.ServeFile(w, r, "views/websockets.html")
}
websocket.html We need to use JavaScript Connect WebScoket Service sends and receives messages , The reason is that I only post JS Code. , Complete code can get the download link through the official account of this section. .
<form>
<input id="input" type="text" />
<button οnclick="send()">Send</button>
<pre id="output"></pre>
</form>
...
<script>
var input = document.getElementById("input");
var output = document.getElementById("output");
var socket = new WebSocket("ws://localhost:8000/ws/echo");
socket.onopen = function () {undefined
output.innerHTML += "Status: Connected\n";
};
socket.onmessage = function (e) {undefined
output.innerHTML += "Server: " + e.data + "\n";
};
function send() {undefined
socket.send(input.value);
input.value = "";
}
</script>
...
Registered routing
After the server and client programs are ready , We register the route and the corresponding request handler for them according to the agreed path :
// router/router.go
func RegisterRoutes(r *mux.Router) {undefined
...
wsRouter := r.PathPrefix("/ws").Subrouter()
wsRouter.HandleFunc("/echo", ws.EchoMessage)
wsRouter.HandleFunc("/echo_display", ws.DisplayEcho)
}
Test verification
Access after service restart http://localhost:8000/ws/echo_display, Any message entered in the input box can be echoed back to the browser .
picture
The server prints the received message to the terminal and then calls the writeMessage Send the message back to the client , Records can be viewed in the terminal .
summary
WebSocket It is widely used in the frequently updated applications , Conduct WebSocket Programming is also a necessary skill we need to master . The practice of the article is a little simpler , No error or security checks . Mainly to clarify the general process . About gorilla/websocket For more details, you need to check the official documents when using .
版权声明
本文为[ysds20211402]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204231203047375.html
边栏推荐
- IDEA 代码格式化插件Save Actions
- Here comes the detailed picture and text installation tutorial of H5 game
- 软银愿景基金进军Web3安全行业 领投CertiK 6000万美元新一轮投资
- Fabric 1.0源代码分析(33) Peer #peer channel命令及子命令实现
- ES6 learning notes II
- PSCP basic usage
- Castle.DynamicProxy实现事务单元控制
- Share two practical shell scripts
- 第四章 为IM 启用填充对象之强制填充In-Memory对象:教程(IM 4.7)
- 远程访问家里的树莓派(上)
猜你喜欢
Fastjson 2 来了,性能继续提升,还能再战十年
2022 love analysis · panoramic report of industrial Internet manufacturers
欣旺达宣布电池产品涨价 此前获“蔚小理”投资超10亿
Idea code quality specification plug-in sonarlint
AI 视频云 VS 窄带高清,谁是视频时代的宠儿
Next. JS static data generation and server-side rendering
远程访问家里的树莓派(上)
宝塔面板命令行帮助教程(包含重置密码)
如果你是一个Golang面试官,你会问哪些问题?
软银愿景基金进军Web3安全行业 领投CertiK 6000万美元新一轮投资
随机推荐
Purpose of IM expression (IM 5.2)
IM表达式的目的(IM 5.2)
1. Construction of electron development environment
SOFA Weekly | 年度优秀 Committer 、本周 Contributor、本周 QA
论文解读(CGC)《CGC: Contrastive Graph Clustering for Community Detection and Tracking》
How Im expressions work (5.3)
golang之筆試題&面試題01
What is a gateway
1.Electron开发环境搭建
第二十四课 经典问题解析
软件测试基础DAY2-用例执行
第四章 为IM 启用填充对象之在NO INMEMORY表上指定INMEMORY列属性:示例(IM-4.4 第四部分)
A detailed explanation of head pose estimation [collection of good articles]
第四章 为IM 启用填充对象之启用和禁用列(IM-4.3 第三部分)
论文解读(CGC)《CGC: Contrastive Graph Clustering for Community Detection and Tracking》
Running error: unable to find or load the main class com xxx. Application
Share two practical shell scripts
Nacos Foundation (6): Nacos configuration management model
Solution of asynchronous clock metastability -- multi bit signal
Win10 splash screen after startup