C++編寫的WebSocket服務(wù)端客戶端實(shí)現(xiàn)示例代碼
使用過標(biāo)準(zhǔn)的libwebsockets服務(wù)端庫(kù)測(cè)試過,主要是短小精悍,相對(duì)于libwebsockets不需要依賴zlib和openssl 以及其他庫(kù),直接make就可以使用了,linux跟windows都可以使用。
測(cè)試用例:
#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對(duì)象是否為空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)測(cè)處理的
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)測(cè)處 理的
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++第三方庫(kù)
其中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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)單鏈表的快速排序算法
大家好,本篇文章主要講的是C語(yǔ)言實(shí)現(xiàn)單鏈表的快速排序算法,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下2022-01-01
淺談帶緩沖I/O 和不帶緩沖I/O的區(qū)別與聯(lián)系
下面小編就為大家?guī)硪黄獪\談帶緩沖I/O 和不帶緩沖I/O的區(qū)別與聯(lián)系。小編覺得挺不錯(cuò)的現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01
C++實(shí)現(xiàn)LeetCode(78.子集合)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(78.子集合),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C語(yǔ)言實(shí)現(xiàn)快速排序改進(jìn)版
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)快速排序的改進(jìn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
C語(yǔ)言中的fscanf()函數(shù)與vfscanf()函數(shù)使用
這篇文章主要介紹了C語(yǔ)言中的fscanf()函數(shù)與vfscanf()函數(shù)使用,是C語(yǔ)言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-08-08
關(guān)于C++的強(qiáng)制類型轉(zhuǎn)換淺析
C++的強(qiáng)制類型轉(zhuǎn)換是我們?cè)谌粘i_發(fā)中經(jīng)常會(huì)遇到的,下面這篇文章主要給大家介紹了關(guān)于C++強(qiáng)制類型轉(zhuǎn)換的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09

