• Stars
    star
    1,223
  • Rank 38,351 (Top 0.8 %)
  • Language
    C#
  • License
    MIT License
  • Created over 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

.NETCore websocket 实现简易、高性能、集群即时通讯组件,支持点对点通讯、群聊通讯、上线下线事件消息等众多实用性功能.

FreeIM 使用 websocket 协议实现简易、高性能(单机支持5万+连接)、集群即时通讯组件,支持点对点通讯、群聊通讯、上线下线事件消息等众多实用性功能。 ImCore 已正式改名为 FreeIM

使用场景:好友聊天、群聊天、直播间、实时评论区、游戏。

如果对本项目感兴趣,欢迎加入 FreeSql QQ讨论群:8578575

dotnet add package FreeIM

ImServer 服务端

public void Configure(IApplicationBuilder app)
{
    app.UseFreeImServer(new ImServerOptions
    {
        Redis = new FreeRedis.RedisClient("127.0.0.1:6379,poolsize=5"),
        Servers = new[] { "127.0.0.1:6001" }, //集群配置
        Server = "127.0.0.1:6001"
    });
}

一套永远不需要迭代更新的 ImServer 服务端,支持 .NET6.0、.NETCore2.1+、NETStandard2.0

WebApi 业务端

public void Configure(IApplicationBuilder app)
{
    //...

    ImHelper.Initialization(new ImClientOptions
    {
        Redis = new FreeRedis.RedisClient("127.0.0.1:6379,poolsize=5"),
        Servers = new[] { "127.0.0.1:6001" }
    });

    ImHelper.EventBus(
        t => Console.WriteLine(t.clientId + "上线了"), 
        t => Console.WriteLine(t.clientId + "下线了"));
}
ImHelper方法 参数 描述
PrevConnectServer (clientId, string) 在终端准备连接 websocket 前调用
SendMessage (发送者, 接收者, 消息内容, 是否回执) 发送消息
GetClientListByOnline - 返回所有在线clientId
HasOnline clientId 判断客户端是否在线
ForceOffline clientId 强制下线
EventBus (上线委托, 离线委托) socket上线与下线事件
频道 参数 描述
JoinChan (clientId, 频道名) 加入
LeaveChan (clientId, 频道名) 离开
GetChanClientList (频道名) 获取频道所有clientId
GetChanList - 获取所有频道和在线人数
GetChanListByClientId (clientId) 获取用户参与的所有频道
GetChanOnline (频道名) 获取频道的在线人数
SendChanMessage (clientId, 频道名, 消息内容) 发送消息,所有在线的用户将收到消息
  • clientId 应该与用户id相同,或者关联;
  • 频道适用临时的群聊需求,如聊天室、讨论区;

ImHelper 支持 .NetFramework 4.5+、.NetStandard 2.0

Html5 终端

终端连接 websocket 前,应该先请求 WebApi 获得授权过的地址(ImHelper.PrevConnectServer),伪代码:

ajax('/prev-connect-imserver', function(data) {
    var url = data; //此时的值:ws://127.0.0.1:6001/ws?token=xxxxx
    var sock = new WebSocket(url);
    sock.onmessage = function (e) {
        //...
    };
})

项目演示

运行环境:.NET6.0 + redis-server 2.8+

cd ImServer && dotnet run --urls=http://*:6001

cd WebApi && dotnet run

打开多个浏览器,分别访问 http://127.0.0.1:5000 发送群消息

image

分析痛点

协议痛点:如果浏览器使用 websocket 协议,iOS 使用其他协议,协议不一致将很难维护。

职责痛点:IM 的系统一般涉及【我的好友】、【我的群】、【历史消息】等等。。

ImServerWebApi(业务方) 该保持何种关系呢?

用户A向好友B发送消息,分析一下:

  • 需要判断B是否为A好友;
  • 需要判断A是否有权限;

获取历史聊天记录,多个 终端 websocket.send('gethistory'),再在 onmessage 定位回调处理,多麻烦啊?

诸如此类业务判断会很复杂,使用 ImServer 做业务逻辑,最终 ImServer终端 都将变成巨无霸难以维护。

设计思路

终端(如浏览器/小程序/iOS/android) 统一使用 websocket 连接 ImServer

ImServer(支持集群)根据 clientId 分区管理 websocket 连接;

WebApi 使用 ImHelper 调用方法(如:SendMessage、群聊相关方法),将数据推至 Redis chan;

ImServer 订阅 Redis chan,收到消息后向 终端 推送消息;

  • 缓解了并发推送消息过多的问题;
  • 解决了连接数过多的问题;
  • 解耦了业务和通讯,架构更加清淅;
    • ImServer 充当消息转发,连接维护,代码万年不变、且不需要重启维护
    • WebApi 负责所有业务

举例1、用户A向B发送消息:终端A ajax -> WebApi -> ImServer -> 终端B websocket.onmessage;

举例2、获取历史聊天记录:终端 请求 WebApi(业务方) 接口,返回json(历史消息)。

举例3、A向B发文件的例子:

  • A向 WebApi 传文件
  • WebApi 通知 ImServer,ImHelper.SendMessage(B, "A正在给传送文件...")
  • B收到消息,A正在给传送文件...
  • WebApi 文件接收完成时通知 ImServer,ImHelper.SendMessage(B, "A文件传输完毕(含文件链接)")
  • B收到消息,A文件传输完毕(含文件链接)

FreeIM 强依赖 redis-server 组件功能:

  • 集成了 redis 轻量级的订阅发布功能,实现消息缓冲发送,后期可更换为其他技术
  • 使用了 redis 存储一些关系数据,如在线 clientId、频道信息、授权信息等

集群分区

单个 ImServer 实例支持多少个客户端连接,3万?如果在线用户有10万人,怎么办???

部署 4 个 ImServer

  • ImServer1 订阅 redisChan1
  • ImServer2 订阅 redisChan2
  • ImServer3 订阅 redisChan3
  • ImServer4 订阅 redisChan4

WebApi(业务方) 根据接收方的 clientId 后四位 16 进制与节点总数取模,定位到对应的 redisChan,进行 redis->publish 操作将消息定位到相应的 ImServer

每个 ImServer 管理着对应的终端连接,当接收到 redis 订阅消息后,向对应的终端连接推送数据。

事件消息

IM 系统比较常用的有上线、下线,在 ImServer 层才能准确捕捉事件,但业务代码不合适在这上面编写了。

此时采用 redis 发布订阅,将上线、下线等事件向指定频道发布,WebApi(业务方) 通过 ImHelper.EventBus 方法进行订阅捕捉。

image

有感而发

为什么说 SignalR 不合适做 IM?

1、IM 的特点必定是长连接,轮训的功能用不上;

2、因为 SignalR 是双工通讯的设计,终端 使用 hub.invoke 发送命令给 SignalR 服务端处理业务,适合用来代替 ajax 减少 http 请求数量;

3、过多使用 hub,SignalR 服务端会被业务入侵,业务变化频繁后不得不重新发布版本,每次部署所有终端都会断开连接,遇到5分钟发一次业务补丁的时候,类似离线和上线提示好友的功能就无法实现;

FreeIM 业务和推送分离设计,终端 连接永不更新重启 ImServer ,业务代码全部在 WebApi 编写,因此重启 WebApi 不会造成连接断开。

💕 Donation (捐赠)

感谢你的打赏

🗄 License (许可证)

MIT

More Repositories

1

csredis

.NET Core or .NET Framework 4.0+ client for Redis and Redis Sentinel (2.8) and Cluster. Includes both synchronous and asynchronous clients.
C#
1,907
star
2

FreeRedis

🦄 FreeRedis is .NET40+ redis client. supports cluster, sentinel, master-slave, pub-sub, lua, pipeline, transaction, streams, client-side-caching, and pooling.
C#
920
star
3

dotnetGen_mysql

.NETCore + Mysql 生成器
C#
242
star
4

FreeSql.Tools

FreeSql 工具包,包括生成器等
C#
212
star
5

FreeSql.AdminLTE

这是一个 .NETCore MVC 中间件,基于 AdminLTE 前端框架动态产生 FreeSql 实体的增删查改界面。
C#
166
star
6

FreeScheduler

轻量化定时任务调度,支持临时的延时任务和重复循环任务(可持久化),可按秒,每天/每周/每月固定时间,自定义间隔执行,支持 .NET Core 2.1+、.NET Framework 4.0+ 运行环境。
C#
164
star
7

dotnetGen_sqlserver

.NETCore + SqlServer 生成器
C#
149
star
8

SafeObjectPool

应用场景:连接池,资源池等等
C#
112
star
9

IdleBus

IdleBus 空闲对象管理容器,有效组织对象重复利用,自动创建、销毁,解决【实例】过多且长时间占用的问题。
C#
107
star
10

dotnetGen_postgresql

.NETCore + PostgreSQL 生成器
C#
94
star
11

NPinyin

拼音汉字转换 .NETCore 版本
C#
80
star
12

FreeSql.Cloud

提供跨数据库访问,分布式事务TCC、SAGA解决方案。
C#
65
star
13

Microsoft.Extensions.Caching.CSRedis

分布式缓存,替代 Microsoft.Extensions.Caching.Redis
C#
44
star
14

FreeSql.DbContext

FreeSql 扩展包,实现真正的 ORM,Repository DbContext UnitOfWork 实现。
C#
41
star
15

FreeSql.DynamicProxy

The dynamic proxy on The .NetCore or .NetFramework4.0+. Support asynchronous method interception, Method parameter interception, Property interception, multiple intercepts, dependency injection and inversion of control
C#
38
star
16

TcpClientHttpRequest

基于 TcpClient 现实的 http请求库,编写于2007年做了几年数据采集工作。
C#
34
star
17

NJob

超级轻便的调度器
C#
30
star
18

FreeSql.Wiki.VuePress

FreeSql wiki 文档采用 vuepress
Dockerfile
30
star
19

MySocket

Socket服务端与客户端的封装(IOCP、EPOLL),支持.NETCore
C#
28
star
20

WorkQueue

超级轻便的线程队列工作器
C#
25
star
21

ojbk

模块化的单体应用项目
JavaScript
21
star
22

dotnetGen

.NET Framework 3.0 + SqlServer 生成器(停止更新)
C#
17
star
23

genms_shop

.NETCore 快速开发做一个简易商城
JavaScript
13
star
24

FreeSql.Connection.Extensions

Mysql, postgresql, sqlserver, Oracle and SQLite connection object extension methods.
C#
10
star
25

dng.Mysql

dotnetgen_mysql生成器所需MySql.Data的基础封装
C#
6
star
26

bmw.js

JavaScript
6
star
27

robot_test

简易任务调度
C#
6
star
28

dotnetGen_demo

dotnetGen 生成后的项目示例
C#
5
star
29

dng.Mssql

dotnetgen_sqlserver生成器所需System.Data.SqlClient的基础封装
C#
4
star
30

oss_signature

阿里云OSS服务端签名后直传,模仿官方get.php代码实现
C#
4
star
31

Spider

爬虫工具,.NET2.0实现
C#
4
star
32

AdminBlazor

AdminBlazor 是一款 Blazor SSR 后台管理项目,支持 RABC 权限菜单/按钮,支持一对一、一对多、多对多代码生成 .razor 界面。
HTML
4
star
33

dng.Pgsql

dotnetgen_postgresql生成器所需npgsql的基础封装
C#
3
star
34

dng.Template

模板引擎,不再使用(作纪念)
C#
3
star
35

cnodejs_netcore

.NETCore + MySql 实现的 cnodejs.org
JavaScript
2
star