C++編寫的WebSocket服務端客戶端實現(xiàn)示例代碼
使用過標準的libwebsockets服務端庫測試過,主要是短小精悍,相對于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"); //如果你需要多線程,可以在一個thread 維護該ws的連接重連機制 while (ws->getReadyState() != WebSocket::CLOSED) //判斷ws是否正常連接 { ws->poll();//這個必須要調(diào)用,否則不能發(fā)送,發(fā)送跟接收都是異步的,都是在這個poll函數(shù)里監(jiān)測處理的 ws->dispatch(handle_message); } delete ws; return 0; }
//線程thread 維護重連連接 void run() { bool conn = FLASE; ws = WebSocket::from_url("ws://localhost:8126/foo"); //如果你需要多線程,可以在一個thread 維護該ws的連接重連機制 while (1) //判斷ws是否正常連接 { if(ws != NULL) { ws->poll(0);//這個必須要調(diào)用,否則不能發(fā)送,發(fā)送跟接收都是異步的,都是在這個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; }
有細心的朋友發(fā)現(xiàn)在發(fā)送中文GBK 的時候與服務端會斷開
//GBK -> UTF-8 //遇到發(fā)送的字符串里有中文的話需要send 前進行轉(zhuǎn)換一下, //這個是網(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++實現(xiàn)的WebSocket客戶端,寫好后這里記一下,免得以后忘記。
本示例共有三個文件組成,依賴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; }
其它兩個文件是封裝
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客戶端實現(xiàn)示例代碼的文章就介紹到這了,更多相關(guān)C++ WebSocket客戶端內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++編程異常處理中try和throw以及catch語句的用法
這篇文章主要介紹了C++編程異常處理中try和throw以及catch語句的用法,包括對Catch塊的計算方式的介紹,需要的朋友可以參考下2016-01-01