如何使用websocket + protobuf开发IM聊天项目

3,664 阅读1分钟

前言

微信是我国当前最火热的APP之一,仿照微信APP自己开发一个自己的项目,是我很早以前就有的想法。就在前段时间,这个想法终于落地并实现了,如你所见,终于诞生了本人的掘金处女篇!初次尝试写文章,难免出现纰漏,还请各位看官见谅~
在线体验地址

项目技术栈

后端:JAVA + Websocket + Protobuf
前端:Vue全家桶 + Websocket + Protobuf.js

移动端预览

消息接收

发送表情

PC端预览

消息接收

发送表情

@群内成员

通讯录


引入protobuf.js

    import protobuf from 'protobufjs'

封装protobuf方法

//发送数据处理成protobuf格式
const getProtoData = (protoClass, messageType, data) => {
    let AwesomeRoot = protobuf.Root.fromJSON(awesomeConfig)
    let AwesomeMessage = AwesomeRoot.lookupType(protoClass)

    let message = AwesomeMessage.create(data)
    let buffer = AwesomeMessage.encode(message).finish()
    
    let arrayBuffer = new ArrayBuffer(3 + buffer.length)
    let dataView = new DataView(arrayBuffer)

    dataView.setUint8(1, 0)
    dataView.setUint8(2, messageType)

    for (let i = 0; i < buffer.length; i++) {
        dataView.setUint8(i + 3, buffer[i])
    }

    const u8Arr = new Int8Array(arrayBuffer)

    return u8Arr
}

//接受protobuf格式数据的也要处理成json
const receiveMessage = (protoClass, data) => {
    let AwesomeRoot = protobuf.Root.fromJSON(awesomeConfig)
    let AwesomeMessage = AwesomeRoot.lookupType(protoClass)

    let buffer = new Uint8Array(data)
    let finalBuffer = buffer.slice(1, buffer.byteLength)

    let deMessage = AwesomeMessage.decode(finalBuffer)
    let extra = deMessage.extra

    if (extra && extra.sequence) {
        extra.sequence = longHandleToString(extra.sequence)
        store.commit('UPDATE_SEQUENCE', extra.sequence)
    }

    return deMessage
}

websocket心跳包

function setHeartBeat() {
    const { accessToken } = store.getters

    heartBeatTimer = setTimeout(() => {
        if (!accessToken) { // 用户退出登录以后,不发送心跳包
            clearTimeout(heartBeatTimer)
            heartBeatTimer = null

            return
        }

        const data = getProtoData('Ping', 1, null)

        sendSock(data)
        
        setHeartBeat()
    }, 90000)
}

websocket断开之后重新连接

function restartSock() {
    const time = 4000

    clearTimeout(heartBeatTimer)
    
    initTimer = setTimeout(() => {
        initWebSocket()
    }, time * 2)

    let newTime = time
    
    if (newTime === 32000) {
        restartTimer = setTimeout(() => {
            initWebSocket()
        }, 32000)
    }
}

以上就是所使用的一些核心方法,大概就是这样了