微服務即時通信系統(十二)---入口網關子服務

目錄

功能設計

模塊劃分

業務接口/功能示意圖

服務實現流程

網關HTTP接口

網關WebSocket接口

總體流程

服務代碼實現

客戶端長連接管理封裝(connectionManage.hpp)

proto文件的編寫

身份鑒權proto

事件通知proto

各項請求的URL的確定

服務端完成入口網關服務類(GatewayServer),進行其中的各項功能函數(請求處理函數)的實現

宏定義個功能請求的URL

GatewayServer類的成員變量和構造函數

WebSocketServer的三個回調函數實現

Speech::SpeechRecognize語音識別請求處理

File::SingleFileUp單文件上傳/發送單文件請求處理

File::MultiFileUp多文件上傳/發送多文件請求處理

File::SingleFileDonw單文件下載/獲取單文件數據請求處理

File::MultiFileDonw多文件下載/獲取多文件數據請求處理

User::UserNicknameRegistr用戶名注冊請求處理

User::UserNicknameLogin用戶名登陸請求處理

User::GetPhoneVerificationCode獲取手機驗證碼請求處理

User::UserPhoneRegister手機號注冊請求處理

User::UserPhoneLogin手機號登陸請求處理

User::GetOneUserInfo獲取用戶信息請求處理

User::SetUserAvatar設置用戶頭像請求處理

User::SetUserNickname設置用戶昵稱請求處理

User::SetUserDescription設置用戶簽名請求處理

User::SetUserPhone設置用戶手機號請求處理

Transmite::SendNewMessage發送新消息請求處理

Store::GetRecentNMessage獲取最近N條消息請求處理

Store::GetTimeRangeMessage獲取時間段消息請求處理

Store::GetMessageByKeyword消息關鍵字搜索請求處理

Friend::GetFriendList獲取好友列表請求處理

Friend::UserSearch用戶搜索請求處理

Friend::ApplyAddFriend申請添加好友請求處理

Friend::GetFriendApplyList獲取好友申請列表請求處理

Friend::FriendApplyEventHandle處理好友申請事件請求處理

Friend::RemoveFriend刪除好友請求處理

Friend::GetChatSessionList獲取聊天會話列表請求處理

Friend::CreateGroupChatSession創建群聊會話請求處理

Friend::GetChatSessionMember獲取會話成員請求處理

完成入口網關服務類的構造者(GatewayServerBuilder)

實例化服務對象,啟動服務

工程系統構建配置文件(CMakeLists.txt)


本章節,主要對項目中入口網關子服務模塊進行分析、開發與測試。

功能設計

入口網關子服務在設計中,最重要的兩個功能:

1、接收客戶端的所有請求,并解析,然后進行請求的子服務分發,得到響應后,再響應給客戶端。(其中這些請求再細化為具體的各項請求,一共28個)。

2、對客戶端進行事件通知:好友申請、申請處理、刪除好友、聊天會話的創建、新消息。

基于上述兩個功能,入口網關子服務包含兩種通信:

1、HTTP通信:進行接收請求,業務處理。

2、WebSocket通信:進行事件通知。

模塊劃分

參數/配置文件解析模塊基于gflags框架直接使用,進行參數/配置文件的解析。
日志模塊基于spdlog封裝的logger 直接進行日志輸出。
服務發現與調用模塊

基于etcd框架封裝的服務發現與brpc框架封裝的服務調用模塊。

因為要分發處理所有請求,需要發現所有的子服務模塊。

redis客戶端模塊

基于redis++封裝的客戶端進行內存數據庫的操作。

根據用戶管理子服務添加的登錄會話信息,進行用戶的身份鑒權和識別。

HTTP通信服務器模塊基于httplib搭建HTTP服務器,接收HTTP請求,進行業務處理。
WebSocket服務器模塊基于WebSocketpp,搭建WebSocket服務器,進行事件通知。
客戶端長連接Connection管理模塊通過用戶ID 和 長連接句柄 建立映射關系,對長連接進行封裝,便于后續管理。

業務接口/功能示意圖

服務實現流程

網關HTTP接口

HTTP通信,分為首行、頭部和正文三部分。

首行中的URL明確了業務請求目標(目的地)。

頭部進行正文或連接描述。

正文中包含請求或響應的內容。

因此,之后實現的時候,首先就要確定各項URL。

其次,在HTTP請求正文中,將采用protobuf協議作為正文的序列化方式。不同的請求正文與后臺的請求基本上吻合,因此,請求正文結構 將與 后臺服務之間復用同一套接口。

網關WebSocket接口

WebSocket通信接口中,包含兩個方面:

1、長連接的身份識別。

當用戶登陸成功之后,向服務器發送WebSocket長連接請求,建立長連接。

長連接建立成功之后,向服務器發送身份鑒權請求,請求內容為protobuf結構數據,包含內容:請求ID、登錄會話ID。

該請求不需要服務端進行回復,鑒權成功則長連接保持,否則斷開長連接即可。

2、事件通知的內容。

因為事件通知在長連接中進行,因此,只需要定義出事件通知的消息結構即可。

總體流程

0、完成客戶端長連接管理的封裝。
1、編寫服務所需的proto文件,利用protoc工具生成RPC服務器所需的.pb.h 和 .pb.cc 項目文件。
2、完成各項功能函數(請求)的URL的編寫。
3、服務端完成入口網關服務類,進行其中的各項功能函數(請求處理函數)的實現。
4、實例化服務器對象,啟動服務。

服務代碼實現

客戶端長連接管理封裝(connectionManage.hpp)

在該封裝中,提供了4個API:

1、新增長連接管理。

2、移除長連接。

3、獲取長連接。

4、通過長連接獲取對應用戶(客戶端)信息。

#pragma once
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
#include "logger.hpp"namespace yangz
{typedef websocketpp::server<websocketpp::config::asio> websocket_server; // 簡單重定義websocket_server類型// 此時, 長連接的類型: websocket_server::connection_ptrclass Connection{public:// 長連接客戶端 -> user_id, login_session_idstruct Client{Client(const std::string &uid, const std::string &lssid) : user_id(uid), login_session_id(lssid) {}std::string user_id;std::string login_session_id;};using ptr = std::shared_ptr<Connection>;Connection() {}~Connection() {}public:// 新增長連接管理void append(const websocket_server::connection_ptr &connection, const std::string &user_id, const std::string &login_session_id){// connection_ptr是weak_ptr, 需要get獲取shared_ptrstd::unique_lock<std::mutex> lock(_mutex);_userid_connections.insert({user_id, connection});_connection_clients.insert({connection, Client(user_id, login_session_id)});LOG_DEBUG("新增長連接用戶信息, connection_ptr: {}, user_id: {}, login_session_id: {}", (size_t)connection.get(), user_id, login_session_id);}// 移除長連接void remove(const websocket_server::connection_ptr &connection){std::unique_lock<std::mutex> lock(_mutex);auto it = _connection_clients.find(connection);if (it == _connection_clients.end()){LOG_ERROR("刪除長連接時, 未找到該長連接, connection_ptr: {}", (size_t)connection.get());return;}_userid_connections.erase(it->second.user_id);_connection_clients.erase(it);LOG_DEBUG("移除長連接成功");}// 獲取該長連接websocket_server::connection_ptr get_connection(const std::string &user_id){std::unique_lock<std::mutex> lock(_mutex);auto it = _userid_connections.find(user_id);if (it == _userid_connections.end()){LOG_ERROR("獲取長連接時, 沒有找到該長連接, user_id: {}", user_id);return websocket_server::connection_ptr();}return it->second;}// 判斷該用戶是否已經建立了長連接, 同時獲取user_id 和 login_session_idbool client_is_connect(const websocket_server::connection_ptr &connection, std::string &user_id, std::string &login_session_id){std::unique_lock<std::mutex> lock(_mutex);auto it = _connection_clients.find(connection);if (it == _connection_clients.end()){LOG_ERROR("獲取用戶信息時, 該用戶并沒有建立長連接");return false;}user_id = it->second.user_id;login_session_id = it->second.login_session_id;return true;}private:std::mutex _mutex;std::unordered_map<std::string, websocket_server::connection_ptr> _userid_connections; // <user_id, 長連接>std::unordered_map<websocket_server::connection_ptr, Client> _connection_clients;      // <長連接, [user_id, login_session_id]>};
}

proto文件的編寫

身份鑒權proto

入口網關子服務首先根據用戶請求中攜帶信息,通過長連接獲取到客戶端信息,然后根據redis數據庫中的信息進行審核。

因此,只需要一個簡單的protobuf結構的信息:user_id, login_session_id即可:

syntax = "proto3";
package yangz;
option cc_generic_services = true;// 用戶身份鑒權請求
message ClientIdentityAuthenticationReq
{string req_id = 1;string login_session_id = 2; // 登錄會話ID, 網關根據該字段識別長連接客戶端的身份
};

事件通知proto

在該proto文件中,要定義出來需要被通知的事件的protobuf結構數據:申請添加好友、處理申請結構、刪除好友、創建群聊、發送新消息。

syntax = "proto3";
package yangz;
import "base.proto";option cc_generic_services = true;enum MessageNotifyType
{APPLY_ADD_FRIEND_NOTIFY = 0; // 申請添加好友FRIEND_APPLY_EVENT_HANDLE_NOTIFY = 1; // 處理好友申請REMOVE_FRIEND_NOTIFY = 2; // 刪除好友CREATE_GROUP_CHAT_SESSION_NOTIFY = 3; // 創建群聊NEW_MESSAGE_NOTIFY = 4; // 新消息
}// 申請添加好友
message ApplyAddFriendNotify
{UserInfo user_info = 1; // 申請人信息
};// 好友申請請求處理
message FriendApplyEventHandleNotify
{bool agree = 1;UserInfo user_info = 2; // 處理人信息
};// 刪除好友
message RemoveFriendNotify
{string user_id = 1; // 主動刪除者的用戶ID
};// 創建群聊
message CreateGroupChatSessionNotify
{ChatSessionInfo chat_session_info = 1; // 聊天會話信息
};// 新聊天消息
message NewMessageNotify
{MessageInfo message_info = 1; // 消息元信息
};message NotifyMessage
{optional string notify_event_id = 1; // 通知事件IDMessageNotifyType notify_type = 2;oneof notify_remarks // 事件備注信息{ApplyAddFriendNotify apply_add_friend = 3;FriendApplyEventHandleNotify friend_apply_event_handle = 4;RemoveFriendNotify remove_friend = 5;CreateGroupChatSessionNotify create_group_chat_session = 6;NewMessageNotify new_message = 7;}
};

各項請求的URL的確定

對于客戶端的請求,該項目中一共提供28個請求功能,分別對應到各個子服務中,因此,需要提供28個URL,來對應子服務下的對應功能。

并且客戶端的請求采用HTTP模式進行通信,通信時采用Post作為請求方法。

SERVICE HHTP PATH:// 語音識別子服務
/service/speech_recognition/speech_recognize        語音識別// 文件管理子服務
/service/file_manage/up_single_file                 發送/上傳單個文件
/service/file_manage/up_multi_file                  發送/上傳多個文件
/service/file_manage/donw_single_file               獲取/下載單個文件
/service/file_manage/donw_single_file               獲取/下載多個文件// 用戶管理子服務
/service/user_manage/user_nickname_registr          用戶名注冊
/service/user_manage/user_nickname_login            用戶名登陸
/service/user_manage/get_phone_verification_code    獲取手機驗證碼
/service/user_manage/user_phone_registr             手機號注冊
/service/user_manage/user_phone_login               手機號登陸
/service/user_manage/get_one_user_info              獲取單個用戶信息
/service/user_manage/set_user_avatar                修改頭像
/service/user_manage/set_user_nickname              修改昵稱
/service/user_manage/set_user_description           修改簽名
/service/user_manage/set_user_phone                 修改手機號// 消息轉發子服務
/service/message_transmite/send_new_message         發送新消息// 消息存儲子服務
/service/message_store/get_recent_n_message         獲取最近N條消息
/service/message_store/get_time_range_message       獲取指定時間段消息
/service/message_store/get_message_by_keyword       消息關鍵字搜索// 好友管理子服務
/service/friend_manage/get_friend_list              獲取好友列表
/service/friend_manage/user_search                  用戶搜索
/service/friend_manage/apply_add_friend             申請添加好友
/service/friend_manage/get_friend_apply_list        獲取好友申請列表
/service/friend_manage/friend_apply_event_handle    處理好友申請
/service/friend_manage/remove_friend                刪除好友
/service/friend_manage/get_chat_session_list        獲取聊天會話列表
/service/friend_manage/create_group_chat_session    創建群聊會話
/service/friend_manage/get_chat_session_member      獲取聊天會話成員

服務端完成入口網關服務類(GatewayServer),進行其中的各項功能函數(請求處理函數)的實現

宏定義個功能請求的URL

// 各功能請求的URL
// speech_recognition_service
#define SPEECH_RECOGNITION "/service/speech_recognition/speech_recognize"// file_manage_service
#define UP_SINGLE_FILE "/service/file_manage/up_single_file"
#define UP_MULTI_FILE "/service/file_manage/up_multi_file"
#define DONW_SINGLE_FILE "/service/file_manage/donw_single_file"
#define DONW_MULTI_FILE "/service/file_manage/donw_multi_file"// user_manage_service
#define USER_NICKNAME_REGISTR "/service/user_manage/user_nickname_registr"
#define USER_NICKNAME_LOGIN "/service/user_manage/user_nickname_login"
#define GET_PHONE_VERIFICATION_CODE "/service/user_manage/get_phone_verification_code"
#define USER_PHONE_REGISTR "/service/user_manage/user_phone_registr"
#define USER_PHONE_LOGIN "/service/user_manage/user_phone_login"
#define GET_ONE_USER_INFO "/service/user_manage/get_one_user_info"
#define SET_USER_AVATAR "/service/user_manage/set_user_avatar"
#define SET_USER_NICKNAME "/service/user_manage/set_user_nickname"
#define SET_USER_DESCRIPTION "/service/user_manage/set_user_description"
#define SET_USER_PHONE "/service/user_manage/set_user_phone"// message_transmite_service
#define SEND_NEW_MESSAGE "/service/message_transmite/send_new_message"// message_store_service
#define GET_RECENT_N_MESSAGE "/service/message_store/get_recent_n_message"
#define GET_TIME_RANGE_MESSAGE "/service/message_store/get_time_range_message"
#define GET_MESSAGE_BY_KEYWORD "/service/message_store/get_message_by_keyword"// friend_manage_service
#define GET_FRIEND_LIST "/service/friend_manage/get_friend_list"
#define USER_SEARCH "/service/friend_manage/user_search"
#define APPLY_ADD_FRIEND "/service/friend_manage/apply_add_friend"
#define GET_FRIEND_APPLY_LIST "/service/friend_manage/get_friend_apply_list"
#define FRIEND_APPLY_EVENT_HANDLE "/service/friend_manage/friend_apply_event_handle"
#define REMOVE_FRIEND "/service/friend_manage/remove_friend"
#define GET_CHAT_SESSION_LIST "/service/friend_manage/get_chat_session_list"
#define CREATE_GROUP_CHAT_SESSION "/service/friend_manage/create_group_chat_session"
#define GET_CHAT_SESSION_MEMBER "/service/friend_manage/get_chat_session_member"

GatewayServer類的成員變量和構造函數

先定義各成員變量,然后進行列表初始化。

隨后在構造函數中,對websocket服務器進行初始化:設置建立長連接/關閉長連接/新消息到來的回調處理函數。

再對http服務器進行初始化:設置客戶端的Post請求處理方法,一共28個,之后再具體實現28個請求處理方法函數。

    class GatewayServer{public:using ptr = std::shared_ptr<GatewayServer>;GatewayServer(const std::shared_ptr<sw::redis::Redis> &redis_client,const std::string &speech_recognition_service_name,const std::string &file_manage_service_name,const std::string &user_manage_service_name,const std::string &message_transmite_service_name,const std::string &message_store_service_name,const std::string &friend_manage_service_name,const ServiceDiscovery::ptr &sd_client,const ServiceChannelManager::ptr &channel_manager,int websocket_port,int http_port): _redis_login_session_client(std::make_shared<LoginSessionManage>(redis_client)),_redis_login_status_client(std::make_shared<LoginStatusManage>(redis_client)),_speech_recognition_service_name(speech_recognition_service_name),_file_manage_service_name(file_manage_service_name),_user_manage_service_name(user_manage_service_name),_message_transmite_service_name(message_transmite_service_name),_message_store_service_name(message_store_service_name),_friend_manage_service_name(friend_manage_service_name),_sd_client(sd_client),_channel_manager(channel_manager),_connections(std::make_shared<Connection>()){// init websocket server_websocket_server.set_access_channels(websocketpp::log::alevel::none);                                                                     // 關閉日志輸出_websocket_server.init_asio();                                                                                                             // 初始化websocket的異步IO_websocket_server.set_open_handler(std::bind(&GatewayServer::open_callback, this, std::placeholders::_1));                                 // 設置websocket握手成功后的回調函數_websocket_server.set_close_handler(std::bind(&GatewayServer::close_callback, this, std::placeholders::_1));                               // 設置websocket連接關閉的回調函數_websocket_server.set_message_handler(std::bind(&GatewayServer::newmessage_callback, this, std::placeholders::_1, std::placeholders::_2)); // 設置websocket新消息的回到處理函數_websocket_server.set_reuse_addr(true);                                                                                                    // 啟動地址重用_websocket_server.listen(websocket_port);                                                                                                  // 開始監聽_websocket_server.start_accept();                                                                                                          // 開始接收連接請求// init http server// 即設置各種客戶端Post請求的回調處理函數, 即28各功能請求處理函數// Port(URL, (httplib::Server::Handler)call_back)// speech_recognition_service_http_server.Post(SPEECH_RECOGNITION, (httplib::Server::Handler)std::bind(&GatewayServer::SpeechRecognize, this, std::placeholders::_1, std::placeholders::_2));// file_manage_service_http_server.Post(UP_SINGLE_FILE, (httplib::Server::Handler)std::bind(&GatewayServer::SingleFileUp, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(UP_MULTI_FILE, (httplib::Server::Handler)std::bind(&GatewayServer::MultiFileUp, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(DONW_SINGLE_FILE, (httplib::Server::Handler)std::bind(&GatewayServer::SingleFileDown, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(DONW_MULTI_FILE, (httplib::Server::Handler)std::bind(&GatewayServer::MultiFileDown, this, std::placeholders::_1, std::placeholders::_2));// user_manage_service_http_server.Post(USER_NICKNAME_REGISTR, (httplib::Server::Handler)std::bind(&GatewayServer::UserNicknameRegistr, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(USER_NICKNAME_LOGIN, (httplib::Server::Handler)std::bind(&GatewayServer::UserNicknameLogin, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(GET_PHONE_VERIFICATION_CODE, (httplib::Server::Handler)std::bind(&GatewayServer::GetPhoneVerificationCode, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(USER_PHONE_REGISTR, (httplib::Server::Handler)std::bind(&GatewayServer::UserPhoneRegister, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(USER_PHONE_LOGIN, (httplib::Server::Handler)std::bind(&GatewayServer::UserPhoneLogin, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(GET_ONE_USER_INFO, (httplib::Server::Handler)std::bind(&GatewayServer::GetOneUserInfo, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(SET_USER_AVATAR, (httplib::Server::Handler)std::bind(&GatewayServer::SetUserAvatar, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(SET_USER_NICKNAME, (httplib::Server::Handler)std::bind(&GatewayServer::SetUserNickname, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(SET_USER_DESCRIPTION, (httplib::Server::Handler)std::bind(&GatewayServer::SetUserDescription, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(SET_USER_PHONE, (httplib::Server::Handler)std::bind(&GatewayServer::SetUserPhone, this, std::placeholders::_1, std::placeholders::_2));// message_transmite_service_http_server.Post(SEND_NEW_MESSAGE, (httplib::Server::Handler)std::bind(&GatewayServer::SendNewMessage, this, std::placeholders::_1, std::placeholders::_2));// message_store_service_http_server.Post(GET_RECENT_N_MESSAGE, (httplib::Server::Handler)std::bind(&GatewayServer::GetRecentNMessage, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(GET_TIME_RANGE_MESSAGE, (httplib::Server::Handler)std::bind(&GatewayServer::GetTimeRangeMessage, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(GET_MESSAGE_BY_KEYWORD, (httplib::Server::Handler)std::bind(&GatewayServer::GetMessageByKeyword, this, std::placeholders::_1, std::placeholders::_2));// friend_manage_service_http_server.Post(GET_FRIEND_LIST, (httplib::Server::Handler)std::bind(&GatewayServer::GetFriendList, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(USER_SEARCH, (httplib::Server::Handler)std::bind(&GatewayServer::UserSearch, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(APPLY_ADD_FRIEND, (httplib::Server::Handler)std::bind(&GatewayServer::ApplyAddFriend, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(GET_FRIEND_APPLY_LIST, (httplib::Server::Handler)std::bind(&GatewayServer::GetFriendApplyList, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(FRIEND_APPLY_EVENT_HANDLE, (httplib::Server::Handler)std::bind(&GatewayServer::FriendApplyEventHandle, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(REMOVE_FRIEND, (httplib::Server::Handler)std::bind(&GatewayServer::RemoveFriend, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(GET_CHAT_SESSION_LIST, (httplib::Server::Handler)std::bind(&GatewayServer::GetChatSessionList, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(CREATE_GROUP_CHAT_SESSION, (httplib::Server::Handler)std::bind(&GatewayServer::CreateGroupChatSession, this, std::placeholders::_1, std::placeholders::_2));_http_server.Post(GET_CHAT_SESSION_MEMBER, (httplib::Server::Handler)std::bind(&GatewayServer::GetChatSessionMember, this, std::placeholders::_1, std::placeholders::_2));// http 新啟線程, 放置阻塞等待消息, 并分離_http_thread = std::thread([this, http_port](){ _http_server.listen("0.0.0.0", http_port); });_http_thread.detach();}// 服務器啟動void start(){_websocket_server.run();}private:// redisLoginSessionManage::ptr _redis_login_session_client; // 登錄會話操作句柄LoginStatusManage::ptr _redis_login_status_client;   // 登陸狀態操作句柄// service namestd::string _speech_recognition_service_name;std::string _file_manage_service_name;std::string _user_manage_service_name;std::string _message_transmite_service_name;std::string _message_store_service_name;std::string _friend_manage_service_name;// service discoverServiceDiscovery::ptr _sd_client; // etcd.hpp中服務發現的操作句柄// channel managerServiceChannelManager::ptr _channel_manager; // 通信信道, 用于和子服務建立連接// connectionConnection::ptr _connections;// wevsocket & httpwebsocket_server _websocket_server;httplib::Server _http_server;std::thread _http_thread; // http新線程, 異步執行, 放置阻塞等候};

WebSocketServer的三個回調函數實現

握手成功回調函數:

簡單打印日志提示。

        // websocket握手成功后的回調函數void open_callback(websocketpp::connection_hdl hdl){LOG_DEBUG("websocket長連接建立成功, connection: {}", (size_t)_websocket_server.get_con_from_hdl(hdl).get());}

連接關閉回調函數:

1、清理對應的connection緩存。

2、日志打印提示。

        // websocket連接關閉的回調函數void close_callback(websocketpp::connection_hdl hdl){// 1. 獲取到connectionauto connection = _websocket_server.get_con_from_hdl(hdl);// 2. 通過connection獲取到客戶端信息std::string user_id, login_session_id;bool res = _connections->client_is_connect(connection, user_id, login_session_id);if (res == false){LOG_WARN("長連接斷開時, 未找到客戶端信息");return;}// 3. 移除相關管理信息_redis_login_session_client->remove(login_session_id);_redis_login_status_client->remove(user_id);_connections->remove(connection);LOG_DEBUG("長連接斷開, 清理緩存完成");}

新消息到來回調函數:

1、獲取其中的connection。

2、將消息正文反序列化。

3、提取login_session_id。

4、根據login_session_id在redis中進行身份查找。

5、添加長連接管理。

6、長連接進行保活。

        // 設置websocket新消息的回到處理函數void newmessage_callback(websocketpp::connection_hdl hdl, websocket_server::message_ptr message){// 1. 獲取connectionauto connection = _websocket_server.get_con_from_hdl(hdl);// 2. 將消息中的ClientIdentityAuthenticationReq進行反序列化獲取ClientIdentityAuthenticationReq req

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

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

相關文章

存儲器層次結構:理解計算機記憶的金字塔

存儲器層次結構&#xff1a;理解計算機記憶的金字塔 在計算機系統中&#xff0c;“速度”與“成本”常常處于對立面。為了在速度與成本之間取得平衡&#xff0c;計算機體系結構采用了一種名為“存儲器層次結構&#xff08;Memory Hierarchy&#xff09;”的設計思想。本文將通…

HTTP 錯誤 500.19 - Internal Server Error

1.HTTP 錯誤 500.19 - Internal Server Error NetCore項目托管到IIS后&#xff0c;報錯如下&#xff1a; 原因是因為IIS中沒有安裝AspNetCoreModuleV2導致的&#xff0c; 1.打開IIS 2.選中服務器根節點&#xff0c;找到模塊&#xff0c;雙擊進入&#xff0c;確認模塊中是否存…

【c++】【STL】stack詳解

目錄 stack類的作用什么是容器適配器stack的接口構造函數emptysizetoppushpopswap關系運算符重載 stack類的實現 stack類的作用 stack是stl庫提供的一種容器適配器&#xff0c;也就是我們數據結構中學到的棧&#xff0c;是非常常用的數據結構&#xff0c;特點是遵循LIFO&#…

K8s學習與實踐

一、Kubernetes 核心原理 1. Kubernetes 設計哲學 Kubernetes&#xff08;k8s&#xff09;是一個開源的容器編排平臺&#xff0c;旨在自動化容器化應用的部署、擴展和管理。其核心設計圍繞以下目標&#xff1a; 聲明式配置&#xff1a;用戶描述期望狀態&#xff08;如 YAML …

Umi-OCR項目(1)

最近接觸到了一個項目&#xff0c;我在想能不能做出點東西出來。 目標&#xff1a;識別一張帶表格的圖片&#xff0c;要求非表格內容和表格內容都要識別得很好&#xff0c;并且可視化輸出為word文檔。 下面是第一步的測試代碼&#xff0c;測試是否能夠調用ocr能力。 import re…

Mioty|采用報文分割(Telegram Splitting)以提高抗干擾能力的無線通信技術【無線通信小百科】

1、什么是Mioty 在物聯網&#xff08;IoT&#xff09;快速發展的背景下&#xff0c;低功耗廣域網&#xff08;LPWAN&#xff09;技術成為連接海量設備的關鍵。LPWAN具有低功耗、低成本、廣覆蓋和強抗干擾能力等特點&#xff0c;使其特別適用于大規模、遠距離、低數據速率的IoT…

TCP三次握手、四次揮手+多線程并發處理

目錄 一、三次握手建立連接 1.1 標記位 1.2 三次握手的過程 二、四次揮手斷開連接 三、模擬服務器和客戶端收發數據 四、多線程并發處理 五、TCP粘包問題 5.1 什么是TCP粘包&#xff1f; 5.2 TCP粘包會有什么問題&#xff1f; 5.3 TCP粘包的解決方法&#xff1f; 一、三…

使用HunyuanVideo搭建文本生視頻大模型

1.摘要 HunyuanVideo是一個全新的開源視頻基礎模型&#xff0c;其視頻生成性能堪比領先的閉源模型&#xff0c;甚至超越它們。我們采用了多項模型學習的關鍵技術&#xff0c;通過有效的模型架構和數據集擴展策略&#xff0c;我們成功訓練了一個擁有超過 130 億個參數的視頻生成…

LabVIEW圓錐滾子視覺檢測系統

基于LabVIEW平臺的視覺檢測系統提高圓錐滾子內組件的生產質量和效率。通過集成高分辨率攝像頭和先進的圖像處理算法&#xff0c;系統能夠自動識別和分類產品缺陷&#xff0c;從而減少人工檢查需求&#xff0c;提高檢測的準確性和速度。 ?? ? 項目背景 隨著制造業對產品質…

mac 基于Docker安裝minio服務器

在 macOS 上基于 Docker 安裝 MinIO 是一個高效且靈活的方案&#xff0c;尤其適合本地開發或測試環境。以下是詳細的安裝與配置步驟&#xff0c;結合了最佳實踐和常見問題的解決方案&#xff1a; 一、安裝 Docker Desktop 下載安裝包 訪問 Docker 官網&#xff0c;下載適用于 …

EchoMimicV2 部署記錄

在這里插入代碼片# 虛擬環境配置 pip install pip -U pip install torch2.5.1 torchvision0.20.1 torchaudio2.5.1 xformers0.0.28.post3 --index-url https://download.pytorch.org/whl/cu124 pip install torchao --index-url https://download.pytorch.org/whl/nightly/cu1…

數據升降級:醫療數據的“時空穿梭“系統工程(分析與架構篇)

一、核心挑戰與量化分析 1. 版本演化困境的深度解析 (1) 格式斷層的結構化危機 數據轉換黑洞:某醫療信息平臺(2021-2023)統計顯示: 數據類型CDA R1→R2轉換失敗率R2→FHIR轉換失敗率關鍵失敗點診斷記錄28.4%19.7%ICD編碼版本沖突(18.7%)用藥記錄15.2%12.3%劑量單位標準化…

個人開發免費好用

聊一聊 現在輸入法非常多&#xff0c;有時候都不知道哪個更好用。 其實&#xff0c;只有多嘗試&#xff0c;才能找到適合自己的。 今天給大家分享一款輸入法&#xff0c;用起來比較順手&#xff0c;大家可以試試。 軟件介紹 BL輸入法 這是一款綠色純凈&#xff0c;安全放心…

Windows查看和修改IP,IP互相ping通

Windows系統 查看IP地址 winr 輸入cmd 打開終端使用 ipconfig 或 ipconfig -all 命令查看當前網絡 IPV4地址 Windows系統 修改IP地址 自動獲取IP&#xff08;DHCP&#xff09;&#xff1a; 打開 控制面板&#xff0c;點擊 網絡和Internet。點擊 網絡和共享中心。選擇 更改適配…

【IP101】圖像處理基礎:從零開始學習顏色操作(RGB、灰度化、二值化、HSV變換)

&#x1f3a8; 顏色操作詳解 &#x1f31f; 在圖像處理的世界里&#xff0c;顏色操作就像是一個魔術師的基本功。今天&#xff0c;讓我們一起來解鎖這些有趣又實用的"魔法"吧&#xff01; &#x1f4da; 目錄 通道替換 - RGB與BGR的"調包"游戲灰度化 - 讓…

windows系統搭建自己的ftp服務器,保姆級教程(用戶驗證+無驗證)

前言 最近在搭建環境時&#xff0c;我發現每次都需要在網上下載依賴包和軟件&#xff0c;這不僅耗時&#xff0c;而且有時還會遇到網絡不穩定的問題&#xff0c;導致下載速度慢或者中斷&#xff0c;實在不太方便。于是&#xff0c;我產生了搭建一個FTP服務器的想法。通過搭建FT…

藍橋杯 7. 晚會節目單

晚會節目單 原題目鏈接 題目描述 小明要組織一臺晚會&#xff0c;總共準備了 n 個節目。然而晚會時間有限&#xff0c;他只能從中選擇 m 個節目。 這 n 個節目是按照小明設想的順序給定的&#xff0c;順序不能改變。 小明發現觀眾對于晚會的喜歡程度與前幾個節目的好看程度…

JavaScript如何實現類型判斷?

判斷一個數據的類型&#xff0c;常用的方法有以下幾種&#xff1a; typeofinstanceofObject.prototype.toString.call(xxx) 下面來分別分析一下這三種方法各自的優缺點 typeof typeof的本意是用來判斷一個數據的數據類型&#xff0c;所以返回的也是一個數據類型。但是會遇到下…

哈希表筆記(四)Redis對比Java總結

文章目錄 一、基礎結構對比數據結構定義Java HashMapRedis字典 主要區別與設計思路 二、關鍵操作API對比初始化Java HashMapRedis字典 添加元素Java HashMapRedis字典 查找元素Java HashMapRedis字典 刪除元素Java HashMapRedis字典 擴容/重哈希操作Java HashMapRedis字典 三、…

docker拉取國內鏡像

1. 場景 最近整了一個tencent云服務器&#xff0c;想要玩一下docker&#xff0c;結果發現拉不下來&#xff0c;鏡像根本拉不下來。 2. 原因 1.云服務器無法訪問外網&#xff1b; 2. 國內的很多公有鏡像倉庫都被封了&#xff1b; 3. 推薦 https://zhuanlan.zhihu.com/p/713…