关于websocket:gin-websocket-一对一聊天

34次阅读

共计 4686 个字符,预计需要花费 12 分钟才能阅读完成。

依赖包

github.com/gin-gonic/gin
github.com/gorilla/websocket

代码

创立 ws/ws.go

package ws

import (
    "encoding/json"
    "github.com/gin-gonic/gin"
    "github.com/gorilla/websocket"
    "log"
    "net/http"
)

// ClientManager is a websocket manager
type ClientManager struct {Clients    map[string]*Client
    Broadcast  chan []byte
    Register   chan *Client
    Unregister chan *Client
}

// Client is a websocket client
type Client struct {
    ID     string
    Socket *websocket.Conn
    Send   chan []byte}

// Message is return msg
type Message struct {
    Sender    string `json:"sender,omitempty"`
    Recipient string `json:"recipient,omitempty"`
    Content   string `json:"content,omitempty"`
}

// Manager define a ws server manager
var Manager = ClientManager{Broadcast:  make(chan []byte),
    Register:   make(chan *Client),
    Unregister: make(chan *Client),
    Clients:    make(map[string]*Client),
}

// Start is  我的项目运行前, 协程开启 start -> go Manager.Start()
func (manager *ClientManager) Start() {
    for {log.Println("<--- 管道通信 --->")
        select {
        case conn := <-Manager.Register:
            log.Printf("新用户退出:%v", conn.ID)
            Manager.Clients[conn.ID] = conn
            jsonMessage, _ := json.Marshal(&Message{Content: "Successful connection to socket service"})
            conn.Send <- jsonMessage
        case conn := <-Manager.Unregister:
            log.Printf("用户来到:%v", conn.ID)
            if _, ok := Manager.Clients[conn.ID]; ok {jsonMessage, _ := json.Marshal(&Message{Content: "A socket has disconnected"})
                conn.Send <- jsonMessage
                close(conn.Send)
                delete(Manager.Clients, conn.ID)
            }
        case message := <-Manager.Broadcast:
            MessageStruct :=Message{}
            json.Unmarshal(message, &MessageStruct)
            for id, conn := range Manager.Clients {if id!=creatId(MessageStruct.Recipient,MessageStruct.Sender){continue}
                select {
                case conn.Send <- message:
                default:
                    close(conn.Send)
                    delete(Manager.Clients, conn.ID)
                }
            }
        }
    }
}
func creatId(uid,touid string) string {return uid+"_"+touid}
func (c *Client) Read() {defer func() {
        Manager.Unregister <- c
        c.Socket.Close()}()

    for {c.Socket.PongHandler()
        _, message, err := c.Socket.ReadMessage()
        if err != nil {
            Manager.Unregister <- c
            c.Socket.Close()
            break
        }
        log.Printf("读取到客户端的信息:%s", string(message))
        Manager.Broadcast <- message
    }
}

func (c *Client) Write() {defer func() {c.Socket.Close()
    }()

    for {
        select {
        case message, ok := <-c.Send:
            if !ok {c.Socket.WriteMessage(websocket.CloseMessage, []byte{})
                return
            }
            log.Printf("发送到到客户端的信息:%s", string(message))

            c.Socket.WriteMessage(websocket.TextMessage, message)
        }
    }
}

//TestHandler socket 连贯 中间件 作用: 降级协定, 用户验证, 自定义信息等
func WsHandler(c *gin.Context) {uid := c.Query("uid")
    touid := c.Query("to_uid")
    conn, err := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {return true}}).Upgrade(c.Writer, c.Request, nil)
    if err != nil {http.NotFound(c.Writer, c.Request)
        return
    }
    // 能够增加用户信息验证
    client := &Client{ID:    creatId(uid,touid),
        Socket: conn,
        Send:   make(chan []byte),
    }
    Manager.Register <- client
    go client.Read()
    go client.Write()}

创立 main.go

package main

import (
    "github.com/gin-gonic/gin"
    "im/ws"
)

//server
func main() {gin.SetMode(gin.ReleaseMode) // 线上环境

    go ws.Manager.Start()
    r := gin.Default()
    r.GET("/ws",ws.WsHandler)
    r.GET("/pong", func(c *gin.Context) {
        c.JSON(200, gin.H{"message": "pong",})
    })
    r.Run(":8282") // listen and serve on 0.0.0.0:8080
}

运行服务端

go  run  mian.go

创立 client.html

<html>
<head>
    <title>Golang Chat</title>

<script src="http://libs.baidu.com/jquery/1.4.2/jquery.min.js"></script>
<meta charset="UTF-8" />
    <script type="text/javascript">
    
        $(function() {function getUrlParam(name)
            {var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)"); // 结构一个含有指标参数的正则表达式对象
                var r = window.location.search.substr(1).match(reg);  // 匹配指标参数
                if (r!=null) return unescape(r[2]); return null; // 返回参数值
            }
            var conn;
            var msg = $("#msg");
            var log = $("#log");
            uid=getUrlParam("uid");
            to_uid=getUrlParam("to_uid");

            function appendLog(msg) {var d = log[0]
                var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
                msg.appendTo(log)
                if (doScroll) {d.scrollTop = d.scrollHeight - d.clientHeight;}
            }

            $("#form").submit(function() {if (!conn) {return false;}
                if (!msg.val()) {return false;}
                var json = {"sender":uid,"recipient":to_uid,"content":msg.val()}; // 创建对象;var jsonStr = JSON.stringify(json);       // 转为 JSON 字符串

                conn.send(jsonStr);
                msg.val("");
                return false
            });

            if (window["WebSocket"]) {conn = new WebSocket("ws://localhost:8282/ws?uid="+uid+"&to_uid="+to_uid);
                conn.onclose = function(evt) {appendLog($("<div><b>Connection Closed.</b></div>"))
                }
                conn.onmessage = function(evt) {appendLog($("<div/>").text(evt.data))
                }
            } else {appendLog($("<div><b>WebSockets Not Support.</b></div>"))
            }
        });
    </script>
    <style type="text/css">
        html {overflow: hidden;}

        body {
            overflow: hidden;
            padding: 0;
            margin: 0;
            width: 100%;
            height: 100%;
            background: gray;
        }

        #log {
            background: white;
            margin: 0;
            padding: 0.5em 0.5em 0.5em 0.5em;
            position: absolute;
            top: 0.5em;
            left: 0.5em;
            right: 0.5em;
            bottom: 3em;
            overflow: auto;
        }

        #form {
            padding: 0 0.5em 0 0.5em;
            margin: 0;
            position: absolute;
            bottom: 1em;
            left: 0px;
            width: 100%;
            overflow: hidden;
        }

    </style>
</head>
<body>
<div id="log"></div>
<form id="form">
    <input type="submit" value="发送" />
    <input type="text" id="msg" size="64"/>
</form>
</body>
</html>

本人搭建 nginx 或 apache 等 web 服务,别离在两个窗口运行

http://localhost/client.html?…

http://localhost/client.html?…

这样就能够聊天了

links

  • 目录
  • 上一节:
  • 下一节:

正文完
 0