简介
gotalk
gotalk.js
那么,让我们来玩一下吧~
快速使用
本文代码使用 Go Modules。
创建目录并初始化:
$ mkdir gotalk && cd gotalk
$ go mod init github.com/darjun/go-daily-lib/gotalk
gotalk
$ go get -u github.com/rsms/gotalk
接下来让我们来编写一个简单的 echo 程序,服务端直接返回收到的客户端信息,不做任何处理。首先是服务端:
// 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)
}
}
gotalk.Handle()
这里的处理器函数比较简单,接受一个字符串参数,直接原样返回。
gotalk.Serve()8080nil
服务器内部一直循环处理请求。
然后是客户端:
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()
}
gotalk.Connect()Request()Request()
err
先运行服务器:
$ go run server.go
在开启一个命令行,运行客户端:
$ go run client.go
hello
hello
hello
hello
hello
net/httpgotalknet/http
// get-started/http/main.go
package main
import (
"fmt"
"log"
"net/http"
)
func index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello world")
}
func main() {
http.HandleFunc("/", index)
if err := http.ListenAndServe(":8888", nil); err != nil {
log.Fatal(err)
}
}
运行:
$ go run main.go
使用 curl 验证:
$ curl localhost:8888
hello world
WebSocket
gotalk
服务端:
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/gotalk/gotalk.WebSocketHandler()/index.htmlhttp.ListenAndServe()
gotalkgotalk.jsindex.htmlgotalk.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.connection()on()requestp()gotalk.Handle()async-await
[图片上传失败...(image-bb0d81-1623109177730)]
gotalk.jsgotalk
协议格式
gotalk
gotalk
看一个官方请求的示例:
+------------------ SingleRequest
| +---------------- requestID "0001"
| | +--------- operation "echo" (text3Size 4, text3Value "echo")
| | | +- payloadSize 25
| | | |
r0001004echo00000019{"message":"Hello World"}
r0001004echo00400000019{"message":"Hello World"}00000019
详细格式可以查看官方文档。
使用这种可阅读的格式给问题排查带来了极大的便利。但是在实际使用中,可能需要考虑安全和隐私的问题。
聊天室
examples
animals/jokes/golang
运行:
$ go run server.go
打开浏览器,输入"localhost:1235",显示如下:
[图片上传失败...(image-36fbe0-1623109177730)]
接下来就可以创建房间,在房间聊天了。
整个实现的有几个要点:
gotalk.WebSocketHandler()
gh := gotalk.WebSocketHandler()
gh.OnConnect = onConnect
gotalk.Sock
func onConnect(s *gotalk.WebSocket) {
socksmu.Lock()
defer socksmu.Unlock()
socks[s] = 1
username := randomName()
s.UserData = username
}
gotalk
enableGracefulShutdown()SIGINT
func enableGracefulShutdown(server *http.Server, timeout time.Duration) chan struct{} {
server.RegisterOnShutdown(func() {
// close all connected sockets
fmt.Printf("graceful shutdown: closing sockets\n")
socksmu.RLock()
defer socksmu.RUnlock()
for s := range socks {
s.CloseHandler = nil // avoid deadlock on socksmu (also not needed)
s.Close()
}
})
done := make(chan struct{})
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT)
go func() {
<-quit // wait for signal
fmt.Printf("graceful shutdown initiated\n")
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
server.SetKeepAlivesEnabled(false)
if err := server.Shutdown(ctx); err != nil {
fmt.Printf("server.Shutdown error: %s\n", err)
}
fmt.Printf("graceful shutdown complete\n")
close(done)
}()
return done
}
SIGINTdoneserver.ListenAndServe()http.ErrServerClosed
done := enableGracefulShutdown(server, 5*time.Second)
// Start server
fmt.Printf("Listening on http://%s/\n", server.Addr)
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
panic(err)
}
<- done
整个聊天室功能比较简单,代码也比较短,建议深入理解。在此基础之上做扩展也比较简单。
总结
gotalkgotalk.js
大家如果发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue😄
参考
我
欢迎关注我的微信公众号【GoUpUp】,共同学习,一起进步~