Git Product home page Git Product logo

freeim's Introduction

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 服务端,支持 .NET8.0 AOT 发布(C++运行时)。

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

freeim's People

Contributors

2881099 avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

freeim's Issues

服务端出现多条上线、下线通知

服务端部署在云服务器上,项目在本地调试好好的,但项目发布到imserver所在服务器上后,用户上线、下线通知在服务端会看到很多条(第1次看到7条,关闭后重启服务和项目,看到10条)
5215

压测时候出现大量超时错误

日志是这样的:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
System.TimeoutException: SafeObjectPool.Get 获取超时(10秒)。
   at SafeObjectPool.ObjectPool`1.Get(Nullable`1 timeout)
   at CSRedis.CSRedisClient.GetAndExecute[T](RedisClientPool pool, Func`2 handler, Int32 jump, Int32 errtimes)
   at CSRedis.CSRedisClient.ExecuteScalar[T](String key, Func`3 hander)
   at CSRedis.CSRedisClient.HKeys(String key)
   at ImClient.GetChanListByClientId(Guid clientId) in D:\code\TT\001_src\im\ImCore\ImClient.cs:line 256
   at ImServer.Acceptor(HttpContext context, Func`1 next) in D:\code\TT\001_src\im\ImCore\ImServer.cs:line 116
   at Microsoft.AspNetCore.Builder.Extensions.MapMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

是什么问题?

Winform的ClientWebSocket始终联不上

ClientWebSocket client = new ClientWebSocket();
client.ConnectAsync(new Uri("ws://127.0.0.1:6001/ws?token=f5e2fdf65e5c4a1f9fc677c8a3e6b99ccd35347169084455a33d01af3fc350ba728e58799bc6434e8c3b9e82b206eddaa4a88d85150b4315856a5e6ecfd3543a"), CancellationToken.None).Wait() ;

联不上。不知道什么原因,求大佬 指点

关于几个小建议,请赐教

1.为什么SignalR不适合做im
我觉得主要的原因是能耗。很多协议不适合做im,除开兼容性问题之外,最主要的原因就是能耗。因为im需要保持长连接,耗电。
2.关于API群发
如果群发1000人,需要创建1000条消息吗?
这个分三种情况:
(1)群组消息
同一群组就订阅同一个Topic,消息就一条,但是推送至用户端还是需要1000次,别无他法。
(2)一类人(Tag相同)
可以借鉴群组的做法。
(3)真的就是无关联的1000人。
那只能创建1000条消息一一推送了。
以上是我的拙见,如有不对,请高手指正。

引入Nuget包和直接拉源码,链接WebSocket问题

您好,我自己在之前使用Nuget包的时候,正常的一个使用没问题的,但是我从git上拉您的源码下来使用后,我前端链接Websocket时,后端就会说资源以释放,不可访问.想请教一下是需要哪里配置吗.

收不到消息

启动了imServer

启动了Web项目
查看redis也创建了房间,并且2个人员也有了
就是发送消息,双方都看不到?
这是什么问题呢?

我真有点搞不懂

在项目里打开本地调试,是正常的,可以正确使用。

但是发布了IMServe到本地之后,在我本地直接运行打开,端口死活是5000和50001
那么IMServer的appsettings.json配置的地址参数配置了还有用吗?
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",

"ImServerOption": {
"RedisClient": "127.0.0.1:6379,poolsize=10",
"Servers": "127.0.0.1:6001",//发布到服务器的时候,这里127.0.0.1我改成了我的IP地址
"Server": "127.0.0.1:6001"//发布到服务器的时候,这里127.0.0.1我改成了我的IP地址
}
}
配置文件的端口,无论我怎么改,只要我发布项目,然后运行exe文件,端口死活是2个,5000和50001(这是在本地直接打包发布运行的)
项目里我搜索出来的端口5000,也就只有WebApi里面有写,但是我改了,重新发布,还是端口死活是5000和50001

好了,等我把IMServer发布到服务器就是端口是一个5000,我配置文件怎么改都是5000,好吧,我认了, 我把webapi也改成5000,Redis是可以链接上(链接地址没动过,IP:6379,是可以访问的),但是IMServer服务死活链接不上。

这是什么情况呢

代码图片发不到这里。不然我发图了

消息回执

大神,看到服务端转发消息的时候有个消息回执的功能,请问对于服务端来说,如何确定当前的消息发给了Receive端,且被Receive接收到了呢

服务端应该怎么发布部署?

发布成web项目?
Exe文件?
Dll然后部署成服务?
看您写的可以发布成多个站点以支持高并发,是部署成web项目然后在IIS下运行么?

发布server到服务器配置问题

"ImServerOption": {
"CSRedisClient": "118.25.209.177:26379,poolsize=5",
"Servers": "127.0.0.1:6001;127.0.0.1:6002",
"Server": "127.0.0.1:6001"
},
比如说我发布到 18.123.123.11 这个server 上。 "Servers": "127.0.0.1:6001;127.0.0.1:6002",
"Server": "127.0.0.1:6001" 这两个配置文件要改成 18.123.123.11:6001,18.123.123.11:6002吗?

关于WSS的配置问题

目前已经把issue内关于wss配置的问题都看过一遍了,仍然出现如下问题(使用的是示例代码):
image

似乎是websocket连接没有建立,发送消息无法接收到

修改的配置项包括:

  1. Webapi、ImServer添加app.UseHttpsRedirection();
  2. launchSettings.jsonhttp修改为https
  3. ImClient60行将ws修改为wss

加载index.html的时候报错,好像是连不上websocket

index.html:66 WebSocket connection to 'ws://localhost:6001/ws?token=0279190161e143a690e949922cae5d3ea3b6d111c1ea4cc6aab00135502f47b1f6b6e20cc16e4745bcb146fc7a00a0228b6bef0dcb264f7898b63149deaa172e' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
index.html:89 websocket error
index.html:72 websocket disconnect
index.html:76 Uncaught ReferenceError: chan is not defined
at index.html:76

如何本地化?适配私人数据库

大佬,我看到代码内,是连接的别的IP地址。如何绑定到我自己的地址???如何将数据存入到我自己的数据库??。是否有相关的介绍或者文档来操作一下呢。。。可以加QQ嘛??

IMServer怎么部署呢?

IMServer怎么部署需要怎么部署呢? 部署到 IIS 还是以服务方式运行, 怎么弄好点呢?

在https方式下收不到消息

我有两个应用一个使用http 一个使用https 两个应用的用户socketId相同
http使用ws, https 方式连接wss,两个应用都可以正常连接imServer
http一切正常,
当使用https的应用时,连接服务器正常,就是收不到消息
此时,同时把http的应用浏览器打开并连接im,https的应用就可以正常收到消息了;如果把http应用连接关闭,就收不到消息
这是什么原因?期待回复

wss的问题

前端是https的, imserver是http可以码?

如何清理online表的无效数据?

似乎是因为im服务器意外停止(或者其他原因),客户端下线之后,server未能在online表删除对应记录,
重启Im服务器之后,出现很多假的在线用户,本想设置15s过期时间,然后用心跳不断延长过期来解决,
可online表无法单独设置每个clientId的过期时间

能否设计一个妥善的处理机制?

下线通知到在线客户端

上下线在 ImHelper.EventBus 获取到事件,上线的时候还可以用 ImHelper.SendMessage(t.clientId, onlineUids, $"用户{t.clientId}上线了");
通知到在线客户端,
但是下线了,API 端怎么通知到在线客户端呢? ImHelper.SendMessage 有没有提供从服务器端发送的呢?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.