这周确定了课程设计的方向, 做 IM
(即时通信App), 我主要负责后端这个方面, 所以学习了一些可以实现的技术细节, 在这里做记录
消息通信
有一个最简单的例子, 就像发手机短信一样, 只要知道手机号码就能发出去并接收到短信, 但实际上(APP的)用户与用户之间是没办法直接了解到互相的网络信息(ip, 端口号)来进行相互通信的, 所以需要用一个服务器来做中转站的功能
假设一个场景, 用户A想要给用户B发送一条消息M, 其(简化版)过程就会是下面这样:
- A 向服务器发送 M
- 服务器接收到 M, 将 M 转发给 B
- B 接收到消息
这样便实现了 A 向 B 发送 M
的过程, 这也可以解决一些问题, 如:
B的状态
对A发送M
的这个事件是 无关 的, 不必考虑各种问题(在线否, 接收到否)- 服务器可以控制 只有双向好友才能通信
- 等到 B 在线, 服务器才将 M 发送出去, 确保 B 能够接收到
消息接收-离线
上面提到 等到 B 上线了, 会接收一系列发给 B 的消息, 实际上是如何实现的呢?
其实并不是服务器主动发送 未接收
消息给 B, 而是 B 上线时主动去拉取(请求)回来
具体实现
- 在服务端, 每个用户都会有一张消息表, 用来记录各种消息记录, 它们有着唯一标识的
序号(seq)
属性 - 在客户端, 存储着用户上一次最后收到的消息的
序号(rev seq)
- 当用户刚登录时, 会向服务端发送一个请求, 拉取
rev seq
后的全部消息, 并更新这个值 - 至此, 用户可以接收到自己未收到的新消息
消息接收-在线
上面说到的是 离线消息 的接收, 那么在线消息呢? 总不会要每时每刻都向服务器发送请求查询是否有新消息吧?
实际想的是 服务器接收到消息时, 先看一下用户是否在线, 如果在线, 那么直接发送给用户, 更新本地 rev seq
, 如果不在线, 那么就是上面的情况;
当然服务端想直接发送信息给用户, 两者之间是需要建立连接的, 放到服务端来实现可以很大优化用户体验
具体实现
- 用户上线时, 与服务器建立连接(目前想法是socket连接)
- 建立连接后, 服务器知道哪些用户是在线的, 可以把消息直接转发给用户
- 用户收到消息要记得更新
rev seq
- 用户下线时, 通知服务器断开连接
- 服务器要维护在线用户状态
(具体socket连接如何实现还没想好)
消息接收表
为了更好的扩展, 用户各自的 消息接收表
并不是简单地设计成只存储 seq
和 string
这样的表, 因为这样只能存储一些简单的文字消息, 还要考虑到 图片/视频/语音/链接 这样的消息内容
具体实现
大致想到的表就是图中的样子吧
其中:
关键字 | 备注 |
---|---|
seq | 序号 |
from | 消息发送者 |
type | 消息类型(文字/图片/视频…) |
contentID | content表的id 用于查询具体内容 |
cid | 主码 |
content | 内容, 根据type来解读 |
也就是说用户可能会收到多种消息, 然后再根据 contentID
去拿回对应内容进行显示
联系人/好友
这一部分目前思考得不算太多, 大概是每个用户都有自己的好友表(单向), 添加/删除都可以实现, 这样就算重装APP也可以保留好友列表
用户信息-验证与存储
用户可以拥有多个唯一标识, 如 用户id
, 手机号
, 邮箱
; 拥有一个密码;
用户信息包含:
- 昵称
- 头像
- 个性签名
- 等
表也挺简单:
用户信息-更新
问题的来源是这样的, 当一个用户更新了自己的信息, 怎么通知其他人呢?
请教了老师之后明白了, 关键是用好之前的消息接收表
具体实现
- 用户更新信息, 会向TA的好友发送一条特殊的消息,
type
为INFO UPDATE
(待定) - 用户收到这样特定的消息会进行特殊处理, 在这里是更新用户信息
建立好友关系
同更新用户信息相似, 也是发送一条特殊的消息, 在客户端做特殊处理
具体实现
- 用户发送好友请求消息, 发送特殊消息,
type
为Friend Req
(待定) - 用户通过或不通过好友申请, 发送特殊消息,
type
为Req SUCC
或Req FAIL
- (若成功)服务端在好友表中添加相应用户, 客户端在好友列表添加相应用户
未来可能要考虑的内容
- 类朋友圈内容发布
- 多种聊天信息(视频/语音)完善
- 表情包保存
- 后台消息推送
- 性能优化