go 使用websocket
package chat
import (
"encoding/json"
"github.com/gorilla/websocket"
"github.com/zeromicro/go-zero/core/logx"
"log"
"net/http"
"sync"
)
type Client struct {
conn *websocket.Conn
messageQueue chan []byte
mu sync.Mutex
user string
}
func NewClient(user string, conn *websocket.Conn) *Client {
return &Client{
conn: conn,
user: user,
messageQueue: make(chan []byte, 100),
}
}
func (c *Client) ReadPump() {
defer func() {
c.conn.Close()
}()
for {
mt, message, err := c.conn.ReadMessage()
if err != nil {
log.Println("read:", err)
manager.mu.Lock()
delete(manager.clients, c.user)
_ = c.conn.Close()
manager.mu.Unlock()
break
}
if mt == websocket.TextMessage || mt == websocket.PingMessage {
c.mu.Lock()
c.messageQueue <- message
c.mu.Unlock()
}
}
}
func Send(user string, returnMessage []byte, logger logx.Logger) {
manager.mu.RLock()
client, exists := manager.clients[user]
manager.mu.RUnlock()
if !exists {
logger.Infof("client not found for user:%s message:%s", user, string(returnMessage))
return
}
client.mu.Lock()
err := client.conn.WriteMessage(websocket.TextMessage, returnMessage)
client.mu.Unlock()
if err != nil {
logger.Errorf("client.conn.WriteMessage error %s", err.Error())
// 主动从 manager 中移除无效连接
manager.mu.Lock()
delete(manager.clients, user)
manager.mu.Unlock()
_ = client.conn.Close()
}
}
type ClientManager struct {
clients map[string]*Client
mu sync.RWMutex
}
var manager = ClientManager{
clients: make(map[string]*Client),
}
func ChatWebsocketHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
logger := logx.WithContext(r.Context())
if err != nil {
logger.Errorf("upgrade:%+v", err)
return
}
// 假设前端会发送一个用户 ID 或会话 ID 用于识别连接
user := r.URL.Query().Get("user")
if user == "" {
logger.Errorf("user is empty:")
_ = conn.Close()
return
}
client := NewClient(user, conn)
// 将新的连接存储到连接管理器中
manager.mu.Lock()
oldClient, exists := manager.clients[user]
if exists {
// 关闭旧的连接
_ = oldClient.conn.Close()
}
manager.clients[user] = client
manager.mu.Unlock()
go client.ReadPump()
l := chat.NewChatWebsocketLogic(r.Context(), svcCtx)
for {
select {
case message := <-client.messageQueue:
var req types.ChatWebsocketRequest
_ = json.Unmarshal(message, &req)
if req.Heartbeat {
// 处理心跳消息
err = client.conn.WriteMessage(websocket.PongMessage, []byte(""))
if err != nil {
logger.Errorf("write pong message failed:", err)
manager.mu.Lock()
delete(manager.clients, user)
manager.mu.Unlock()
_ = client.conn.Close()
return
}
returnMessage, _ := json.Marshal(true)
Send(user, returnMessage, logger)
continue
}
channel := make(chan string, 50)
go func() {
defer func() {
close(channel)
close(baseInfoCh)
}()
res := &types.ChatWebsocketResponse{}
res, errChat := l.ChatWebsocket(&req, channel, baseInfoCh)
if errChat != nil {
logger.Error("ChatWebsocketHandler error :", errChat)
res.ErrorMessage = response.GetErrorMessage(errChat)
}
returnMessage, _ := json.Marshal(res)
Send(user, returnMessage, logger)
}()
var rs []rune
length := 1
for {
s, ok := <-channel
if !ok {
if len(rs) > 0 {
SendSocketMessage(string(rs), req.MessageId)
rs = []rune{}
}
break
}
rs = append(rs, []rune(s)...)
if len(rs) > length {
SendSocketMessage(string(rs), req.MessageId)
rs = []rune{}
if length < 4 {
length++
}
}
}
}
}
}
}
func SendSocketMessage(message, messageId string) {
baseReturn := &types.ChatWebsocketResponse{}
returnMessage, _ := json.Marshal(types.ChatWebsocketResponse{
Message: message,
MessageId: messageId,
})
Send(user, returnMessage, logger)
}
go 使用websocket的更多相关文章
- 漫扯:从polling到Websocket
Http被设计成了一个单向的通信的协议,即客户端发起一个request,然后服务器回应一个response.这让服务器很为恼火:我特么才是老大,我居然不能给小弟发消息... 轮询 老大发火了,小弟们自 ...
- 细说WebSocket - Node篇
在上一篇提高到了 web 通信的各种方式,包括 轮询.长连接 以及各种 HTML5 中提到的手段.本文将详细描述 WebSocket协议 在 web通讯 中的实现. 一.WebSocket 协议 1. ...
- java使用websocket,并且获取HttpSession,源码分析
转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...
- WebSocket - ( 一.概述 )
说到 WebSocket,不得不提 HTML5,作为近年来Web技术领域最大的改进与变化,包含CSS3.离线与存储.多媒体.连接性( Connectivity )等一系列领域,而即将介绍的 WebSo ...
- php+websocket搭建简易聊天室实践
1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...
- Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...
- Cowboy 开源 WebSocket 网络库
Cowboy.WebSockets 是一个托管在 GitHub 上的基于 .NET/C# 实现的开源 WebSocket 网络库,其完整的实现了 RFC 6455 (The WebSocket Pro ...
- 借助Nodejs探究WebSocket
文章导读: 一.概述-what's WebSocket? 二.运行在浏览器中的WebSocket客户端+使用ws模块搭建的简单服务器 三.Node中的WebSocket 四.socket.io 五.扩 ...
- 细说websocket - php篇
下面我画了一个图演示 client 和 server 之间建立 websocket 连接时握手部分,这个部分在 node 中可以十分轻松的完成,因为 node 提供的 net 模块已经对 socket ...
- webSocket and LKDBHelper的使用说明
socketket与lkdbhelper来处理数据 客户需求: 当我们有需要从自己的后台推送消息给我们的用户时,用户需要实时的接收到来自我们的推送消息.前提是没有使用第三方的推送框架,那么这个使用we ...
随机推荐
- Vite本地构建:手写核心原理
前言 接上篇文章,我们了解到vite的本地构建原理主要是:启动一个 connect 服务器拦截由浏览器请求 ESM的请求.通过请求的路径找到目录下对应的文件做一下编译最终以 ESM的格式返回给浏览器. ...
- uniapp打包所需的ios证书和证书profile文件获取的图文教程
使用uniapp进行云打包,可以打包android和ios两种app,但是uniapp官方并不能凭空产生这两种平台所需的打包证书. 那么这两种打包证书又是如何获取呢? android相对简单,使用jd ...
- python selenium元素定位
1.ID元素定位基于元素属性中的id的值来进行定位,id是一个标签的唯一属性值可以通过id属性来唯一定位一个元素,是首选的元素定位方式,动态ID不做考虑.driver .find_element_by ...
- Fiddler使用界面介绍-底部状态栏
底部状态栏 1.Capturing抓包状态 Capturing:Fiddler正在抓包 空白:Fiddler停止抓包 2.All Processes抓取进程类型 All Processes:抓取所有进 ...
- 初看vue3源码
因为工作的原因又回到了vue的领域,需要加深对vue和vue生态的了解 也许平时比较多人手机看别人解析怎么看vue源码的,自己动手看vue源码的还是比较少,这次我想自己动手看看 首先 吧代码获取到本地 ...
- 【H5】08 图片
摘自: https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Multimedia_and_embedding 在这份教程中,到目前为止我们已经看到了 ...
- 【Git】下载安装(Linux)
安装CentOS8貌似有自带Git 可以先查看一下有没有 git --version 有或者没有都行,有的话安装就当是更新 没有就装,yum提供了安装,我们不需要自己压缩包安装了 yum instal ...
- 【Vue】Re23 组件封装
视频地址: https://www.bilibili.com/video/BV15741177Eh?p=119 common.css /* 演示案例是base.css */ body { paddin ...
- 横扫鸿蒙弹窗乱象,SmartDialog出世
前言 但凡用过鸿蒙原生弹窗的小伙伴,就能体会到它们是有多么的难用和奇葩,什么AlertDialog,CustomDialog,SubWindow,bindXxx,只要大家用心去体验,就能发现他们有很多 ...
- 获取Windows个性化中自带的聚焦锁屏
想要保存登录屏幕(锁屏界面)的背景图片,可以通过以下脚本一键获取: @echo off setlocal enabledelayedexpansion :: Windows Spotlight 锁屏图 ...