C++編寫的WebSocket服務(wù)端客戶端實(shí)現(xiàn)示例代碼
使用過標(biāo)準(zhǔn)的libwebsockets服務(wù)端庫測試過,主要是短小精悍,相對于libwebsockets不需要依賴zlib和openssl 以及其他庫,直接make就可以使用了,linux跟windows都可以使用。
測試用例:
#include "easywsclient.hpp" #include <assert.h> #include <stdio.h> #include <string> using easywsclient::WebSocket; static WebSocket::pointer ws = NULL; void handle_message(const std::string & message) { printf(">>> %s\n", message.c_str()); if (message == "world") { ws->close(); } } int main() { ws = WebSocket::from_url("ws://localhost:8126/foo"); assert(ws);//判斷ws對象是否為空null ws->send("goodbye"); ws->send("hello"); //如果你需要多線程,可以在一個(gè)thread 維護(hù)該ws的連接重連機(jī)制 while (ws->getReadyState() != WebSocket::CLOSED) //判斷ws是否正常連接 { ws->poll();//這個(gè)必須要調(diào)用,否則不能發(fā)送,發(fā)送跟接收都是異步的,都是在這個(gè)poll函數(shù)里監(jiān)測處理的 ws->dispatch(handle_message); } delete ws; return 0; }
//線程thread 維護(hù)重連連接 void run() { bool conn = FLASE; ws = WebSocket::from_url("ws://localhost:8126/foo"); //如果你需要多線程,可以在一個(gè)thread 維護(hù)該ws的連接重連機(jī)制 while (1) //判斷ws是否正常連接 { if(ws != NULL) { ws->poll(0);//這個(gè)必須要調(diào)用,否則不能發(fā)送,發(fā)送跟接收都是異步的,都是在這個(gè)poll函數(shù)里監(jiān)測處 理的 ws->dispatch(handle_message); if(ws->getReadyState() == WebSocket::CLOSED) { //ws連接斷開 重連 delete ws; ws = NULL; ws = WebSocket::from_url("ws://localhost:8126/foo"); } else if(wss->getReadyState()== WebSocket::OPEN) { //ws連接ok // ws->send("goodbye"); ws->send("hello"); } } else { ws = WebSocket::from_url("ws://localhost:8126/foo"); sleep(1); } usleep(100); } if(ws!=NULL) delete ws; }
有細(xì)心的朋友發(fā)現(xiàn)在發(fā)送中文GBK 的時(shí)候與服務(wù)端會(huì)斷開
//GBK -> UTF-8 //遇到發(fā)送的字符串里有中文的話需要send 前進(jìn)行轉(zhuǎn)換一下, //這個(gè)是網(wǎng)友提供的在windows下的轉(zhuǎn)換函數(shù) std::string Server_Stream::GBKToUTF8(const std::string& strGBK) { std::string strOutUTF8 = ""; WCHAR * str1; int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0); str1 = new WCHAR[n]; MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n); n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL); char * str2 = new char[n]; WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL); strOutUTF8 = str2; delete[]str1; str1 = NULL; delete[]str2; str2 = NULL; return strOutUTF8; }
下面是C++實(shí)現(xiàn)的WebSocket客戶端,寫好后這里記一下,免得以后忘記。
本示例共有三個(gè)文件組成,依賴Websocket++第三方庫
其中main.cpp是使用示例
#include <iostream> #include <string> #include <sstream> #include "websocket_endpoint.h" int main(int argc, char **argv) { bool done = false; std::string input; kagula::websocket_endpoint endpoint; endpoint.connect("ws://localhost:9002"); while (!done) { std::cout << "Enter Command: "; std::getline(std::cin, input); if (input == "quit") { done = true; } else if (input.substr(0, 4) == "send") { std::stringstream ss(input); std::string cmd; std::string message; ss >> cmd; std::getline(ss, message); endpoint.send(message); } else if (input.substr(0, 4) == "show") { endpoint.show(); } else { std::cout << "> Unrecognized Command" << std::endl; } } endpoint.close(); return 0; }
其它兩個(gè)文件是封裝
websocket_endpoint.h文件清單
#ifndef _WEBSOCKET_ENDPOINT_ #define _WEBSOCKET_ENDPOINT_ #include <string> /* Title: Web Socket Client Author: kagula Date: 2016-11-21 Dependencies: Websocket++、Boost::ASIO Test Environment: VS2013 Update5, WebSocket++ 0.70, Boost 1.61 Description: [1]Support connect a web socket server. [2]If server is crash, client will not follow crash. */ namespace kagula { class websocket_endpoint { public: websocket_endpoint(); ~websocket_endpoint(); int connect(std::string const & uri); void close(); void send(std::string message); void show(); }; } #endif
websocket_endpoint.cpp文件清單
#include <websocketpp/config/asio_no_tls_client.hpp> #include <websocketpp/client.hpp> #include <websocketpp/common/thread.hpp> #include <websocketpp/common/memory.hpp> #include <cstdlib> #include <iostream> #include <map> #include <string> #include <sstream> #include "websocket_endpoint.h" typedef websocketpp::client<websocketpp::config::asio_client> ws_client; namespace kagula { class connection_metadata { public: typedef websocketpp::lib::shared_ptr<connection_metadata> ptr; connection_metadata(websocketpp::connection_hdl hdl, std::string uri) : m_hdl(hdl) , m_status("Connecting") , m_uri(uri) , m_server("N/A") {} void on_open(ws_client *client, websocketpp::connection_hdl hdl) { m_status = "Open"; ws_client::connection_ptr con = client->get_con_from_hdl(hdl); m_server = con->get_response_header("Server"); } // if connection failed, the function will be invoke. void on_fail(ws_client *client, websocketpp::connection_hdl hdl) { m_status = "Failed"; ws_client::connection_ptr con = client->get_con_from_hdl(hdl); m_server = con->get_response_header("Server"); m_error_reason = con->get_ec().message(); } void on_close(ws_client *client, websocketpp::connection_hdl hdl) { m_status = "Closed"; ws_client::connection_ptr con = client->get_con_from_hdl(hdl); std::stringstream s; s << "close code: " << con->get_remote_close_code() << " (" << websocketpp::close::status::get_string(con->get_remote_close_code()) << "), close reason: " << con->get_remote_close_reason(); m_error_reason = s.str(); } void on_message(websocketpp::connection_hdl, ws_client::message_ptr msg) { if (msg->get_opcode() == websocketpp::frame::opcode::text) { m_messages.push_back("<< " + msg->get_payload()); } else { m_messages.push_back("<< " + websocketpp::utility::to_hex(msg->get_payload())); } } websocketpp::connection_hdl get_hdl() const { return m_hdl; } std::string get_status() const { return m_status; } std::string get_uri() const { return m_uri; } void record_sent_message(std::string message) { m_messages.push_back(">> " + message); } friend std::ostream & operator<< (std::ostream & out, connection_metadata const & data); private: websocketpp::connection_hdl m_hdl; std::string m_status; std::string m_uri; std::string m_server; std::string m_error_reason; std::vector<std::string> m_messages; }; std::ostream & operator<< (std::ostream & out, connection_metadata const & data) { out << "> URI: " << data.m_uri << "\n" << "> Status: " << data.m_status << "\n" << "> Remote Server: " << (data.m_server.empty() ? "None Specified" : data.m_server) << "\n" << "> Error/close reason: " << (data.m_error_reason.empty() ? "N/A" : data.m_error_reason) << "\n"; out << "> Messages Processed: (" << data.m_messages.size() << ") \n"; std::vector<std::string>::const_iterator it; for (it = data.m_messages.begin(); it != data.m_messages.end(); ++it) { out << *it << "\n"; } return out; } ws_client g_wsEndPoint; connection_metadata::ptr g_wsClientConnection; websocketpp::lib::shared_ptr<websocketpp::lib::thread> g_threadWS; websocket_endpoint::websocket_endpoint(){ g_wsEndPoint.clear_access_channels(websocketpp::log::alevel::all); g_wsEndPoint.clear_error_channels(websocketpp::log::elevel::all); g_wsEndPoint.init_asio(); g_wsEndPoint.start_perpetual(); g_threadWS = websocketpp::lib::make_shared<websocketpp::lib::thread>(&ws_client::run, &g_wsEndPoint); } websocket_endpoint::~websocket_endpoint() { g_wsEndPoint.stop_perpetual(); if (g_wsClientConnection->get_status() == "Open") { // Only close open connections websocketpp::lib::error_code ec; g_wsEndPoint.close(g_wsClientConnection->get_hdl(), websocketpp::close::status::going_away, "", ec); if (ec) { std::cout << "> Error closing ws connection " << g_wsClientConnection->get_uri() << " :" << ec.message() << std::endl; } } g_threadWS->join(); } int websocket_endpoint::connect(std::string const & uri) { websocketpp::lib::error_code ec; ws_client::connection_ptr pConnection = g_wsEndPoint.get_connection(uri, ec); if (ec) { std::cout << "> Connect initialization error: " << ec.message() << std::endl; return -1; } g_wsClientConnection = websocketpp::lib::make_shared<connection_metadata>(pConnection->get_handle(), uri); pConnection->set_open_handler(websocketpp::lib::bind( &connection_metadata::on_open, g_wsClientConnection, &g_wsEndPoint, websocketpp::lib::placeholders::_1 )); pConnection->set_fail_handler(websocketpp::lib::bind( &connection_metadata::on_fail, g_wsClientConnection, &g_wsEndPoint, websocketpp::lib::placeholders::_1 )); pConnection->set_close_handler(websocketpp::lib::bind( &connection_metadata::on_close, g_wsClientConnection, &g_wsEndPoint, websocketpp::lib::placeholders::_1 )); pConnection->set_message_handler(websocketpp::lib::bind( &connection_metadata::on_message, g_wsClientConnection, websocketpp::lib::placeholders::_1, websocketpp::lib::placeholders::_2 )); g_wsEndPoint.connect(pConnection); return 0; } void close(websocketpp::close::status::value code, std::string reason) { websocketpp::lib::error_code ec; g_wsEndPoint.close(g_wsClientConnection->get_hdl(), code, reason, ec); if (ec) { std::cout << "> Error initiating close: " << ec.message() << std::endl; } } void websocket_endpoint::close() { if (g_wsClientConnection->get_status()=="Open") { int close_code = websocketpp::close::status::normal; kagula::close(close_code, ""); } } void websocket_endpoint::send(std::string message) { websocketpp::lib::error_code ec; g_wsEndPoint.send(g_wsClientConnection->get_hdl(), message, websocketpp::frame::opcode::text, ec); if (ec) { std::cout << "> Error sending message: " << ec.message() << std::endl; return; } g_wsClientConnection->record_sent_message(message); } void websocket_endpoint::show() { std::cout << * g_wsClientConnection << std::endl; } }
到此這篇關(guān)于C++編寫的WebSocket客戶端實(shí)現(xiàn)示例代碼的文章就介紹到這了,更多相關(guān)C++ WebSocket客戶端內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)歌手比賽評(píng)分系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)歌手比賽評(píng)分系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C++ 實(shí)現(xiàn)PE文件特征碼識(shí)別的步驟
PE文件就是我們常說的EXE可執(zhí)行文件,針對文件特征的識(shí)別可以清晰的知道該程序是使用何種編程語言實(shí)現(xiàn)的,前提是要有特征庫,PE特征識(shí)別有多種形式,第一種是靜態(tài)識(shí)別,第二種則是動(dòng)態(tài)識(shí)別,我們經(jīng)常使用的PEID查殼工具是基于靜態(tài)檢測的方法。2021-06-06c語言實(shí)現(xiàn)冒泡排序、希爾排序等多種算法示例
c語言實(shí)現(xiàn)插入排序、冒泡排序、選擇排序、快速排序、堆排序、歸并排序、希爾排序示例,需要的朋友可以參考下2014-04-04探究C++中指針與數(shù)組運(yùn)算符優(yōu)先級(jí)
C++中與指針和數(shù)組相關(guān)的運(yùn)算符優(yōu)先級(jí),通過實(shí)際代碼示例解釋了運(yùn)算符的左結(jié)合與右結(jié)合方式,以及如何使用圓括號(hào)()來改變默認(rèn)的結(jié)合順序,文章還提供了一個(gè)優(yōu)先級(jí)表,列出了運(yùn)算符的優(yōu)先級(jí)和結(jié)合性,幫助讀者更好地理解復(fù)雜表達(dá)式中運(yùn)算符的調(diào)用順序2024-10-10C++編程異常處理中try和throw以及catch語句的用法
這篇文章主要介紹了C++編程異常處理中try和throw以及catch語句的用法,包括對Catch塊的計(jì)算方式的介紹,需要的朋友可以參考下2016-01-01