實時聊天室之WebSocket實戰

2022.07.27

實時聊天室之WebSocket實戰

WebSocket 是一種在單個TCP 連接上進行全雙工通訊的網絡通信協議。

​想了解更多關於開源的內容,請訪問:​

​51CTO 開源基礎軟件社區​

​https://ost.51cto.com​

前言

如果要實現像微信聊天一樣的功能,在組網內進行通信顯然是不夠的,所以軟總線並不作用與這種遠距離傳輸。如果我們要完成微信的聊天功能,傳統的方法就是利用webSocket借助服務器進行全雙工通信。

WebSocket是什麼?

WebSocket 是一種在單個TCP 連接上進行全雙工通訊的網絡通信協議。

在以前沒有webSocket的時候,大家都用HTTP協議進行網絡通信,但是HTTP協議是一個無狀態,無連接,單向的應用層協議,因此只能讓客戶端對服務端進行單向請求,服務端無法主動向客戶端發送消息,導致了像實時聊天這種業務開展起來比較困難。

有開發者就使用HTTP進行長輪詢的方案,也就是說需要HTTP在一段時間內必須一直保持連接請求,以獲取最新的服務器的消息。這樣顯然效率低下,而且非常浪費資源。

因此就誕生了WebSocket,只需要進行一次連接,就可以一直保持全雙工的通信狀態。

Demo展示

下面我們就來用官方提供的WebSocket接口實現一個簡易實時聊天室的Demo。效果如下:

#夏日挑戰賽#【FFH】實時聊天室之WebSocket實戰-開源基礎軟件社區

代碼實現

可以看到官方文檔的接口說明,我們只需要簡單用到幾個接口就可以實現我們的業務需求了。

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/websocket-connection-0000001333321005。

#夏日挑戰賽#【FFH】實時聊天室之WebSocket實戰-開源基礎軟件社區

1、申請網絡權限

在config.json文件裡面註冊網絡權限,該權限允許程序打開網絡套接字,進行網絡連接。

"reqPermissions": [
  {
    "name": "ohos.permission.INTERNET"
  }
]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

2、導入webSocket模塊

import webSocket from '@ohos.net.webSocket';
  • 1.

3、創建webSocket對象

接著我們調用createWebSocket()接口生成一個webSocket對象,並且保存起來。

let ws = webSocket.createWebSocket();
  • 1.

4、連接webSocket通道

調用connect()接口進行連接。這裡需要一個URL作為參數傳入,在這個demo中,直接用了一個以前開發好的服務器接口進行調用,但是不對外開放,因此大家只需要將自己開發好的接口地址放到”wsURL“內即可。

onInit() {
        let that = this;
        ws.connect("wsURL", (err, value) => {
            if (!err) {
                console.log("xxx---connect success");
            } else {
                console.log("xxx---connect fail, err:" + JSON.stringify(err));
            }
        });
    },
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

5、订阅通道内消息更新

这里我们调用on( type:‘message’ )接口进行消息监听,这里要注意的是服务端传递过来的是字符串类型,所以如果消息是JSON对象,则需要用JSON.parse()进行解析,还原成JSON对象。

onInit() {
        let that = this;
        ws.on('message', (err, value) => {
            console.log("xxx---on message, message:" + value);
            //传递的是序列化后的字符串,需要解序列化为JSON对象
            let dataObj = JSON.parse(value)
            console.log("xxx---parse success---postId: "+dataObj.postId+",message:"+dataObj.message)
            that.message.push(dataObj)
            console.log("xxx---check message: "+JSON.stringify(that.message))
        });
    },
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

6、发送消息

紧接着调用send()接口进行消息的发送,这里注意,如果要传递的是JSON对象,要使用JSON.stringify()进行序列化操作, 保证我们传递的是流字符串的形式。

在该接口的回调中,我们也可以打印出来,看看消息是否发送成功。

sendMessage(){
        let that  = this;
        let data = {
            postId:that.id,
            message:that.sendMes
        }
        let dataStr = JSON.stringify(data)
        ws.send(dataStr, (err, value) => {
            if (!err) {
                console.log("xxx---send success");
            } else {
                console.log("xxx---send fail, err:" + JSON.stringify(err));
            }
        });
        that.message.push(data)
    },
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

7、隐藏标题栏

细心的小伙伴就会发现,我的demo展示的黑色标题栏不见了,其实是可以隐藏掉的,只需要在config.json文件中module.abilities下添加几行代码即可。

"metaData":{
            "customizeData":[
              {
                "name": "hwc-theme",
                "value": "androidhwext:style/Theme.Emui.NoTitleBar",
                "extra":""
              }
            ]
          }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

8、样式设计

接着就是简单设计一下界面样式,把获取到的消息渲染出来就完成啦。

<div class="container">
    <div style="width: 100%;height: 8%;color: #ff86868a;font-size: 25px;justify-content: center;position: absolute;">
        <text style="top: 10px;">
            实时聊天室
        </text>
    </div>
    <list style="height: 80%;">
        <list-item for="{{message}}" class="{{$item.postId==id?'listItemRight':'listItemLeft'}}" >
            <div class="listItemDiv" >
                <text style="padding:5px;border-radius: 10px;font-size: 20px;margin: 5px;max-width: 70%;">
                    {{$item.message}}
                </text>
            </div>
        </list-item>
    </list>
    <div  style="position: absolute;left:10px;bottom: 20px;">

        <textarea id="textarea" class="textarea" extend="true"
                  placeholder="请输入聊天信息"
                  onchange="inputChange" >
        </textarea>
        <button style="width: 75px;height: 50px;margin-left: 10px;background-color: #ff4848f5;" onclick="sendMessage">  发送 </button>
    </div>

</div>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
.container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    left: 0px;
    top: 0px;
    width: 100%;
    height: 100%;
}
.textarea {
    placeholder-color: gray;
    width: 70%;
}

.listItemDiv{
    background-color: #ff87f3d0;
    border-radius: 10px;

}

.listItemLeft{
    margin: 10px;
    width: 100%;
    justify-content: flex-start;
}
.listItemRight{
    margin: 10px;
    width: 100%;
    justify-content: flex-end;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

文章相关附件可以点击下面的原文链接前往下载:

https://ost.51cto.com/resource/2210。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​