因为我们现在有了本地服务器利器,且了解了数据库。实现单聊群聊易如反掌。从功能上来说单聊群聊难度是几乎差不多的,本文详细的说明单聊实现逻辑。
一切解题思路都在数据库上。数据库需要设计的,设计好了,很多问题全部迎刃而解。
一、单聊和群聊是不是同一个类型?
经过我深思熟虑,参考之前做的环信和云信以及腾讯云的源码,表分开设计比较好。
二、用户表设计:
这里还是有一个前提,所有好友的ip段以及ip是固定的。假设不固定后面再说怎么处理,其实就是个数组如何初始化的小case。另外,据我所知每个人不仅有ip,而且携带的蓝牙设备有一个唯一的设备标识我们成为device id,简称did。
单聊或群聊可能需要显示用户的头像昵称信息,我们把用户信息做成一张表,单聊群聊记录哪个用户的聊天记录的时候只需要记录这个用户的ip和did信息,到时候根据ip外键关联。
id: 主键自增
ip: 用户的ip地址
did:用户的设备唯一标识号
head_image: 头像
nick_name: 昵称
c_time: 个人信息的创建时间戳,这是更新用户信息的重要判断标准。
....其他字段
当我自己在修改我的个人昵称头像的时候,更新我自己的表就可以了。不用告诉其他人,因为有的人不在线,现在告诉他们貌似效率不高。
三、获取好友列表
因为好友列表好友的状态是时刻变化的,且在页面onShow的时候需要请求刷新列表数据,我想了下这个列表数据不需要保存到数据库(保存也可以你自己决定)。
(1)好友列表是固定的。如果是ip从10-21,一定是12个人的列表
(2)他们的状态可能是时刻变化的。
所有人在好友页面列表onShow事件中开始获取好友在线状态(列表恒定在,过滤自己),以ip=10这个人为例。for循环POST请求10-21的ip的接口:/user/check/online
如果11请求成功,把数组在线状态online置为101
如果12请求被回调告知失败,把数组在线状态online置为102
......
这样我们就得到了一个好友列表了。页面将在点击刷新按钮或下一次onShow的时候刷新。
四、单聊数据表设计:
我们先设计表,表好了,功能基本就完成了。单聊我们使用single_chat表,后面群聊我们使用group_chat表
先思考一个两个人单聊,需要哪些字段:
id: 主键自增
from: 发送方的ip
to:接受方的ip
message_type: 消息类型,101文字消息 102语音消息 103图片消息 104视频消息 ...
content: 消息具体内容,因为全部本质是文本消息,所以这里就是统一的简单的字符串
c_time: 消息的创建时间戳,这个非常重要,将决定了消息的顺序。特别是消息和服务器同步后保证消息不顺序混乱。
五、单聊功能实现:
目前我ip=10,ip=11在线,ip=12不在线。
(a)与不在线的人聊天:
与不在线的人聊天比较简单,点击进入12的单聊页面,允许他点进。因为就算12不在线,我也可以查看历史记录或从服务器同步数据。只是进来如果12不在线,发任何消息都失败。我们可以简单点,失败的消息不记录数据库,只有在发成功的才记录。
(b)与在线的人聊天:如ip=11
(1)因为所有的消息都是文本消息只有message_type不一样,从数据库的角度就只有一种消息一样。ip=10向11发消息后,先把数据记录到数据库,然后把数据刷新到聊天列表中。
(2)Ip=11的人收到消息(处理POST请求),一样先记录到数据库,然后刷新到UI。
(3)进入聊天页面查看历史消息直接一个sql+where查询得到聊天列表。
(c)如何查看更多历史消息?
我喜欢先简化问题,再来细节化解决问题。目前我们先简化问题实现功能,查询数据库的时候limit0,500,数据当然在数据库,我们目前只显示最近的500条聊天记录。
(d)如何和服务器数据同步?接口即将写。
就是上面这200条数据,在进入聊天列表的时候全部丢给服务器,服务器对比后记录服务器不存在的数据,且将你缺失的数据返回。
(1)如果返回的list.size=0,说明服务器的数据你都有。
(2)如果返回的list.size>0,说明服务器的数据你有list.size条丢失了,你插入数据库即可。不用担心顺序的问题。你查询的时候c_time会自动给你整理好。
所以进入聊天列表,请求服务器接口,post服务器成功后插入缺失的数据执行500条查询。post失败后也执行500条查询即可。
(e)更新头像昵称信息后,好友什么时候获知最好?
目前我个人感觉,在用户发单聊或群聊消息的时候附带上自己的个人信息就可以了。用户收到后,对比一下from用户信息的c_time,如果本地没有这个用户或本地用户的c_time和收到的用户c_time不一致,则更新该用户的个人信息。
用户发送消息体参考:
message = {
from: 10, //发送方ip
from_user:{ //完成的用户模型,不用想是否费流量,这个问题在局域网和5G时代不是问题了
ip: 10,
nick_name: "张三" , //昵称
head_image: "", //头像
c_time: 1356669887, //用户信息最后更新时间
},
to:11, //接收访ip
message_type: 101 //文字消息
content: "hello", //消息内容
}