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 ...
随机推荐
- 斯坦福AI团队被质疑抄袭国产大模型
原文地址: https://mbd.baidu.com/newspage/data/landingsuper?context={"nid"%3A"news_8882699 ...
- 【转载】 EdgeX Foundry试运行
原文地址: https://www.cnblogs.com/charlieroro/p/14843335.html ========================================== ...
- js 实现俄罗斯方块(三)
我又来啦!上一篇有点水,本篇我们来干货! 嘿嘿,首先我们先搭建游戏世界------网格 所有的操作包括左移右移下移旋转都是在这个网格中 既然是使用js来写当然跑不了html啦,实现网格最简单的 方法就 ...
- CSV文件导出详细讲解
一.准备jar 如下所以放入maven配置文件中 二.controller层 三.SERVICE层 四.CsvUtil文件 /** * csv文件导入导出 */public class CsvUti ...
- SMU 2024 spring 天梯赛自主训练2
SMU 2024 spring 天梯赛自主训练2 7-1 I Love GPLT - SMU 2024 spring 天梯赛自主训练2 (pintia.cn) PHP 点击查看代码 I L o v e ...
- dubbo服务治理(一)降级
在线网站一般都会有服务器压力剧增的时候,比如说网上商城的促销,这个时候常用的手段就是服务降级,根据当前业务情况及流量对一些服务和页面有策略的降级,以此缓解了服务器资源压力,以保证核心任务的正常运行,同 ...
- Linux信号量(3)-内核信号量
概念 Linux内核的信号量在概念和原理上和用户态的System V的IPC机制信号量是相同的,不过他绝不可能在内核之外使用,因此他和System V的IPC机制信号量毫不相干. 如果有一个任务想要获 ...
- 使用 preloadComponents 进行组件预加载
title: 使用 preloadComponents 进行组件预加载 date: 2024/8/18 updated: 2024/8/18 author: cmdragon excerpt: 摘要: ...
- python模块xlsxwriter使用
1.安装 pip install XlsxWriter 2.使用 # -*- coding: utf-8 -*- from io import BytesIO import qrcode # impo ...
- Linux下常用组件镜像源、smaba、gcc、ssh、mysql安装
Linux安装 博主使用的是ubuntu 16.04 apt更换镜像源 这里以更换阿里云镜像源为例. 首先去阿里云官方网站找对应版本系统的镜像源https://developer.aliyun.com ...