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

鼠扑  金牌会员 | 2024-6-22 12:49:46 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 698|帖子 698|积分 2094

前言

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:
  1. sudo apt-get update
  2. sudo apt-get install libboost-all-dev
复制代码
步骤 2:安装 websocketpp
从 GitHub 仓库下载并安装 websocketpp:
  1. git clone https://github.com/zaphoyd/websocketpp.git
  2. cd websocketpp
  3. mkdir build
  4. cmake ..
  5. sudo make
  6. sudo make install
复制代码
执行完上述步骤,相干的头文件已经复制到ubuntu系统了,只需要在编写代码的时候调用相干头文件即可。
C++ 实现简朴的WebSocket服务器

完整代码(可读取图片文件发送给浏览器)如下:
  1. #include <websocketpp/config/asio_no_tls.hpp>
  2. #include <websocketpp/server.hpp>
  3. #include <websocketpp/base64/base64.hpp>
  4. #include <iostream>
  5. #include <fstream>
  6. #include <vector>
  7. #include <set>
  8. #include <memory>
  9. typedef websocketpp::server<websocketpp::config::asio> server;
  10. class websocket_server {
  11. public:
  12.     websocket_server() {
  13.         // 初始化 asio 库
  14.         m_server.init_asio();
  15.         // 注册回调函数
  16.         m_server.set_http_handler(bind(&websocket_server::on_http, this, std::placeholders::_1));
  17.         m_server.set_open_handler(bind(&websocket_server::on_open, this, std::placeholders::_1));
  18.         m_server.set_close_handler(bind(&websocket_server::on_close, this, std::placeholders::_1));
  19.         m_server.set_message_handler(bind(&websocket_server::on_message, this, std::placeholders::_1, std::placeholders::_2));
  20.     }
  21.     void run(uint16_t port) {
  22.         // 监听指定端口
  23.         m_server.listen(port);
  24.         // 开始接受连接
  25.         m_server.start_accept();
  26.         // 启动 asio io_service 运行循环
  27.         try {
  28.             m_server.run();
  29.         } catch (const std::exception &e) {
  30.             std::cerr << "Error: " << e.what() << std::endl;
  31.         }
  32.     }
  33. private:
  34.     typedef std::set<websocketpp::connection_hdl, std::owner_less<websocketpp::connection_hdl>> con_list;
  35.     server m_server;
  36.     con_list m_connections;
  37.     void on_http(websocketpp::connection_hdl hdl) {
  38.         server::connection_ptr con = m_server.get_con_from_hdl(hdl);
  39.         std::string response_body = "Hello, World!";
  40.         con->set_body(response_body);
  41.         con->set_status(websocketpp::http::status_code::ok);
  42.     }
  43.     void on_open(websocketpp::connection_hdl hdl) {
  44.         m_connections.insert(hdl);
  45.         std::cout << "Connection opened" << std::endl;
  46.     }
  47.     void on_close(websocketpp::connection_hdl hdl) {
  48.         m_connections.erase(hdl);
  49.         std::cout << "Connection closed" << std::endl;
  50.     }
  51.     void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg) {
  52.         std::cout << "Received message: " << msg->get_payload() << std::endl;
  53.         if (msg->get_payload() == "img") {
  54.             std::cout << "send img" << std::endl;
  55.             // Read the image file and encode to base64 each time a request is received
  56.             std::ifstream imageFile("test.jpg", std::ios::binary);
  57.             if (imageFile.is_open()) {
  58.                 std::vector<unsigned char> imageData((std::istreambuf_iterator<char>(imageFile)),
  59.                                                      std::istreambuf_iterator<char>());
  60.                 std::string base64ImageData = websocketpp::base64_encode(imageData.data(), imageData.size());
  61.                 m_server.send(hdl, base64ImageData, websocketpp::frame::opcode::text);
  62.             } else {
  63.                 std::cerr << "Failed to open image file" << std::endl;
  64.             }
  65.         } else {
  66.             m_server.send(hdl, "Message received: " + msg->get_payload(), msg->get_opcode());
  67.         }
  68.     }
  69. };
  70. int main() {
  71.     websocket_server server_instance;
  72.     server_instance.run(8080);
  73.     return 0;
  74. }
复制代码
当服务器初始化的时候,主要是初始化asio库和注册 处理的回调函数
  1.   // 初始化 asio 库
  2.         m_server.init_asio();
  3.         // 注册回调函数
  4.         m_server.set_http_handler(bind(&websocket_server::on_http, this, std::placeholders::_1));
  5.         m_server.set_open_handler(bind(&websocket_server::on_open, this, std::placeholders::_1));
  6.         m_server.set_close_handler(bind(&websocket_server::on_close, this, std::placeholders::_1));
  7.         m_server.set_message_handler(bind(&websocket_server::on_message, this, std::placeholders::_1, std::placeholders::_2));
复制代码
下方这段代码,监听了8080端口。当访问浏览器的时候,会回应hello world 。
留意:访问的时候,不能是https 只能是http
  1. void on_http(websocketpp::connection_hdl hdl) {
  2.         server::connection_ptr con = m_server.get_con_from_hdl(hdl);
  3.         std::string response_body = "Hello, World!";
  4.         con->set_body(response_body);
  5.         con->set_status(websocketpp::http::status_code::ok);
  6.     }
复制代码
效果如下:

  1. void on_message(websocketpp::connection_hdl hdl, server::message_ptr msg) {
  2.         std::cout << "Received message: " << msg->get_payload() << std::endl;
  3.         if (msg->get_payload() == "img") {
  4.             std::cout << "send img" << std::endl;
  5.             // Read the image file and encode to base64 each time a request is received
  6.             std::ifstream imageFile("test.jpg", std::ios::binary);
  7.             if (imageFile.is_open()) {
  8.                 std::vector<unsigned char> imageData((std::istreambuf_iterator<char>(imageFile)),
  9.                                                      std::istreambuf_iterator<char>());
  10.                 std::string base64ImageData = websocketpp::base64_encode(imageData.data(), imageData.size());
  11.                 m_server.send(hdl, base64ImageData, websocketpp::frame::opcode::text);
  12.             } else {
  13.                 std::cerr << "Failed to open image file" << std::endl;
  14.             }
  15.         } else {
  16.             m_server.send(hdl, "Message received: " + msg->get_payload(), msg->get_opcode());
  17.         }
  18.     }
复制代码
接收消息的函数,接收js / WebSocket client的消息
发送图片数据到网页示例

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


  • 嵌入HTML/CSS: 在HTML或CSS中,使用Base64编码可以将图片嵌入到文件中,如许在加载网页时不需要单独请求图片资源,减少HTTP请求次数,提拔页面加载速度。
    1. <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." />
    复制代码
  • 电子邮件附件: 在电子邮件中,附件通常以MIME格式发送。Base64编码用于将二进制附件转换为文本,使其可以嵌入到邮件正文中。
    1. Content-Type: image/jpeg
    2. Content-Transfer-Encoding: base64
    3. Content-Disposition: attachment; filename="image.jpg"
    4. /9j/4AAQSkZJRgABAQEAAAAAAAD/2wBDA...
    复制代码
  • Web API 传输: 某些API只支持文本数据(如JSON)。通过将图片Base64编码,可以在API请求和相应中传输图片数据。
    1. {
    2.   "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
    3. }
    复制代码
  • 数据存储: 在某些数据库系统中,尤其是那些设计为以文本情势存储数据的系统,将图片Base64编码后存储,可以避免二进制数据存储时可能碰到的兼容性题目。
服务端实现

读取当前目录的图片文件,使用websocketpp::base64编码成Base64数据,通过Socket文本情势传输。
  1. std::ifstream imageFile("test.jpg", std::ios::binary);
  2.             if (imageFile.is_open()) {
  3.                 std::vector<unsigned char> imageData((std::istreambuf_iterator<char>(imageFile)),
  4.                                                      std::istreambuf_iterator<char>());
  5.                 std::string base64ImageData = websocketpp::base64_encode(imageData.data(), imageData.size());
  6.                 m_server.send(hdl, base64ImageData, websocketpp::frame::opcode::text);
  7.             } else {
  8.                 std::cerr << "Failed to open image file" << std::endl;
  9.             }
复制代码
网页端实现

完整代码如下
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>WebSocket Image and Text Receiver</title>
  7. </head>
  8. <body>
  9.     <h1>WebSocket Image and Text Receiver</h1>
  10.     <div id="imageContainer"></div>
  11.     <div>
  12.         <input type="text" id="textInput" placeholder="Type your message here">
  13.         <button onclick="sendMessage()">Send Message</button>
  14.     </div>
  15.     <script>
  16.         const socket = new WebSocket('ws://192.168.1.11:8080');
  17.         socket.binaryType = 'arraybuffer'; // Specify that binary data will be received
  18.         socket.onmessage = function (event) {
  19.             
  20.                 // Received text data
  21.                 displayImage(event.data);
  22.             
  23.         };
  24.         // Convert ArrayBuffer to base64 string
  25.         function arrayBufferToBase64(buffer) {
  26.             const binary = [];
  27.             const bytes = new Uint8Array(buffer);
  28.             const len = bytes.byteLength;
  29.             for (let i = 0; i < len; i++) {
  30.                 binary.push(String.fromCharCode(bytes[i]));
  31.             }
  32.             const base64String = window.btoa(binary.join(''));
  33.             return base64String;
  34.         }
  35.         // Display image in the image container
  36.         function displayImage(base64Image) {
  37.             const imageContainer = document.getElementById('imageContainer');
  38.             const img = document.createElement('img');
  39.             img.src = 'data:image/jpeg;base64,' + base64Image;
  40.             console.log(img.src)
  41.             imageContainer.appendChild(img);
  42.         }
  43.         // Display text message
  44.         function displayText(message) {
  45.             const messageContainer = document.getElementById('imageContainer');
  46.             const textNode = document.createTextNode(message);
  47.             messageContainer.appendChild(textNode);
  48.             messageContainer.appendChild(document.createElement('br')); // Add line break
  49.         }
  50.         // Send text message to server
  51.         function sendMessage() {
  52.             const textInput = document.getElementById('textInput');
  53.             const message = textInput.value;
  54.             if (socket.readyState === WebSocket.OPEN) {
  55.                 socket.send(message);
  56.                 textInput.value = ''; // Clear the input field
  57.             } else {
  58.                 console.log('WebSocket is not open');
  59.             }
  60.         }
  61.     </script>
  62. </body>
  63. </html>
复制代码
测试效果

起首在服务器端打开websocket_server 等候网页端链接
打开网页的时候触发连接的回调函数

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


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

鼠扑

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表