Go语言开发im-websocket服务和vue3+ts开发类似微信pc即时通讯

前言

IM即时通讯聊天, 为软件开发者打造,不依赖第三方sdk,完全用Go语言开发即时通讯服务,支持H5、Electron、Wails 、Uniapp和各种小程序的IM即时通讯, 快速实现私聊、群聊、在线客服!让你快速搭建一个微信聊天系统,打造一个类微信聊天应用。

内容如下:

  • 完全基于GoFly框架开发即时通讯服务器,不依赖第三方即时通讯SDK,减少维护成本。
  • 支持gofly管理后台、H5、Electron、Wails 、Uniapp和各种小程序的IM即时通讯
  • 一对一单聊
  • 群聊
  • 在线客服
  • 发送内容支持文本、图片、附件(zip、text、word...)音频、视频等

后端选择技术栈:

  • 开发语言:Golang
  • 基础框架:Gin
  • 集成框架:GoFly快速开发框架
  • 数据库:mysql(可迁移PostgreSQL、SQL-Server、oracle)

前端选择技术栈:

  • 脚手架搭建:vite

  • web框架:vue3

  • 前端语言:TypeScript 

  • 前端UI:ArcoDesign

通讯协议:

即时通讯协议:websocket,通讯核心代码如下:

  • Go服务端代码:
package websocketimport ("fmt""net/http""sync""time""github.com/gorilla/websocket"
)var (// 消息通道news = make(map[string]chan interface{})// websocket客户端链接池client = make(map[string]*websocket.Conn)// 互斥锁,防止程序对统一资源同时进行读写mux sync.Mutex
)// websocket Upgrader
var wsupgrader = websocket.Upgrader{ReadBufferSize:   1024,WriteBufferSize:  1024,HandshakeTimeout: 5 * time.Second,// 取消ws跨域校验CheckOrigin: func(r *http.Request) bool {return true},
}// WsHandler 处理ws请求
func WsHandler(w http.ResponseWriter, r *http.Request, id string) {var conn *websocket.Connvar err errorvar exist bool// 创建一个定时器用于服务端心跳pingTicker := time.NewTicker(time.Second * 10)conn, err = wsupgrader.Upgrade(w, r, nil)if err != nil {fmt.Println("处理ws请求错误", err)return}// 把与客户端的链接添加到客户端链接池中addClient(id, conn)// 获取该客户端的消息通道m, exist := getNewsChannel(id)if !exist {m = make(chan interface{})addNewsChannel(id, m)}// 设置客户端关闭ws链接回调函数conn.SetCloseHandler(func(code int, text string) error {deleteClient(id)fmt.Println("端关闭ws链接回调函数错误", code)return nil})for {select {case content, _ := <-m:// 从消息通道接收消息,然后推送给前端fmt.Println("从消息通道接收消息:", content)err = conn.WriteJSON(content)if err != nil {fmt.Println("推送给前端数错误", err)conn.Close()deleteClient(id)return}case <-pingTicker.C:// 服务端心跳:每20秒ping一次客户端,查看其是否在线conn.SetWriteDeadline(time.Now().Add(time.Second * 20))err = conn.WriteMessage(websocket.PingMessage, []byte{})if err != nil {fmt.Println("send ping err:", err)conn.Close()deleteClient(id)return}}}
}// 将客户端添加到客户端链接池
func addClient(id string, conn *websocket.Conn) {mux.Lock()client[id] = connmux.Unlock()
}// 获取指定客户端链接
func getClient(id string) (conn *websocket.Conn, exist bool) {mux.Lock()conn, exist = client[id]mux.Unlock()return
}// 删除客户端链接
func deleteClient(id string) {mux.Lock()delete(client, id)fmt.Println("websocket退出:", id)mux.Unlock()
}// 添加用户消息通道
func addNewsChannel(id string, m chan interface{}) {mux.Lock()news[id] = mmux.Unlock()
}// 获取指定用户消息通道
func getNewsChannel(id string) (m chan interface{}, exist bool) {mux.Lock()m, exist = news[id]mux.Unlock()return
}// 删除指定消息通道
func deleteNewsChannel(id string) {mux.Lock()if m, ok := news[id]; ok {close(m)delete(news, id)}mux.Unlock()
}// 1.对点消息推送
func SetMessage(id string, content interface{}) {mux.Lock()if m, exist := news[id]; exist {go func() {m <- content}()}mux.Unlock()
}// 2.群发消息
func SetMessageAllClient(content interface{}) {mux.Lock()all := newsmux.Unlock()go func() {for _, m := range all {m <- content}}()}
  •  前端ts代码:
// WebSocket链接工具
import {  onUnmounted } from 'vue';interface WebSocketOptions {url: string;protocols?: string | string[];reconnectTimeout?: number;
}class WebSocketService {private ws: WebSocket | null = null;private callbacks: { [key: string]: Function[] } = {};private reconnectTimeoutMs: number = 5000; // 默认5秒重连间隔constructor(private options: WebSocketOptions) {}//实现断线重连private reconnectAttempts = 0;private maxReconnectAttempts = 5;public open(): void {if(!this.ws){this.ws = new WebSocket(this.options.url, this.options.protocols)this.ws.addEventListener('open', this.handleOpen);this.ws.addEventListener('message', this.handleMessage);this.ws.addEventListener('error', this.handleError);this.ws.addEventListener('close', this.handleClose);//为了保持连接的稳定性,我们可以添加心跳机制this.startHeartbeat();}}//连接public connect(url:any): void {if(url){this.options.url=urlthis.open();}else{console.error("请传url链接地址")}}public close(isActiveClose = false): void {if (this.ws) {this.ws.close();if (!isActiveClose) {setTimeout(() => this.reconnect(), this.reconnectTimeoutMs);}}}//重连public reconnect(): void {if (this.reconnectAttempts < this.maxReconnectAttempts) {this.reconnectAttempts++;console.log(`尝试重新连接... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);setTimeout(() => {this.open();}, this.reconnectTimeoutMs);} else {console.error('达到最大重连次数,连接失败');}}public on(event: 'message', callback: (data: any) => void): void;public on(event: 'open' | 'error' | 'close', callback: () => void): void;public on(event: string, callback: (...args: any[]) => void): void {if (!this.callbacks[event]) {this.callbacks[event] = [];}this.callbacks[event].push(callback);}private handleOpen = (): void => {console.log('WebSocket连接已建立');if (this.callbacks.open) {this.callbacks.open.forEach((cb) => cb());}//实现断线重连this.reconnectAttempts = 0;this.startHeartbeat();};private handleMessage = (event: MessageEvent): void => {const data = JSON.parse(event.data);// console.log('WebSocket接收到消息:', data);if (this.callbacks.message) {this.callbacks.message.forEach((cb) => cb(data));}};private handleError = (error: Event): void => {console.error('WebSocket错误:', error);if (this.callbacks.error) {this.callbacks.error.forEach((cb) => cb(error));}};private handleClose = (): void => {console.log('WebSocket连接已关闭');//实现断线重连this.ws=nullthis.stopHeartbeat();this.reconnect();if (this.callbacks.close) {this.callbacks.close.forEach((cb) => cb());if (!this.options.reconnectTimeout) {this.reconnect();}}};public send(data: any): void {if (this.ws && this.ws.readyState === WebSocket.OPEN) {this.ws.send(JSON.stringify(data));} else {console.warn('尝试发送消息时WebSocket未连接');}}//添加心跳机制private heartbeatTimer: any | null = null;private heartbeatInterval = 30000; // 30秒private startHeartbeat() {this.heartbeatTimer = setInterval(() => {this.send({ type: 'heartbeat' });}, this.heartbeatInterval);}private stopHeartbeat() {if (this.heartbeatTimer) {clearInterval(this.heartbeatTimer);this.heartbeatTimer = null;}}}export default function useWebSocket(options: WebSocketOptions) {const wsService = new WebSocketService(options);onUnmounted(() => {wsService.close(true);});return {open: wsService.open.bind(wsService),connect: wsService.connect.bind(wsService),close: wsService.close.bind(wsService),reconnect: wsService.reconnect.bind(wsService),on: wsService.on.bind(wsService),send: wsService.send.bind(wsService)};}

效果示例

完整代码下载

去下载完整代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/142191.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

浅谈住房城乡建设部科技创新平台布局重点方向

最近住房建设部组织开展住房城乡建设部科技创新平台&#xff08;以下简称部科技创新平台&#xff09;申报工作。详细内容见住房城乡建设部科技创新平台开始申报了 (qq.com)。在这里有4大方向共15个课题。内容见下图&#xff1a; 虽然我是做技术的&#xff0c;但是如何体现创新还…

mycat双主高可用架构部署-水评分表-枚举分片配置

MySQL5.7服务器IP是192.168.31.209及192.168.31.210 vi /usr/local/mycat/conf/schema.xml <?xml version"1.0"?> <!DOCTYPE mycat:schema SYSTEM "schema.dtd"> <mycat:schema xmlns:mycat"http://io.mycat/"><schema n…

AI赋能:无人直播新赛道,防封号、不限流,打造24小时流量引擎!

AI赋能&#xff1a;无人直播新赛道&#xff0c;防封号、不限流&#xff0c;打造24小时流量引擎&#xff01; 在数字化浪潮的推动下&#xff0c;直播行业正经历着前所未有的变革。传统直播模式受限于主播的实时参与、时间和地域的局限&#xff0c;难以满足日益增长的多元化需求。…

java技术栈介绍

Java技术栈是一个庞大而丰富的生态系统&#xff0c;它包含了从基础语言特性到高级框架、库和工具的整个集合。这个技术栈为开发者提供了构建各种类型应用&#xff08;包括企业级应用、Web应用、移动应用、大数据应用等&#xff09;所需的全部组件。以下是对Java技术栈的一个更详…

Windows 上下载、编译 OpenCV 并配置系统环境变量的详细步骤

创作不易&#xff0c;您的打赏、关注、点赞、收藏和转发是我坚持下去的动力&#xff01; 在 Windows 上下载并编译 OpenCV&#xff0c;然后配置系统环境变量的步骤如下&#xff1a; 1. 下载 OpenCV 打开 OpenCV 官方下载页面。找到最新的 Windows 版本&#xff0c;点击下载&…

[产品管理-23]:NPDP新产品开发 - 21 - 产品创新中的市场调研 - 市场调研对创新产品开发的意义

目录 前言&#xff1a; 一、市场调研概述 1.1 客户与市场的区别 1、定义与范围 2、关注焦点 3、作用与影响 4、总结 1.2 销售与市场的区别 1、对象与范围 2、工作方式 3、工作内容 4、目标 5、考核标准 6、在企业运营中的角色 1.3 什么是市场调研 1、市场调研的…

[Python]用Nuitka将 Python 脚本打造为独立高效的可执行文件

nuitka --onefile --ltoyes --standalone --show-modules --show-memory --nofollow-import-tomatplotlib --nofollow-import-toscipy --nofollow-import-topygame --nofollow-import-topyarrow --nofollow-import-tosqlalchemy --nofollow-import-topandas PDF信息提取-含界面…

GUI编程13:JDialog弹窗

视频链接&#xff1a;15、JDialog弹窗_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1DJ411B75F?p15&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 package com.yundait.lesson04;import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; im…

双亲委派机制知识点

类加载器 双亲委派模型 为什么采用双亲委派模型 打破双亲委派机制的场景 Tomcat 打破双亲委派机制:目的是可以加载不同版本的jar包 实现类隔离&#xff1a;在Tomcat中&#xff0c;每个Web应用使用独立的类加载器加载类文件&#xff0c;这样做的好处在于&#xff0c;当在同一T…

【自动化测试】移动app的分层测试以及自动遍历的基本概念

引言 移动应用的分层测试是一种系统化的测试方法&#xff0c;它将测试过程分解为不同的层次&#xff0c;以确保应用在每个层面上都符合设计要求和用户期望 文章目录 引言一、移动app的分层测试1.1 单元测试&#xff08;Unit Testing&#xff09;1.2 集成测试&#xff08;Integr…

k8s集群备份与迁移

什么是 Velero? Velero 是一个用Go语言开发的开源工具&#xff0c;用于 Kubernetes 集群的备份、恢复、灾难恢复和迁移。 Velero备份工作流程 当用户发起velero backup create时&#xff0c;会执行如下四个动作&#xff1a; velero客户端调用Kubernetes API创建自定义资源并…

用于稀疏自适应深度细化的掩码空间传播网络 CVPR2024

目录 Masked Spatial Propagation Network for Sparsity-Adaptive Depth Refinement &#xff08;CVPR 2024&#xff09;用于稀疏自适应深度细化的掩码空间传播网络1 介绍2 算法流程2.1 问题建模2.2 Guidance Network2.3 MSPN 模块 3 实验结果3.1 稀疏度自适应深度细化对比试验…

背包问题(如何定义dp状态)

前言&#xff1a;我们要如何定义dp的定义呢&#xff0c;我们不能像正常那样&#xff0c;定义为花费了 i 钱得到的最大收益&#xff0c;我们这一题需要的是收益为 i 的时候的最小花费&#xff0c;那么我们就需要定义为达到收益为 v 的时候的最小花费 这一题有一个难点就是&#…

C++初阶:STL详解(三)——vector的介绍和使用

✨✨小新课堂开课了&#xff0c;欢迎欢迎~✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C&#xff1a;由浅入深篇 小新的主页&#xff1a;编程版小新-CSDN博客 前言&#xff1a; 前面我们刚刚了解了strin…

VTD激光雷达(2)——02_OptiX_Lidar

BRDF公式计算强度&#xff0c;关键是材料 表面凹凸不平可以在三维模型中建立 &#xff1b;一般是建模是平的&#xff0c;在软件中设置 第二章图片有水 问题PBR和非PBR的区别

【Linux】-基本指令(上)

&#x1f511;&#x1f511;博客主页&#xff1a;阿客不是客 &#x1f353;&#x1f353;系列专栏&#xff1a;深入代码世界&#xff0c;了解掌握 Linux 欢迎来到泊舟小课堂 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 与Windows环境不同&#xff0c;我们…

【算法】动态规划—最长公共子序列

最长公共子序列问题就是求出两个字符串的LCS长度&#xff0c;是一道非常经典的面试题目&#xff0c;因为它的解法是典型的二维动态规划。 比如输入 str1 "babcde", str2 "acbe"&#xff0c;算法应该输出3&#xff0c;因为 str1 和 str2 的最长公共子序列…

视频格式转为mp4(使用ffmpeg)

1、首先安装ffmpeg&#xff0c;下载链接如下 https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-6.1.1-full_build.7z 安装后确保ffmpeg程序加到PATH路径里&#xff0c;cmd执行ffmpeg -version出现下图内容表示安装成功。 2、粘贴下面的脚本到文本文件中&#xff0c;文件后缀…

基于对数变换的图像美白增强,Matlab实现

博主简介&#xff1a;matlab图像处理&#xff08;QQ:3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于对数变换的图像美白增强&#xff0c;用matlab实现。 一、案例背景和算法介绍 这次案例是美白算法&…

re题(20)BUUCTF [GWCTF 2019]pyre

BUUCTF在线评测 (buuoj.cn) Python解包及反编译: PyInstaller Extractoruncompyle6 - 知乎 (zhihu.com) python撤消&#xff1a; Pycharm撤销操作和代码跳转后退回操作以及消除波浪线操作快捷键_pycharm怎么反撤销-CSDN博客 把.pyc文件变成py文件 把.py文件用记事本打开 cod…