原文地址:https://zhuanlan.zhihu.com/p/374016707
提供简洁、清晰的 API;
支持 TCP,WebSocket 等协议;
采用非常简单而又高效的传输协议格式,便于抓包调试;
内置了 JavaScript 文件gotalk.js,方便开发基于 Web 网页的客户端程序;
go get -u github.com/rsms/gotalk
一个简单示例:
// get-started/server/server.go
package main
import (
"log"
"github.com/rsms/gotalk"
)
func main() {
gotalk.Handle("echo", func(in string) (string, error) {
return in, nil
})
if err := gotalk.Serve("tcp", ":8080", nil); err != nil {
log.Fatal(err)
}
}
客户端
func main() {
s, err := gotalk.Connect("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
for i := 0; i < 5; i++ {
var echo string
if err := s.Request("echo", "hello", &echo); err != nil {
log.Fatal(err)
}
fmt.Println(echo)
}
s.Close()
}
WebSocket
func main() {
gotalk.Handle("echo", func(in string) (string, error) {
return in, nil
})
http.Handle("/gotalk/", gotalk.WebSocketHandler())
http.Handle("/", http.FileServer(http.Dir(".")))
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
gotalk为了方便 Web 程序的编写,将 WebSocket 通信细节封装在一个 JavaScript 文件gotalk.js中。可以直接从仓库中的 js 目录下获取使用。接着我们编写页面index.html,引入gotalk.js:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="gotalk/gotalk.js"></script>
</head>
<body>
<input id="txt">
<button id="snd">send</button><br>
<script>
let c = gotalk.connection()
.on('open', () => log(`connection opened`))
.on('close', reason => log(`connection closed (reason: ${reason})`))
let btn = document.querySelector("#snd")
let txt = document.querySelector("#txt")
btn.onclick = async () => {
let content = txt.value
if (content.length === 0) {
alert("no message")
return
}
let res = await c.requestp('echo', content)
log(`reply: ${JSON.stringify(res, null, 2)}`)
return false
}
function log(message) {
document.body.appendChild(document.createTextNode(message))
document.body.appendChild(document.createElement("br"))
}
</script>
</body>
</html>
协议格式
gotalk采用基于 ASCII 的协议格式,设计为方便人类阅读且灵活的。每条传输的消息都分为几个部分:类型标识、请求ID、操作、消息内容。
类型标识:只用一个字节,用来表示消息的类型,是请求消息还是响应消息,流式消息还是非流式的,错误、心跳和通知也都有其特定的类型标识。请求 ID:用 4 个字节表示,方便匹配响应。由于gotalk可以同时发送任意个请求并接收之前请求的响应。所以需要有一个 ID 来标识接收到的响应对应之前发送的哪条请求。操作:即为我们上面定义的消息名,例如"echo"。消息内容:使用长度 + 实际内容格式。
看一个官方请求的示例:
+—————— SingleRequest | +—————- requestID “0001” | | +——— operation “echo” (text3Size 4, text3Value “echo”) | | | +- payloadSize 25 | | | | r0001004echo00000019{“message”:“Hello World”}
r:表示这是一个单条请求。0001:请求 ID 为 1,这里采用十六进制编码。004echo:这部分表示操作为"echo",在实际字符串内容前需要指定长度,否则接收方不知道内容在哪里结束。004指示"echo"长度为 4,同样采用十六进制编码。00000019{"message":"Hello World"}:这部分是消息的内容。同样需要指定长度,十六进制00000019表示长度为 25。
详细格式可以查看官方文档。