什么是Socket.IO?
Socket.io是建立在 WebSocket 之上的一个实时应用程序框架。它封装了 WebSocket,并提供了更高级别的接口,
包括实时事件处理、自动重新连接、多房间支持等功能。Socket.IO 在客户端和服务器端分别有对应的库,简化了实时通信的开发。
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
socketio "github.com/googollee/go-socket.io"
"log"
"net/http"
"net/url"
"strings"
)
func main() {
router := gin.New()
//初始化server
server := socketio.NewServer(nil)
//redis适配器,可选
ok, err := server.Adapter(&socketio.RedisAdapterOptions{
Addr: "127.0.0.1:6379",
Prefix: "socket.io",
Network: "tcp",
})
if err != nil || !ok {
log.Fatal("socket-io adapter error:", err)
}
// 建立连接
server.OnConnect("/", func(s socketio.Conn) error {
//通过query参数获取建立连接的uid
params, _ := url.ParseQuery(s.URL().RawQuery)
uid := params.Get("uid")
s.SetContext(uid)
// 加入一个房间
s.Join("test")
log.Println("建立连接:", s.ID(), uid) //记录连接错误信息
return nil
})
// 连接错误
server.OnError("/", func(s socketio.Conn, e error) {
log.Println("连接错误:", s, e) //记录连接错误信息
})
// 关闭连接
server.OnDisconnect("/", func(s socketio.Conn, reason string) {
s.LeaveAll() //将socket从所有加入的room中移除
if uid := s.Context(); uid != nil {
log.Printf("用户[%s]断开连接", uid)
}
log.Println("关闭连接:", s.ID(), reason)
})
// ”notice“事件
server.OnEvent("/", "notice", func(s socketio.Conn, msg string) {
log.Println("notice收到内容::", msg)
s.Emit("notice", "have "+msg) // 向client回复内容
})
router.GET("/bcast", func(context *gin.Context) {
// 向房间内的所有人员发消息
server.BroadcastToRoom("/", "test", "notice", "广播通知")
})
//----------------------------------end----------------------------------
go server.Serve()
defer server.Close()
router.Use(gin.Recovery(), Cors())
router.GET("/socket.io/*any", gin.WrapH(server))
router.POST("/socket.io/*any", gin.WrapH(server))
router.Static("/public", "./websocket")
if err := router.Run(":9100"); err != nil {
log.Fatal("failed run app: ", err)
}
}
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method // 请求方法
origin := c.Request.Header.Get("Origin") // 请求头部
var headerKeys []string // 声明请求头keys
for k, _ := range c.Request.Header {
headerKeys = append(headerKeys, k)
}
headerStr := strings.Join(headerKeys, ", ")
if headerStr != "" {
headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
} else {
headerStr = "access-control-allow-origin, access-control-allow-headers"
}
if origin != "" {
c.Header("Access-Control-Allow-Origin", origin) // 这是允许访问所有域
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") // 服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
// header的类型
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
// 允许跨域设置 可以返回其他子段
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析
c.Header("Access-Control-Max-Age", "172800") // 缓存请求信息 单位为秒
c.Header("Access-Control-Allow-Credentials", "true") // 跨域请求是否需要带cookie信息 默认设置为true
c.Set("content-type", "application/json") // 设置返回格式是json
}
// 放行所有OPTIONS方法
if method == "OPTIONS" {
c.JSON(http.StatusOK, "Options Request!")
}
// 处理请求
c.Next() // 处理请求
}
}
建立websocket文件夹,并新建 index.html
<html lang="cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>WebSocket</title>
<!-- <script type="text/javascript" src="https://cdn.socket.io/4.4.1/socket.io.js"></script>-->
<script type="text/javascript" src="socket.io.js"></script>
</head>
<body>
<h1> socket.io Client</h1>
<input id="sendTxt" type="text"/>
<button id="sendBtn">发送</button>
<div id="recv"></div>
<script type="text/javascript">
var socket = io("ws://192.168.252.128:9100?uid=zhangsan");
//把接收的数据显示到界面
function showMessage(str){
var div = document.createElement('div');
div.innerHTML = str;
document.body.appendChild(div)
}
// 点击之后发送
document.getElementById("sendBtn").onclick = function(){
var txt = document.getElementById("sendTxt").value;
if(txt){ // 文本不为空发送
socket.emit('notice',txt);
}
}
// 连接成功
socket.on('connect', function(socket){
showMessage("连接成功")
});
// 连接失败
socket.on('disconnect', function(socket){
showMessage("连接失败")
});
socket.on('error', function(socket){
showMessage("连接错误")
});
socket.on('notice',function(data){
console.log("receive server data",data);
showMessage(data)
})
</script>
</body>
</html>