C++服務器設計(七):聊天系統服務端實現

  在之前的章節中,我們對服務端系統的設計實現原理進行了剖析,在這一章中,我們將對服務端框架進行實際運用,實現一款運行于內網環境的聊天系統。該聊天系統由客戶端與服務器兩部分組成,同時服務端通過數據庫維護用戶的賬號信息。本章將重點介紹如何運用該服務端框架進行服務器業務邏輯開發。

聊天系統功能分析

  本聊天系統只作為服務端框架的運用展示,因此僅限于最基本的局域網聊天工具,數據傳輸均采用為明文形式,并不在安全性上進行深入探討。具體功能需求分析如下:

  • l? 用戶注冊:提供新用戶賬號注冊功能,注冊內容包括新用戶的賬號名和密碼。服務器需要檢測注冊信息的有效性,并將注冊用戶的信息保存在數據庫中。
  • l? 用戶登錄:用戶根據賬號密碼進行登錄操作,若未進行登錄操作將無權限請求聊天相關消息。服務器查詢數據庫驗證用戶賬號信息,同時判斷該用戶是否已經登陸。用戶賬號不允許重復登錄。
  • l? 在線好友更新:已登錄用戶可以主動向服務器查詢當前在線的好友信息。服務器同樣應該及時向所有登錄用戶推送好友上線及下線信息。
  • l? 好友聊天:已登錄用戶可以向在線狀態的任意好友發送聊天消息,同時也能接收到來自其他在線狀態的好友發送過來的消息。
  • l? 群體聊天:已登錄用戶可以同時向所有在線狀態的好友發送群體聊天消息。同時也能接收到來自其他在線狀態的好友發送的群體聊天消息。

聊天系統服務端實現

數據庫實現

  聊天系統需要維護用戶的賬號信息,記錄注冊的新賬號,并對每次登錄的用戶信息進行校驗。我們選用輕量級的Mysql作為數據庫管理系統,并選擇Mysql++作為Mysql的API操作庫。

  整個聊天系統只建立了一個名為UserInfo表結構,如表5-1所示。同時根據Mysql++封裝了兩個操作接口,分別添加新用戶賬號信息,以及根據賬號名和密碼查詢該用戶是否存在。

表5-1 用戶賬號信息表UserInfo

字段名

數據類型

關鍵字

約束

含義

id

int(20)

Y

unique

唯一標識符

username

varchar(20)

N

unique,not null

賬號名

Password

varchar(20)

N

not null

密碼

  由于數據庫操作涉及網絡傳輸及磁盤處理,因此屬于耗時操作。而在服務端框架Reactor反應池中的所有處理必須在非阻塞環境下進行,如果進行耗時操作將會阻塞當前線程,導致其它消息事件得不到及時處理。因此在Reactor中進行數據庫操作應該以異步的方式進行,可以通過創建工作線程池的方式處理數據庫等耗時操作。但是在本聊天系統中,只有在注冊新用戶和用戶登錄兩個場景中才涉及數據庫操作。為了簡化開發模型,我們在此直接調用數據庫相關的操作。

  數據庫部分并非本文論述重點,因此不再做進一步介紹。

聊天設備類型及消息事件實現

  通過分析功能需求,可以得知客戶端連接主要存在兩種狀態下的消息請求,分別為臨時狀態和登錄狀態。在臨時狀態下需要能夠請求注冊新用戶和登錄操作,在登錄狀態下需要能夠請求當前在線用戶信息,向某個用戶發送消息類型和廣播消息類型。并且由于服務器存在登錄超時的機制,客戶端連接不管在臨時狀態還是登錄狀態,均需定時向服務器發送心跳消息。

  客戶端的兩種狀態正好對應于服務端框架制定的兩種設備類型,即臨時設備類型和登錄設備類型。如圖5-1所示。我們為臨時設備添加新的注冊賬號消息事件,用于向所有與服務端建立了連接的客戶進行注冊操作。同時我們創建一個新的設備類型,名為ChatType設備類型,并且繼承于登錄設備類型,用于專門處理登錄后和聊天相關的消息事件。

?

圖5-1 聊天設備類型及消息事件

  臨時設備類型新添加的消息事件介紹如下:

  • l? registerUsr:注冊新的用戶賬號。客戶端在請求該消息事件時需同時傳入期待注冊的賬號名和密碼。服務器接收到該消息事件后,將校驗賬號名和密碼是否合法,然后調用數據庫新賬戶注冊接口,進行賬戶注冊。最后根據數據庫實際插入結果向客戶端發送注冊結果信息。由于該消息事件無需請求權限,任何連接該服務器的客戶均可進行注冊操作。為了防止存在某些客戶進行惡意注冊現象,在實際實現中添加了邀請碼信息。服務端將會驗證客戶端傳來的邀請碼是否正確,如果邀請碼正確才會實際進行注冊操作。
  • l? heartMsg:心跳消息。客戶端將會定期發送心跳消息。服務器接收到該消息事件后,將會在超時隊列更新該連接的超時信息。在事件回調實現中,并不會對該消息進行進一步業務處理,而是直接返回。

?

  ChatType為新創建的繼承于默認登錄設備的設備類型,具體實現的消息事件介紹如下:

  • l? askFriends:請求當前在線的用戶信息。客戶端會在登錄成功后,向服務器請求該消息事件。服務器收到該消息事件后,將會查詢除請求者外,當前其他所有在線的ChatType類型的用戶信息,并整理發送給客戶端。該數據用于客戶端對在線用戶列表的初始化工作。
  • l? chatSend:向一個指定在線用戶發送聊天消息。客戶端將會把聊天消息的內容,自己的信息,及期望接收該聊天消息的用戶信息發送給服務器。服務端接收到該消息事件后,將會嘗試找尋該接收用戶,并將聊天消息和發送者消息轉發給該接收用戶,并向發送用戶返回發送成功消息事件。如果該接收用戶并不在線,將只會向發送用戶返回發送失敗的消息事件。
  • l? groupSend:向全體在線用戶發送聊天消息。客戶端將會把聊天消息及自身信息發送給服務器。服務器接收到該消息后,將會遍歷除請求者外,當前其他所有在線的ChatType類型的用戶,并將該聊天消息和發送者信息轉發給所有遍歷的用戶,并向發送用戶返回發送成功的消息。
  • l? heartMsg:心跳消息。同臨時設備新添加的heartMsg的心跳消息。

聊天設備的生命周期實現

  雖然我們已經為聊天客戶端的連接制定了具體的設備類型和消息事件,但是一些和連接狀態相關的業務邏輯仍然需要我們設計。比如如何制定與聊天客戶端相關的具體登錄過程?當某個聊天客戶端已經成功登錄后,怎樣第一時間通知其他客戶端該賬號已上線?當某個聊天客戶端退出時,又如何通知其他客戶端該賬號已下線?這些與客戶端狀態相關的操作都依賴上一章節制定的連接生命周期機制來進行管理。

?

圖5-2 聊天設備的生命周期

  具體的聊天設備的連接生命周期實現如圖所示。我們只需對具體業務相關的生命周期接口的實現進行重寫即可,因此無需進行更改的生命周期接口并未被列出。需要被重寫的接口實現介紹如下:

  • l? onLoginCheckMsg():當客戶端執行登錄操作,且選擇登錄類型為ChatType設備類型時,將會執行該接口。此時系統將會檢查客戶端傳來的賬號名和密碼是否合法,如果合法將會調用數據庫的賬號密碼查詢接口,判斷該賬戶是否存在。如果該賬戶存在,則返回True,并將控制權交還給系統進行進一步的登錄操作;如果該賬戶不存在,則向該客戶端發送不存在該賬號信息,此次登錄失敗的消息,并直接返回False退出整個登錄操作。
  • l? onLoginSuccessMsg():當登錄類型為ChatType的客戶端進行登錄操作,執行onLoginCheckMsg()返回True,且系統整個登錄過程成功時,將會執行該接口。此時系統將會進行兩件工作:首先向該客戶端發送登錄成功的消息;其次將會遍歷除該用戶本身外的其他已登錄的ChatType類型的用戶,并向這些用戶發送通知消息表明該新用戶已上線。這樣每個登錄用戶只需在第一次登錄的時候向服務器請求當前所有在線用戶信息,而新的用戶上線或老用戶下線等信息將由服務器主動推送,而無需客戶端定期請求維護。
  • l? onLoginFailureMsg():當登錄類型為ChatType的客戶端進行登錄操作,執行onLoginCheckMsg()返回True,但整個登錄過程失敗時,將會執行該接口。一般該接口被執行將表明此用戶賬號已經被登錄,服務器無法對相同賬號進行重復登錄操作。此時服務器將會向客戶端發送重復登錄,此次登錄失敗的消息,并退出整個登錄操作。
  • l? onLogoutMsg():當登錄類型為ChatType的客戶端進行注銷操作時,將會執行該接口。服務器將向該客戶端返回注銷成功的消息,并對該連接進行進一步的注銷操作。
  • l? releaseConnNode():當登錄類型為ChatType的客戶端進行注銷成功,或者連接由于超時或者其它異常原因被迫退出時,將會執行該接口。此時服務器將會遍歷除該用戶本身外的其他已登錄的ChatType類型的用戶,并向這些用戶發送通知消息表明該用戶已經下線。同時系統將會把該用戶連接所申請的相關資源進行釋放工作。
  • l? onOverTime():當服務器一段時間內未收到該客戶端有效消息或心跳消息,將會被判超時,并執行該接口。一般執行該接口時表明該客戶端已經由于異常而停止工作,但是并未主動斷開連接。此時服務器將嘗試向該客戶端發送一條該連接已經超時的消息。由于客戶端已經處于異常狀態,并不能保證該條消息能夠被客戶端接收。然后服務器將會執行releaseConnNode()接口,并強制斷開該客戶端連接。

聊天系統展示

  該聊天系統部署于局域網內,并可通過C#實現的客戶端進行相關操作。運行場景截圖如下:

圖5-3 登錄及注冊窗口

  如圖5-3為客戶端的登錄窗口與注冊窗口。注冊窗口通過登錄窗口的注冊按鍵打開,并可進行新賬號的注冊操作。同時登錄窗口可以進行賬號的登錄操作,如果登錄失敗將會顯示具體失敗原因;如果登錄成功,將會進入客戶端主界面。

?

圖5-4 主界面及好友聊天窗口

  如圖5-4為客戶端的主界面及聊天窗口。在主界面中顯示了當前登錄的用戶名及當前在線的用戶名列及數量。可以單擊具體用戶名進入與該用戶的聊天窗口。在聊天窗口中,可以在輸入欄輸入消息,并點擊發送鍵或按下回車鍵發送該消息。如果收到其他用戶的聊天消息,客戶端也會主動彈出該用戶的聊天窗口,并顯示接收的的聊天信息。在主界面的下方還存在群聊按鍵,點擊可以進入群聊窗口。

?

圖5-5 群聊窗口

  如圖5-5為群聊窗口。在群聊窗口中可以接收到打開了該窗口的其他用戶發送的聊天信息。同時自己也能輸入相關聊天消息并發送給所有該窗口下的其他用戶。

轉載于:https://www.cnblogs.com/moyangvip/p/5586045.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/374519.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/374519.shtml
英文地址,請注明出處:http://en.pswp.cn/news/374519.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

高校實驗室管理系統_史上最全面的實驗室信息管理系統(LIMS)全解

1. LIMS的基本概念和發展狀況1.1 概括LIMS實驗室管理系統是為實驗、檢測等業務板塊提供流程化、模塊化、標準化操作管理系統,打造基于行業法規的實驗室全流程質量控制管理系統,實現實驗室“人、機、料、法、環”關鍵環節管理。1.2 發展狀況隨著科研規范化…

ORM問題

在過去的幾年中,像Hibernate這樣的對象關系映射工具已經幫助開發人員在處理關系數據庫方面取得了巨大的生產力增長。 ORM使開發人員可以將精力集中在應用程序邏輯上,并避免為諸如插入或查詢之類的簡單任務編寫大量樣板SQL。 但是,充分證明的對…

ActiveMQ中Session設置的相關理解

名詞解釋: P:生產者 C:消費者 服務端:P 或者 ActiveMQ服務 客戶端:ActiveMQ服務 或者 C 客戶端成功接收一條消息的標志是這條消息被簽收。成功接收一條消息一般包括如下三個階段: 1.客戶端接收…

python中的 descriptor

學好和用好python, descriptor是必須跨越過去的一個點,現在雖然Python書籍花樣百出,但是似乎都是在介紹一些Python庫而已,對Python語言本身的關注很少,或者即使關注了,但是能夠介紹把 dscriptor介紹清楚的&…

Heroku運行Java

如果您是像我這樣的Java迷,那么您有個好消息值得振奮。 Heroku現在運行Java! 嗯,與其他流行的“ Web”語言(如PHP / RoR)不同,Java具有在Web服務器中進行部署和維護的麻煩。 一直以來,只有企業才…

配置了坐標還是找不到serv_為什么老人家總是這疼那疼,還找不到原因?是矯情還是另有原因...

“哎呀,怎么回事,腰痛腿痛的,痛的我一晚上都沒怎么睡覺,怎么回事昨天也沒干嘛啊!”對于這一句話,相信很多朋友都不是很陌生。這句話是來自于一位網友的留言,而說這話的真是她的媽媽。這也是很多…

Nginx負載均衡和LVS負載均衡的比較分析

lvs和nginx都可以用作多機負載的方案,它們各有優缺,在生產環境中需要好好分析實際情況并加以利用。 首先提醒,做技術切不可人云亦云,我云即你云;同時也不可太趨向保守,過于相信舊有方式而等別人來幫你做墊被…

QuartZ.net 常用配置說明

配置文件說明app.config中的quartz部分<quartz><!-- configure Thread Pool--><addkey"quartz.threadPool.type"value"Quartz.Simpl.SimpleThreadPool,Quartz" /><addkey"quartz.threadPool.threadCount"value"10&quo…

qopenglwidget 透明_廊坊透明真空袋用途-祺泰包裝

功能方面&#xff1a;平面真空袋抽真空后易形成不平整&#xff0c;不均勻的現象。目前&#xff0c;真空包裝主要用于食品的包裝&#xff0c;如肉類、谷類加工食品以及易氧化變質的食品&#xff0c;也可用于機械零件、儀器和羽絨制品、毛制品等蓬松制品的包裝。在超shi中&#x…

使用Spring Data Neo4j進行領域建模

大家好&#xff0c;威利在這里。 上次我告訴您&#xff0c;我正在使用Neo4j和Spring Data Neo4j構建Skybase CMDB&#xff0c;我很高興收到很多對此的積極反饋。 我展示了一些代碼&#xff0c;但沒有那么多。 在本文中&#xff0c;我將向您展示如何使用Spring Data Neo4j在Skyb…

mysql 阿里內核人員

丁奇 http://dinglin.javaeye.com/鳴嵩 曹偉-鳴嵩 (新浪微博)彭立勛 http://www.penglixun.com/皓庭 http://wqtn22.iteye.com/項仲 http://blog.csdn.net/wudongxu劍川 http://gaoyusong.com/武藏 http://ybbct.iteye.com/祁奚 http://i.mtime.com/844165/褚霸 http://blog.y…

linux基本命令學習

1. 執行文件&#xff1a; ./文件 &#xff1a;執行該文件 sh startup.sh 執行該文件 2. Vi編輯 vi命令&#xff1a; :w 保存文件但不退出 :w file 將修改另外保存到file中&#xff0c;不退出 :w! 強制保存&#xff0c;不推出 :wq 保存文件并退出 :wq! 強制保存文件&#xff0…

506. 相對名次

方法一 復制數組排序返回對應下標 class Solution {public String[] findRelativeRanks(int[] score) {int n score.length;int[] newScore Arrays.copyOf(score,n);Arrays.sort(newScore);String[] res new String[n];for(int i 0;i<n;i){int rank Arrays.binarySear…

Java壓縮

在最近的項目中&#xff0c;我們不得不做一些我個人從未真正看過的事情。 壓縮。 我們需要拍幾個文件和圖像&#xff0c;將它們壓縮并提供給FTP使用&#xff0c;是的&#xff0c;總有一天&#xff0c;感覺確實回到了90年代。 除了過去的FTP之行外&#xff0c;它還是一個很好的機…

蘇州面對公司發布

假設您對我們這種創業型公司和我們的發展方向感興趣的話&#xff0c;我們希望通過以下10個問答進一步添加兩方的了解。我們希望看到的是您經過深思熟慮的、對公司和自己的前途負責任的謹慎回答。而不是應付公差式的輕描淡寫&#xff08;我們會依據您回答質量的高低決定是否邀請…

linux多線程_Java+Linux,深入內核源碼講解多線程之進程

之前寫了兩篇文章&#xff0c;都是針對Linux這個系統的&#xff0c;為什么?我為什么這么喜歡寫這個系統的知識&#xff0c;可能就是為了今天的內容多線程系列&#xff0c;現在多線程不是一個面試重點 啊&#xff0c;那如果你能深入系統內核回答這個知識點&#xff0c;面試官會…

594. 最長和諧子序列

和諧數組是指一個數組里元素的最大值和最小值之間的差別 正好是 1 。 現在&#xff0c;給你一個整數數組 nums &#xff0c;請你在所有可能的子序列中找到最長的和諧子序列的長度。 數組的子序列是一個由數組派生出來的序列&#xff0c;它可以通過刪除一些元素或不刪除元素、…

解決git clone報錯SSL certificate problem

Git新手一枚&#xff0c;今天進行git clone操作時發生如下問題&#xff1a;提示無效的鏈接error: SSL certificate problem: Invalid certificate chain while accessing https://githib.com/...XXXX.git fatal: HTTP request failed解決方法也很簡單&#xff0c;一條命令就搞定…

使用內存映射文件獲取巨大的矩陣

總覽 矩陣可能真的很大&#xff0c;有時甚至比一個數組中可以容納的更大。 您可以通過具有多個數組來擴展最大大小&#xff0c;但這會使堆大小確實很大且效率低下。 一種替代方法是在內存映射文件上使用包裝器。 內存映射文件的優點是它們對堆的影響很小&#xff0c;并且可以由…

ipad連接電腦_這些應用讓iPad生產力分分鐘UP

IT時報見習記者 錢奕昀用iPad辦公這件事&#xff0c;多年前網友就在討論&#xff0c;最常見的還是那句“買前生產力&#xff0c;買后愛奇藝”。很長一段時間里&#xff0c;它的生產力屬性都是弱于娛樂屬性的。其實&#xff0c;作為PC端和移動端的形態中和&#xff0c;iPad可以…