当前位置: 首页 > news >正文

嵌入式开发—C++使用websocketpp 创建WebSocket服务器,并向浏览器发送图片

文章目录

    • 前言
      • websocketpp 库的主要特点
      • 使用 websocketpp 创建 WebSocket 服务器
    • C++ 实现简单的WebSocket服务器
    • 发送图片数据到网页示例
      • Base64编码图片的具体应用场景
      • 服务端实现
      • 网页端实现
      • 测试效果

前言

websocketpp 是一个开源的 C++ 库,用于创建 WebSocket 服务器和客户端。它提供了简单易用的接口,并且支持 WebSocket 协议的完整实现,适合高性能应用。

websocketpp 库的主要特点

  • 跨平台:支持在多种平台上运行,包括 Windows、Linux 和 macOS。
  • 依赖少:只依赖于 Boost.Asio 或 standalone Asio。非常方便进行嵌入式平台进行移植
  • 高性能:设计用于处理高性能 WebSocket 应用。
  • 完全实现 WebSocket 协议:支持 WebSocket 协议的完整实现,包括握手、消息发送和接收、连接管理等。

使用 websocketpp 创建 WebSocket 服务器

步骤 1:安装依赖项

websocketpp 依赖于 Boost.Asio 或 standalone Asio

在ubuntu上安装Boost:

sudo apt-get update
sudo apt-get install libboost-all-dev

步骤 2:安装 websocketpp

从 GitHub 仓库下载并安装 websocketpp:

git clone https://github.com/zaphoyd/websocketpp.git
cd websocketpp
mkdir build
cmake ..
sudo make
sudo make install

执行完上述步骤,相关的头文件已经复制到ubuntu系统了,只需要在编写代码的时候调用相关头文件即可。

C++ 实现简单的WebSocket服务器

完整代码(可读取图片文件发送给浏览器)如下:

#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <websocketpp/base64/base64.hpp>#include <iostream>
#include <fstream>
#include <vector>
#include <set>
#include <memory>typedef websocketpp::server<websocketpp::config::asio> server;class websocket_server {
public:websocket_server() {// 初始化 asio 库m_server.init_asio();// 注册回调函数m_server.set_http_handler(bind(&websocket_server::on_http, this, std::placeholders::_1));m_server.set_open_handler(bind(&websocket_server::on_open, this, std::placeholders::_1));m_server.set_close_handler(bind(&websocket_server::on_close, this, std::placeholders::_1));m_server.set_message_handler(bind(&websocket_server::on_message, this, std::placeholders::_1, std::placeholders::_2));}void run(uint16_t port) {// 监听指定端口m_server.listen(port);// 开始接受连接m_server.start_accept();// 启动 asio io_service 运行循环try {m_server.run();} catch (const std::exception &e) {std::cerr << "Error: " << e.what() << std::endl;}}private:typedef std::set<websocketpp::connection_hdl, std::owner_less<websocketpp::connection_hdl>> con_list;server m_server;con_list m_connections;void on_http(websocketpp::connection_hdl hdl) {server::connection_ptr con = m_server.get_con_from_hdl(hdl);std::string response_body = "Hello, World!";con->set_body(response_body);con->set_status(websocketpp::http::status_code::ok);}void on_open(websocketpp::connection_hdl hdl) {m_connections.insert(hdl);std::cout << "Connection opened" << std::endl;}void on_close(websocketpp::connection_hdl hdl) {m_connections.erase(hdl);std::cout << "Connection closed" << std::endl;}void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg) {std::cout << "Received message: " << msg->get_payload() << std::endl;if (msg->get_payload() == "img") {std::cout << "send img" << std::endl;// Read the image file and encode to base64 each time a request is receivedstd::ifstream imageFile("test.jpg", std::ios::binary);if (imageFile.is_open()) {std::vector<unsigned char> imageData((std::istreambuf_iterator<char>(imageFile)),std::istreambuf_iterator<char>());std::string base64ImageData = websocketpp::base64_encode(imageData.data(), imageData.size());m_server.send(hdl, base64ImageData, websocketpp::frame::opcode::text);} else {std::cerr << "Failed to open image file" << std::endl;}} else {m_server.send(hdl, "Message received: " + msg->get_payload(), msg->get_opcode());}}
};int main() {websocket_server server_instance;server_instance.run(8080);return 0;
}

当服务器初始化的时候,主要是初始化asio库和注册 处理的回调函数

  // 初始化 asio 库m_server.init_asio();// 注册回调函数m_server.set_http_handler(bind(&websocket_server::on_http, this, std::placeholders::_1));m_server.set_open_handler(bind(&websocket_server::on_open, this, std::placeholders::_1));m_server.set_close_handler(bind(&websocket_server::on_close, this, std::placeholders::_1));m_server.set_message_handler(bind(&websocket_server::on_message, this, std::placeholders::_1, std::placeholders::_2));

下方这段代码,监听了8080端口。当访问浏览器的时候,会回应hello world 。

注意:访问的时候,不能是https 只能是http

void on_http(websocketpp::connection_hdl hdl) {server::connection_ptr con = m_server.get_con_from_hdl(hdl);std::string response_body = "Hello, World!";con->set_body(response_body);con->set_status(websocketpp::http::status_code::ok);}

效果如下:

在这里插入图片描述

 void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg) {std::cout << "Received message: " << msg->get_payload() << std::endl;if (msg->get_payload() == "img") {std::cout << "send img" << std::endl;// Read the image file and encode to base64 each time a request is receivedstd::ifstream imageFile("test.jpg", std::ios::binary);if (imageFile.is_open()) {std::vector<unsigned char> imageData((std::istreambuf_iterator<char>(imageFile)),std::istreambuf_iterator<char>());std::string base64ImageData = websocketpp::base64_encode(imageData.data(), imageData.size());m_server.send(hdl, base64ImageData, websocketpp::frame::opcode::text);} else {std::cerr << "Failed to open image file" << std::endl;}} else {m_server.send(hdl, "Message received: " + msg->get_payload(), msg->get_opcode());}}

接收消息的函数,接收js / WebSocket client的消息

发送图片数据到网页示例

websocketpp 支持发送文本,发送二进制码流,可以使用Base64将二进制的图片文件转为字符发送,而且js支持直接读取Base64编码显示图片,减少了网页端编码难度。

Base64编码图片的具体应用场景

  1. 嵌入HTML/CSS: 在HTML或CSS中,使用Base64编码可以将图片嵌入到文件中,这样在加载网页时不需要单独请求图片资源,减少HTTP请求次数,提升页面加载速度。

    <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." />
    
  2. 电子邮件附件: 在电子邮件中,附件通常以MIME格式发送。Base64编码用于将二进制附件转换为文本,使其可以嵌入到邮件正文中。

    Content-Type: image/jpeg
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment; filename="image.jpg"
    /9j/4AAQSkZJRgABAQEAAAAAAAD/2wBDA...
    
  3. Web API 传输: 某些API只支持文本数据(如JSON)。通过将图片Base64编码,可以在API请求和响应中传输图片数据。

    {"image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
    }
    
  4. 数据存储: 在某些数据库系统中,尤其是那些设计为以文本形式存储数据的系统,将图片Base64编码后存储,可以避免二进制数据存储时可能遇到的兼容性问题。

服务端实现

读取当前目录的图片文件,使用websocketpp::base64编码成Base64数据,通过Socket文本形式传输。

 std::ifstream imageFile("test.jpg", std::ios::binary);if (imageFile.is_open()) {std::vector<unsigned char> imageData((std::istreambuf_iterator<char>(imageFile)),std::istreambuf_iterator<char>());std::string base64ImageData = websocketpp::base64_encode(imageData.data(), imageData.size());m_server.send(hdl, base64ImageData, websocketpp::frame::opcode::text);} else {std::cerr << "Failed to open image file" << std::endl;}

网页端实现

完整代码如下

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket Image and Text Receiver</title>
</head><body><h1>WebSocket Image and Text Receiver</h1><div id="imageContainer"></div><div><input type="text" id="textInput" placeholder="Type your message here"><button onclick="sendMessage()">Send Message</button></div><script>const socket = new WebSocket('ws://192.168.1.11:8080');socket.binaryType = 'arraybuffer'; // Specify that binary data will be receivedsocket.onmessage = function (event) {// Received text datadisplayImage(event.data);};// Convert ArrayBuffer to base64 stringfunction arrayBufferToBase64(buffer) {const binary = [];const bytes = new Uint8Array(buffer);const len = bytes.byteLength;for (let i = 0; i < len; i++) {binary.push(String.fromCharCode(bytes[i]));}const base64String = window.btoa(binary.join(''));return base64String;}// Display image in the image containerfunction displayImage(base64Image) {const imageContainer = document.getElementById('imageContainer');const img = document.createElement('img');img.src = 'data:image/jpeg;base64,' + base64Image;console.log(img.src)imageContainer.appendChild(img);}// Display text messagefunction displayText(message) {const messageContainer = document.getElementById('imageContainer');const textNode = document.createTextNode(message);messageContainer.appendChild(textNode);messageContainer.appendChild(document.createElement('br')); // Add line break}// Send text message to serverfunction sendMessage() {const textInput = document.getElementById('textInput');const message = textInput.value;if (socket.readyState === WebSocket.OPEN) {socket.send(message);textInput.value = ''; // Clear the input field} else {console.log('WebSocket is not open');}}</script>
</body></html>

测试效果

首先在服务器端打开websocket_server 等待网页端链接

打开网页的时候触发连接的回调函数

在这里插入图片描述

输入img 指令 发送给服务器端, 服务器读取图片发送Base64编码,网页解析显示图片

在这里插入图片描述

相关文章:

  • springboot从2.7.2 升级到 3.3.0
  • Golang:使用embed引入静态文件
  • 【Uniapp微信小程序】自定义水印相机、微信小程序地点打卡相机
  • Vue CLI:Vue CLI是一个强大的工具,可以帮助开发者快速地创建和管理Vue项目。我们可以讨论它的一些核心特性,比如热重载、懒加载等
  • 【云原生】kubernetes中pod的生命周期、探测钩子的实战应用案例解析
  • C++入门5——C/C++动态内存管理(new与delete)
  • 使用 C++ 在当前进程中获取指定模块的基址
  • HackTheBox-Machines--Sense
  • 标题:Go语言中的YAML魔法:轻松配置你的环境
  • Python打印当前目录下,所有文件名的首字母
  • Centos7安装Docker和DockerCompose
  • DynamiCrafter ComfyUI 教程 | 对图片转视频的效果进行精细化控制
  • Spark_SparkOnHive_海豚调度跑任务写入Hive表失败解决
  • Mac/Linux getline 无法读取文件内容(读取内容无法显示)
  • 【数据库】MySQL表的操作
  • 「译」Node.js Streams 基础
  • CSS实用技巧
  • Java 最常见的 200+ 面试题:面试必备
  • java8 Stream Pipelines 浅析
  • JavaScript标准库系列——Math对象和Date对象(二)
  • leetcode讲解--894. All Possible Full Binary Trees
  • spring + angular 实现导出excel
  • SpringBoot几种定时任务的实现方式
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • vue--为什么data属性必须是一个函数
  • 第十八天-企业应用架构模式-基本模式
  • - 概述 - 《设计模式(极简c++版)》
  • 近期前端发展计划
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 实习面试笔记
  • 使用 Docker 部署 Spring Boot项目
  • 我这样减少了26.5M Java内存!
  • 写代码的正确姿势
  • 栈实现走出迷宫(C++)
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • ​queue --- 一个同步的队列类​
  • ​埃文科技受邀出席2024 “数据要素×”生态大会​
  • ​浅谈 Linux 中的 core dump 分析方法
  • # centos7下FFmpeg环境部署记录
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • # 数仓建模:如何构建主题宽表模型?
  • #Datawhale AI夏令营第4期#多模态大模型复盘
  • #单片机(TB6600驱动42步进电机)
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (一)appium-desktop定位元素原理
  • ***检测工具之RKHunter AIDE
  • 、写入Shellcode到注册表上线
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .bat批处理(一):@echo off
  • .mysql secret在哪_MYSQL基本操作(上)
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .net core 6 集成 elasticsearch 并 使用分词器