C++下轻量化websocket客户端库——easywsclient的使用

1、背景介绍

1.1 WebSocket介绍

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在这里插入图片描述

在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

1.2 WebSocket 属性

连接状态属性

以下是 WebSocket 对象的属性:
0 - 表示连接尚未建立。
1 - 表示连接已建立,可以进行通信。
2 - 表示连接正在进行关闭。
3 - 表示连接已经关闭或者连接不能打开。

Socket.bufferedAmount
只读属性 bufferedAmount 为True表示信息已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

WebSocket 事件

以下是 WebSocket 对象的相关事件:
事件 事件处理程序 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发

WebSocket 方法

以下是 WebSocket 对象的相关方法,用于信息发生与连接

方法 描述
Socket.send() //使用连接发送数据
Socket.close() //关闭连接

1.3 easywsclient介绍

websocket并不局限于在网页端(JS客户端使用),其还支持在各个后端中使用,如C++、Java等
easywsclient是一个基于C++11的轻量化标注websocket客户端库(跨平台,支持各种系统),支持RFC 6455版本13 WebSocket,兼容现行所有的WebSocket服务器(如c++ crow库的WebSocket服务端)。对于socketio的服务器兼容存在问题,应使用socketio的客户端。
项目地址: https://github.com/dhbaird/easywsclient

2、easywsclient使用

2.1 代码介绍

easywsclient项目核心代码为"easywsclient.hpp"和"easywsclient.cpp",仅需将这两个文件拷贝到自己项目下即可使用WebSocket客户端通信了。
其关键接口函数有以下4个,send函数用于发送文本信息,sendBinary函数用于发送二进制信息,dispatch用于设置信息接收处理的函数

        ws->poll();
        ws->send("hello");
        //ws->sendBinary(vp);
        ws->dispatch(handle_message);

2.2 基本使用

使用easywsclient主要是要指定dispatch函数,可以在dispatch函数中对服务器返回的信息进行处理,也可以在此处断开WebSocket连接

#include "easywsclient.hpp"
//#include "easywsclient.cpp" // <-- include only if you don't want compile separately
using easywsclient::WebSocket;
WebSocket::pointer ws;
void handle_message_close(const std::string& message)
{
    ws->close();
}
int
main()
{
#ifdef _WIN32
    INT rc;
    WSADATA wsaData;

    rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (rc) {
        printf("WSAStartup Failed.\n");
        return 1;
    }
#endif
    ws = WebSocket::from_url("ws://localhost:8126/foo");
    assert(ws);
    while (websocketclient->getReadyState() != WebSocket::CLOSED) {
        ws->poll();
        ws->send("hello");
        ws->dispatch(handle_message_close);
    }
    ...
    delete ws; // alternatively, use unique_ptr<> if you have C++11

#ifdef _WIN32
    WSACleanup();
#endif
    return 0;
}

2.3 发送二进制数据

需要调用sendBinary函数,其入参为std::vector<uint8_t>类型。其支持将多种数据类型进行拼接,允许一次性传入多个数据(使用memcpy将数据复制到对应内存位置即可)。

        long dsize =  sizeof(int) +sizeof(char) * txt_data.size() ;
        uint8_t* buffer; 
        buffer = (uint8_t*)malloc(sizeof(uint8_t) * dsize);
        memcpy(buffer, 123456, sizeof(int));
        memcpy(buffer+sizeof(int), txt_data.data(), sizeof(char)*txt_data.size());
        std::vector<uint8_t> vp(buffer, buffer + dsize);

        ws->poll();
        ws->sendBinary(vp);

        //可以将二进制数据保存下来,与服务器端进行验证
        ofstream fout("send.dat", ios::binary);
        fout.write(reinterpret_cast<const char*>(buffer), sizeof(uint8_t) * dsize);
        fout.close();

3、websocket服务器

在c++下搭建websocket服务器需要依赖其他的第三方库,这里初略介绍一下2个可以实现websocket服务器的c++库

3.1 使用websocketpp库

websocketpp库下载地址为:https://github.com/zaphoyd/websocketpp/,其依赖Boost库。故此,在导入websocketpp库前,需要先导入Boost库。websocketpp库也支持websocket客户端,但考虑到依赖的库更多了,还是推荐使用easywsclient库

#include <websocketpp/config/asio_no_tls.hpp>
 
#include <websocketpp/server.hpp>
 
#include <iostream>
 
typedef websocketpp::server<websocketpp::config::asio> server;
 
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
 
// pull out the type of messages sent by our config
typedef server::message_ptr message_ptr;
 
// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
    std::string cmd = msg->get_payload();
    std::string res = "fu wu qi de xin xi! \" ";
 
    std::cout << "on_message called with hdl: " << hdl.lock().get()
              << " and message: " << msg->get_payload()
              << std::endl;
 
    // check for a special command to instruct the server to stop listening so
    // it can be cleanly exited.
    if (msg->get_payload() == "stop-listening") {
        s->stop_listening();
        return;
    }
 
    try {
        s->send(hdl, res, msg->get_opcode());
    } catch (websocketpp::exception const & e) {
        std::cout << "Echo failed because: "
                  << "(" << e.what() << ")" << std::endl;
    }
}
 
int main() {
    // Create a server endpoint
    server echo_server;
 
    try {
        // Set logging settings
        echo_server.set_access_channels(websocketpp::log::alevel::all);
        echo_server.clear_access_channels(websocketpp::log::alevel::frame_payload);
 
        // Initialize Asio
        echo_server.init_asio();
 
        // Register our message handler
        echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));
 
        // Listen on port 9002
        echo_server.listen(9002);
 
        // Start the server accept loop
        echo_server.start_accept();
 
        // Start the ASIO io_service run loop
        echo_server.run();
    } catch (websocketpp::exception const & e) {
        std::cout << e.what() << std::endl;
    } catch (...) {
        std::cout << "other exception" << std::endl;
    }
}

详情可以参考:https://hpg123.blog.csdn.net/article/details/124888325

3.2 使用crow库

corw是一个开源、轻量化的c++web库,在使用上与python的flask是类似的,其支持路由绑定、返回数据(json、文本、response对象(静态资源、模板文件)、接口请求处理(REST请求,url参数绑定、json请求、GET参数和POST
参数)和各种高级操作(Cookie操作、Session操作、文件上传操作、文件下载操作、websocket
操作、自定义loghandler)。此外,还对各类参数请求、结果返回过程中对中文的支持(如get
参数、post参数、url参数、json结果中中文参数的正确解读)。其使用文档的下载地址为:https://download.csdn.net/download/a486259/87471152

#include "crow.h"
#include <unordered_set>
#include <mutex>
int main()
{
	crow::SimpleApp app;
	std::mutex mtx;
	std::unordered_set<crow::websocket::connection*> users;
	CROW_WEBSOCKET_ROUTE(app, "/ws")
		.onopen([&](crow::websocket::connection& conn) {
			CROW_LOG_INFO << "new websocket connection from " << conn.get_remote_ip();
			std::lock_guard<std::mutex> _(mtx);
			users.insert(&conn);
		})
		.onclose([&](crow::websocket::connection& conn, const std::string& reason) {
			CROW_LOG_INFO << "websocket connection closed: " << reason;
			std::lock_guard<std::mutex> _(mtx);
			users.erase(&conn);
		})
		.onmessage([&](crow::websocket::connection& /*conn*/, const std::string& data, bool is_binary){
			std::lock_guard<std::mutex> _(mtx);
			//给当前用户发信息
			conn.send_text(data);
			//给所有用户发信息
			for (auto u : users){
			if (is_binary){
			u->send_binary(data);
			}else{
			u->send_text(data);
	});
	CROW_ROUTE(app, "/")
	([] {
		char name[256];
		gethostname(name, 256);
		crow::mustache::context x;
		x["servername"] = name;
		auto page = crow::mustache::load("ws.html");
		return page.render(x);
	});
}
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万里鹏程转瞬至

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值