葉為正,林聲肯,黃立軒,許志明,李 晶
(中山大學新華學院,廣東 廣州 510520)
隨著網絡技術的發(fā)展,越來越多的人開始使用互聯網,人們對網絡即時通訊系統(tǒng)的需求量也越來越大,并且已成為當今人們交流的重要途徑,這使得即時通訊技術飛速發(fā)展[1-2]。盡管市場上出現了許多第三方即時通訊提供方,如環(huán)信、融云以及騰訊云通信IM等,但自主開發(fā)出一款能在企事業(yè)單位內部使用的、進行工作溝通交流的即時通訊系統(tǒng)具有重要意義[3]。文中首先介紹了實現該系統(tǒng)所采用的技術,并在IntelliJ IDEA與HBuilder開發(fā)環(huán)境下進行編程開發(fā),然后重點研究整個即時通訊系統(tǒng)的設計思路、實現方法以及實現效果。
Nginx是一款高性能的Web服務器[4],采用多進程的基于事件驅動的架構,全異步的網絡I/O處理機制,以及極少的進程間切換設計,使得它能夠同時支持百萬級別的TCP連接[5]。FastDFS是用C語言編寫的一款開源的分布式文件系統(tǒng)[6]。FastDFS是為互聯網量身定制,充分考慮了冗余備份、負載均衡、線性擴容等機制,并注重高可用、高性能等指標。使用FastDFS可以很容易搭建一套高性能的文件服務器集群提供文件上傳、下載等服務[7]。文中采用Nginx+FastDFS搭建圖片服務器,用于存儲用戶頭像和二維碼等圖片文件。
MUI框架,是DCloud公司發(fā)布的一款開源框架,是最接近原生App的前端框架[8]。HTML5+是HBulider利用自己的IDE結合不同平臺的接口再加上HTML5[9]開發(fā)出來的一套框架,它有自己的使用規(guī)范,允許和提供了一些接口和函數來讓Web[10]開發(fā)者實現原生App所能實現的功能,并且MUI以iOS平臺UI為基礎,補充了Android特有的UI組件[11]。
Netty是一個性能極高、異步事件驅動的框架[12],是一個異步非阻塞的框架。這個框架支持多種通信協議,包括UDP、TCP以及文件傳輸協議等[13]。通過使用Netty,對于所有的IO操作,開發(fā)人員都可以主動地或由它內部的機制取得結果[14]。SpringBoot是由Pivotal團隊開發(fā)的全新的開源開發(fā)框架,能夠簡化應用Spring開發(fā)項目。最突出的特點是配置方式,大大簡化了Spring應用的各個方面。另外SpringBoot能夠集成大量的框架,解決了之前很重要的項目之間包的版本依賴和穩(wěn)定性等問題[15]。
該平臺采用C/S模式,前端也就是客戶端采用移動應用程序的方式,后端采用SpringBoot+Netty作為主要的服務端,利用Spring MVC的注解創(chuàng)建RESTful Web服務。移動客戶端與服務端連接讀寫邏輯處理均是啟動階段通過給邏輯處理鏈Pipeline添加邏輯處理器實現連接數據的讀寫邏輯??蛻舳诉B接成功回調邏輯處理器channelActive()方法,客戶端/服務端接收連接數據調用channelRead()方法。寫數據調用writeAndFlush()方法,客戶端與服務端交互的二進制數據傳輸載體為ByteBuf,ByteBuf通過連接的內存管理器創(chuàng)建即ctx.alloc().buffer(),通過writeBytes()方法將字節(jié)數據填充到ByteBuf寫到對端。Netty客戶端與服務端通信流程如圖1所示。
圖1 Netty客戶端與服務端通信流程
客戶端模塊設計:用戶通過登錄或者注冊進入到App時,首先會進入到聊天頁面,通過底部導航進入發(fā)現頁進行好友添加操作,當好友添加成功,在通訊錄中即可顯示已添加的好友,點擊頭像跳轉至聊天頁面。在個人信息頁,可以進行頭像、昵稱的修改以及退出登錄。平臺功能模塊設計如圖2所示。
經過對即時通訊系統(tǒng)的設計和功能需求分析,建立了關系數據庫的實體-關系模型,確定數據庫里用戶、通訊錄好友、好友請求、聊天信息實體。每個實體對應一個數據表,具有多個字段屬性。
圖2 平臺功能模塊設計
該系統(tǒng)將MySQL數據庫作為后臺數據庫,創(chuàng)建的后臺數據庫名稱為IMDB,包括4個表:用戶信息表、通訊錄好友信息表、好友請求記錄表、聊天信息表,如表1所示。
表1 即時通信系統(tǒng)中的表
在對系統(tǒng)需求和實際情況分析的基礎上,對每個表的字段名、數據類型、完整性約束信息進行定義,便于各類資源的信息的存儲和數據檢索。系統(tǒng)數據表詳細情況如表2~表5所示。
表2 用戶信息
表3 通訊錄好友信息
表4 好友請求信息
表5 聊天信息
即時通訊APP開發(fā)主要包含兩個部分:移動客戶端和Java Web后臺服務端??蛻舳说牧奶旃δ芡ㄟ^WebSocket與后端數據進行交互,其他功能均采用MUI提供的Ajax與后端數據進行交互。
用戶第一次進入該系統(tǒng)時,輸入用戶名和密碼,后端接收到用戶輸入的信息后,會判斷數據庫中是否存在該用戶,若不存在則自動注冊后登錄,并將用戶的信息通過H5+提供的API接口plus.storage.setItem(key,value)方法存儲在本地數據存儲區(qū)。當用戶打開該軟件時,系統(tǒng)會自動通過plus.storage.getItem(key)方法獲取應用存儲的值進行登錄操作。
在個人信息模塊中,主要有查看頭像、昵稱、賬號、我的二維碼與退出登錄等功能。點擊頭像即可查看頭像、下載頭像與上傳頭像。上傳頭像時,系統(tǒng)會調用開源圖片裁剪插件Cropper進行圖片的裁剪,通過前端傳過來的base64字符串,然后轉換為文件對象再上傳到FastDFS,將拼接好的圖片url寫入用戶對象,最后調用MyBatis對該用戶對象進行更新操作。二維碼是用戶注冊時后端使用谷歌開源項目zxing所生成的,點擊二維碼,即可查看二維碼或者下載二維碼,其他用戶可以通過發(fā)現頁的掃一掃功能實現添加好友的功能。點擊退出登錄,即可將用戶的信息從系統(tǒng)中清除,跳轉到登錄模塊。個人信息頁面如圖3所示。
圖3 個人信息頁面
本模塊主要有添加好友與掃一掃功能,輸入好友的賬號即可實現好友請求的發(fā)送。在掃一掃中也可以通過掃描好友的二維碼進行添加好友的請求。通過H5+API中的Barcode模塊完成二維碼的掃描識別功能,獲得碼數據及碼類型,再使用mui.ajax(url[,settings])將myUserId與friendUsername傳遞至后端,或者直接通過添加好友將數據傳遞至后端,后端根據friendUsername將朋友信息通過mybatis操作數據庫查詢出這個Users對象,然后再查詢發(fā)送好友請求記錄表(friends_request),如果sendUserId和acceptUserId沒有關聯,則建立關聯關系,實現發(fā)送添加好友的請求。在對方登錄系統(tǒng)后,如果忽略好友請求,則直接刪除好友請求的數據庫表記錄,如果是通過好友請求,則互相增加好友記錄到數據庫對應的表,然后刪除好友請求的數據庫表記錄。發(fā)現頁面如圖4所示。
圖4 發(fā)現頁面
該模塊使用MUI的Ajax將該用戶的id傳至后端,獲取所有好友列表,通過words.convertPinyin(friend.friendNickname)將好友的昵稱轉化成拼音,截取拼音的首字母,構建通訊錄html進行渲染。當用戶下一次打開通訊錄,直接從緩存中獲取聯系人列表渲染到頁面。對好友通訊錄批量綁定點擊事件,當用戶點擊某個好友,即會打開聊天頁面,并攜帶相應的用戶參數。通訊錄列表頁面如圖5所示。
在該模塊的后端主要有兩個類:WebSocket服務端啟動類WSServer與處理類ChatHandler。聊天列表頁面如圖6所示。
圖5 通訊錄列表頁面
圖6 聊天列表頁面
在WSServer中,由于WebSocket是基于http協議的,所以要通過pipeline.addLast(new HttpServerCodec())來添加http編解碼器,此外,還要增加心跳支持以及httpWebsocket支持,最后增加自定義的處理類Chathandler以及心跳處理類HeartBeatHandler。在Chathandler中,它繼承了SimpleChannelInboundHandler
步驟1:獲取客戶端傳輸過來的消息。
通過msg.text()獲取客戶端傳輸過來的消息,通過ctx.channel()獲取當前的channel,并將客戶端傳遞至后端的json字符串轉換成相應的DataContent數據內容對象。
步驟2:通過數據內容對象中action屬性與后端的枚舉類中的屬性進行對比判斷消息類型,并根據不同的類型來處理不同的業(yè)務。
(1)當websocket第一次open的時候,初始化channel,把用的channel和userid關聯起來。
(2)若是聊天類型的消息時,就把聊天記錄保存到數據庫,同時標記消息的簽收狀態(tài)為“未簽收”。發(fā)送消息,即從全局用戶Channel關系中獲取接受方的channel,若channel為空代表用戶離線。當接受方receiverChannel不為空的時候,從ChannelGroup去查找對應的channel是否存在,當用戶在線時,通過writeAndFlush推送消息。
(3)若是簽收消息類型,就針對具體的消息進行簽收,修改數據庫中對應消息的簽收狀態(tài)“已簽收”。
(4)若是心跳類型,則打印輸出相應的心跳包數據。
步驟3:當觸發(fā)handlerRemoved或發(fā)生異常,ChannelGroup會自動移除對應客戶端的channel。若心跳處理類HeartBeatHandler類中的IdleStateEven為讀寫空閑時,也會關閉無用的channel,以防資源浪費。
該平臺開發(fā)完成后,該系統(tǒng)服務端部署MacOS,并將Nginx+FastDFS圖片服務器部署在CentOS6.5中。在小米8手機(四核,高通驍龍845,運行內存6 GB,6.21英寸屏幕,Android OS v8.0)以及iPhone 8手機(六核,蘋果A11+M1協處理器,運行內存2 GB,4.7英寸屏幕,iOS v10)中對各項功能進行了測試,客戶端運行良好,可以實現登錄注冊、修改個人信息、添加好友以及聊天的功能。
研究了基于Netty+SpringBoot的即時通訊系統(tǒng)的設計與實現,采用了HBuilder和IntelliJ IDEA開發(fā)了即時通訊系統(tǒng),通過HBuilder開發(fā)出來的應用可生成適用于安卓與蘋果系統(tǒng)的安裝包,節(jié)約了開發(fā)人員同時開發(fā)不同客戶端的成本,實現了基本的數據通信,可以滿足日常的通信需求。