关于聊天系统

在线聊天功能的总设计思路:

现在有两个浏览器在不同的两台电脑上面, 浏览器A登陆的是系统管理员,

浏览器B登陆的是总监, 现在系统管理员想给总监发送消息,而浏览器之间

是不可以相互之间直接发送消息的。因为一个浏览器是在A电脑上面,

一个浏览器是在B电脑上面。这两台电脑是不可以相互之间直接通讯的。

但是这两个浏览器都访问了CRM这个网站。我们就想一个办法,

系统管理员先把这个消息发给服务器,然后总监再向这个服务器要,

那么这样就涉及到一个问题。系统管理员把这个消息给服务器,服务器又怎么知道

这个消息是给总监的呢?所以必须给服务器一个实体,这个里面要包括哪几个东西呢?

首先谁发的必须要有,我们给这个实体取名为 ChatMsg , ChatMsg里面有这么几个属性

FormUserID(发送者ID),FormRealName(发送者名称),ToUserID(接收者ID),

ToRealName(接收者名称),MessageBody(内容),SendTime(发送时间)

系统管理员把这个消息实体发给这个网站以后,总监登录系统以后向这个服务器要,

总监的这个请求就必须带一个userid过来,服务器就会把userid等于这个值的消息给总监。

现在A电脑系统管理员和B电脑总监 都发送消息给这个网站,而这个网站还要做其他很多事情

这样就相当于它的职责不太清晰,压力也变大了。

那么想一个办法,CRM网站就只是负责处理登录,权限控制这些功能。那么这个聊天消息

的实时处理以及入库就交给另一个网站来处理。

就相当于一个应用服务器 ,那么在分布式结构里面,CRM就充当着

Web服务器。而这个应用服务器上面呢 说白了 也就相当于一个IIS,而在这个IIS上面发布了

一个站点,这个站点是用WCF构建的, 这个WCF服务 负责 聊天消息的实时转发和

历史消息的入库操作。那么这个时候 CRM的职责只需要 将浏览器发送过来的ChatMsg实体

转发给WCF聊天服务即可。无需理会这里面的逻辑了,这样CRM压力释放了,职责也明确了。

总监发送ID想从服务器拿到自己的消息,而CRM也只需要把ID转发给WCF聊天服务,由WCF处理

返回再由CRM转回给总监即可。这个时候CRM的职责就是一个转发的功能。所有的业务都不需要

处理,直接交给WCF服务处理,

那么再分析这些具体里面需要什么实际技术去实现呢?

发送消息需要什么就可以简单实现呢?在线聊天的界面,左边是一个用户列表,数据来源于

sysUserInfo这个表,右边上面用一个面板来做接收消息区域,放一个div就行了。

下面再放一个文本框,里面就是用来填要发送的消息内容。再有两个按钮,发送和查看历史消息

点击发送用Ajax的异步请求把文本框里的消息内容发送个CRM。

那么这个异步请求到底发送哪些消息过去?

FormUserID(发送者ID),FormRealName(发送者名称)表示发送者系统管理员,在服务器

已经登录就可以在Session中拿到,在这里没必要浏览器发送到CRM。就只需要把

ToUserID(接收者ID) ToRealName(接收者名称),MessageBody(内容),发送给服务器。

SendTime(发送时间)也不需要,就直接取服务器时间。

所以Ajax请求只需要把

ToUserID(接收者ID),ToRealName(接收者名称),MessageBody(内容),发送给CRM网站即可。

然后在CRM网站内部实例化ChatMsg对象就行了。

那么WCF这边级需要2个方法,发送消息需要一个方法。

SendMessage(ChatMsg msg)方法,这个方法

将来被CRM网站调用的。CRM实例化ChatMsg通过参数传给SendMessage方法。

因为发送消息以后级行了,不需要等待服务器处理完,所以这个方法是个数据报方法即可。

第二个方法:B电脑用户要从服务器拿到自己的消息,发送userid到CRM,然后转到WCF

将userid 传给方法 GetMessage(int userid),就把当前传过来的用户ID对应的聊天消息返回

,而返回的格式就直接返回ChatMsg实体的集合List<ChatMsg>,这个方法就必须是请求响应方法

,为什么?因为必须等服务器响应完才能返回,否则拿回去的数据会是空的。

那么这SendMessage方法接收到这个实体所做的逻辑步骤有哪些?

1,将msg消息实体先入Redis队列,

2,入库。加入到历史表中,方便将来查询。

GetMessage()方法呢?

获取消息逻辑有:

1,根据用户id从Redis中将消息出队 就直接返回

这两个方法的逻辑确定下来后,就要考虑第3件事。考虑性能问题

当用户频繁使用聊天功能进行发送消息的时候,会出现频繁的操作数据库

这样会导致数据库的压力非常大。

那该如何解决:

1,使用一个线程每隔1分钟将一批聊天记录进行一次性入库操作。

这样就能解决频繁操作数据库的问题。提升了db的性能,

但是引发了另一个问题,在进行一批数据的入库操作时,如果这批数据过大,

如何保证快速插入到db中。

解决方案:使用 system,data.SqlBluckCopy类来进行高效的批量插入处理,

这个时候注意:利用历史消息队列来统一存放要入库的消息实体。不然数据

从Redis中出队就没有了。

注意问题:

1,每个用户在Redis中都要有一个专属的消息队列(不然获取不到消息):

allmsg+msg.ToUserID,

这样就引发出一个设计问题:

1,在Redis中开启一个实时队列,此实时队列是每个用户都有一个的,

用来存储别人给这个用户发送的消息数据。

2,在Redis中开启一个历史消息队列,这个队列中存储的是每个用户的聊天消息,将来

每隔固定时间就将此消息队列中的数据入库(考虑到分表来存储)

3,使用单例类来管理上面两个队列利用Lock()锁防止多线程的并发问题。

时间: 2024-11-04 18:29:20

关于聊天系统的相关文章

简易版聊天系统实现 Socket VS NIO两种实现方式

说是简单聊天系统,压根不能算是一个系统,顶多算个雏形.本文重点不在聊天系统设计和实现上,而是通过实现类似效果,展示下NIO 和Socket两种编程方式的差异性.说是Socket与NIO的编程方式,不太严谨,因为NIO的底层也是通过Socket实现的,但又想不出非常好的题目,就这样吧. 主要内容 Socket方式实现简易聊天效果 NIO方式实现简易聊天效果 两种方式的性能对比 前言 预期效果,是客户端之间进行"广播"式聊天,类似于QQ群聊天.希望以后有机会,以此简易版为基础,不断演进,演

Java网络编程基础(六)— 基于TCP的NIO简单聊天系统

在Java网络编程基础(四)中提到了基于Socket的TCP/IP简单聊天系统实现了一个多客户端之间护法消息的简单聊天系统.其服务端采用了多线程来处理多个客户端的消息发送,并转发给目的用户.但是由于它是基于Socket的,因此是阻塞的. 本节我们将通过SocketChannel和ServerSocketChannel来实现同样的功能. 1.客户端输入消息的格式 username:msg    username表示要发送的的用户名,msg为发送内容,以冒号分割 2.实现思路 实现思路与Java网络

使用Unity自带的NetWorkView实现简单的聊天系统

众所周知,在游戏中,我们经常会简单带聊天系统.一般,我们常见的有公会聊天,也就是大家熟知的QQ群聊,还有就是私聊,相信大家都懂得.好了, 废话不多扯了,我们开工. 首先,我们来写服务器端的. 老规矩,我们先搭建基本的UI.我们这里仍然使用NGUI.服务器端,我们主要负责显示客户端接入情况和收集全部消息,然后同步给每个客户端. 首先,我们创建一个Sprite,重命名为BackGround,然后为其选择图集和精灵,将其颜色调整为黑色,大小为整个UIRoot.然后,我们创建一个Label,重命名为Ti

基于Netty的聊天系统(一)通讯原理篇

今天周六,正好顺便把聊天系统的通讯原理写一下,本来是用XMPP+Openfire做了一个聊天,但是在做群聊那块需要去写插件来主动向表里变去写数据,因为openfire外国人写的,最初设计的群聊是会议室那种形式,和我们现在这种QQ群聊还是有差别的,改造起来比较麻烦,需要去通都源码等等,openfire是基于mina来写的,mina和netty又出自同一作者之手,那么我们就基于netty来写一个吧,首先我们来谈一谈通讯的原理 1:通讯原理 首先比方说A和B两个人要进行聊天(这里我们先讨论一对一这种聊

java实现聊天系统项目笔记

JavaSE学完以后,用java实现的聊天室融合了很多java知识. 比如GUI简单的图形界面,集合,IO,多线程,socket,监听等. 那么这个聊天系统是如何实现的呢? 首先我们要有界面.如图所示. 这仅仅是一个简单的Frame窗口界面. 首先package : 包入境,相当于这个类文件的绝对路径,与别人重复几率减小 import   : 导入包/类的意思.当要想调用某个包中的类的方法,就要用到import extends : ChatClient01继承Frame,相当于,继承了父类Fra

Java-在线聊天系统-非线程

一.概述 1.目标:建立基于tcp协议的聊天系统 2.思路:用java socket编程 二.代码 1.ChatServer.java import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; p

基于Netty的聊天系统(三)协议定制----消息篇

今天我们继续来讨论协议,今天基本就把一对一聊天的协议定制完毕了,上一篇我们讲述了登录的过程,那么登录完毕就是聊天了,首先我们还是以A和B为例子,A发送消息给B,那么这条消息的的协议如下 发送消息协议: {"id":"xxxx","#":"msg","text":"内容","to":"接收用户ID","type":0,"

IM聊天系统

先上图片: c# 客户端,openfire服务端,基于java开源推送服务开发的及时聊天系统.大概功能有,单点消息支持文本/图片/截图/音频/视频发送直接播放/视频聊天/大文件传输/动态自定义表情等.持久化群成员,功能支持会议视频和上述消息功能.辅助功能有,签名头像皮肤广播消息等等.由于时间问题不涉及技术细节,有兴趣的可以加群225807275

制作高仿QQ的聊天系统(二)—— Adapter &amp; Activity

一.适配器 1.1 分页显示数据 因为聊天信息数目很多,所以adpter需要做分页处理,这里的分页处理是我自己实现的,如果有更好的办法欢迎在评论中告知.我们从友盟的反馈SDK中能得到聊天的list,我设定的是一次性显示10条数据,所以在适配器中传入和传出的position并不是listview的index,需要进行一定的计算. 下面是计算position的方法: /** * @description 重要方法,计算出当前的position * * @param position * @retur

基于Netty的聊天系统(二)协议定制----登录篇

上一篇文章我们讨论了聊天的基本流程,那么我们现在基于上一篇文章的流程开始定义协议,如果有朋友有更好的建议,可以在下边回复一起学习讨论,我们说登录分为两部分,第一部分为和服务器的连接阶段,第二部分为验证阶段,那么首先我们基于这2个部分来指定协议: 连接阶段: {"id":"xxxx","#":"conn","u":1[email protected]/ios,"v":100} id:客户端