ToB企服应用市场:ToB评测及商务社交产业平台

标题: 学懂C++(四十一):网络编程——深入详解 C++ 网络编程之 WebSocket 应用 [打印本页]

作者: 一给    时间: 2024-8-24 04:14
标题: 学懂C++(四十一):网络编程——深入详解 C++ 网络编程之 WebSocket 应用
目次
一、引言
二、WebSocket 概念
1. WebSocket 概述
2. WebSocket 协议
WebSocket 握手哀求示例
三、WebSocket 工作原理
四、WebSocket 的实现方式
1. 预备工作
2. WebSocket 服务器实现
服务器代码
3. WebSocket 客户端实现
客户端代码
五、总结


一、引言

        在现代互联网应用中,即时通讯、及时数据传输和交互变得越来越重要。传统的 HTTP 协议由于其无状态和哀求/响应模子的限定,难以满意这类需求。WebSocket 协议应运而生,提供了持久的双向通讯通道。本文将深入解析 WebSocket 的概念、工作原理及其在 C++ 中的实现,并联合经典实例进行讲解。
二、WebSocket 概念

1. WebSocket 概述

        WebSocket 是一种全双工的通讯协议,设计用于在 Web 浏览器和服务器之间进行及时、低耽误的双向通讯。相较于传统的 HTTP 协议,WebSocket 协议具有以下几个显著特点:

2. WebSocket 协议

        WebSocket 协议通过 HTTP/1.1 协议进行初始握手,然后升级到 WebSocket 协议。握手乐成后,通讯双方可以通过 TCP 连接进行双向数据传输。
WebSocket 握手哀求示例

  1. GET /chat HTTP/1.1
  2. Host: server.example.com
  3. Upgrade: websocket
  4. Connection: Upgrade
  5. Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
  6. Sec-WebSocket-Version: 13
复制代码
WebSocket 握手响应示例
  1. HTTP/1.1 101 Switching Protocols
  2. Upgrade: websocket
  3. Connection: Upgrade
  4. Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
复制代码
三、WebSocket 工作原理

WebSocket 的工作流程重要包罗以下几个步骤:
四、WebSocket 的实现方式

        WebSocket 的实现方式可以分为客户端和服务器两部分。在 C++ 中,可以使用开源的 WebSocket 库(如 libwebsockets、Boost.Beast)进行实现。本文将使用 Boost.Asio 和 Boost.Beast 库来实现 WebSocket 客户端和服务器。
1. 预备工作

在开始编写代码之前,请确保已经安装了 Boost 库。可以从 Boost 官方网站下载并安装。
在 Linux 上

在基于 Debian 的体系(如 Ubuntu)上,可以使用以下下令安装 Boost 库:
  1. sudo apt-get update sudo apt-get install libboost-all-dev
复制代码
在 Windows 上

在 Windows 上,可以使用 vcpkg 或从 Boost 官网下载源码并手动编译安装。以下是使用 vcpkg 的示例:
  1. vcpkg install boost-asio boost-beast
复制代码
2. WebSocket 服务器实现

服务器代码

  1. #include <boost/beast/core.hpp>
  2. #include <boost/beast/websocket.hpp>
  3. #include <boost/asio/ip/tcp.hpp>
  4. #include <cstdlib>
  5. #include <iostream>
  6. #include <memory>
  7. #include <string>
  8. #include <thread>
  9. namespace beast = boost::beast;         // from <boost/beast.hpp>
  10. namespace http = beast::http;           // from <boost/beast/http.hpp>
  11. namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
  12. namespace net = boost::asio;            // from <boost/asio.hpp>
  13. using tcp = net::ip::tcp;               // from <boost/asio/ip/tcp.hpp>
  14. // 会话类
  15. class session : public std::enable_shared_from_this<session> {
  16.     websocket::stream<beast::tcp_stream> ws_;
  17.     beast::flat_buffer buffer_;
  18. public:
  19.     explicit session(tcp::socket socket)
  20.         : ws_(std::move(socket)) {}
  21.     // 启动异步操作
  22.     void run() {
  23.         // 执行 WebSocket 握手
  24.         ws_.async_accept(beast::bind_front_handler(&session::on_accept, shared_from_this()));
  25.     }
  26. private:
  27.     // WebSocket 握手的回调函数
  28.     void on_accept(beast::error_code ec) {
  29.         if (ec) {
  30.             std::cerr << "accept: " << ec.message() << std::endl;
  31.             return;
  32.         }
  33.         // 读取消息
  34.         do_read();
  35.     }
  36.     // 读取消息
  37.     void do_read() {
  38.         ws_.async_read(buffer_, beast::bind_front_handler(&session::on_read, shared_from_this()));
  39.     }
  40.     // 读取消息后的回调函数
  41.     void on_read(beast::error_code ec, std::size_t bytes_transferred) {
  42.         if (ec == websocket::error::closed) {
  43.             return;
  44.         }
  45.         if (ec) {
  46.             std::cerr << "read: " << ec.message() << std::endl;
  47.             return;
  48.         }
  49.         std::cout << "Received: " << beast::make_printable(buffer_.data()) << std::endl;
  50.         buffer_.consume(buffer_.size()); // 清空缓冲区
  51.         // 回应消息
  52.         ws_.text(ws_.got_text());
  53.         ws_.async_write(boost::asio::buffer("Echo: Hello from server"), beast::bind_front_handler(&session::on_write, shared_from_this()));
  54.     }
  55.     // 写消息后的回调函数
  56.     void on_write(beast::error_code ec, std::size_t bytes_transferred) {
  57.         if (ec) {
  58.             std::cerr << "write: " << ec.message() << std::endl;
  59.             return;
  60.         }
  61.         // 继续读取消息
  62.         do_read();
  63.     }
  64. };
  65. // 监听器类
  66. class listener : public std::enable_shared_from_this<listener> {
  67.     net::io_context& ioc_;
  68.     tcp::acceptor acceptor_;
  69. public:
  70.     listener(net::io_context& ioc, tcp::endpoint endpoint)
  71.         : ioc_(ioc), acceptor_(net::make_strand(ioc)) {
  72.         beast::error_code ec;
  73.         // 打开接收器
  74.         acceptor_.open(endpoint.protocol(), ec);
  75.         if (ec) {
  76.             std::cerr << "open: " << ec.message() << std::endl;
  77.             return;
  78.         }
  79.         // 绑定到端点
  80.         acceptor_.bind(endpoint, ec);
  81.         if (ec) {
  82.             std::cerr << "bind: " << ec.message() << std::endl;
  83.             return;
  84.         }
  85.         // 开始监听
  86.         acceptor_.listen(net::socket_base::max_listen_connections, ec);
  87.         if (ec) {
  88.             std::cerr << "listen: " << ec.message() << std::endl;
  89.             return;
  90.         }
  91.     }
  92.     // 启动异步接受操作
  93.     void run() {
  94.         do_accept();
  95.     }
  96. private:
  97.     // 异步接受操作
  98.     void do_accept() {
  99.         acceptor_.async_accept(net::make_strand(ioc_), beast::bind_front_handler(&listener::on_accept, shared_from_this()));
  100.     }
  101.     // 接受连接后的回调函数
  102.     void on_accept(beast::error_code ec, tcp::socket socket) {
  103.         if (ec) {
  104.             std::cerr << "accept: " << ec.message() << std::endl;
  105.         } else {
  106.             // 创建 WebSocket 会话
  107.             std::make_shared<session>(std::move(socket))->run();
  108.         }
  109.         // 继续接受连接
  110.         do_accept();
  111.     }
  112. };
  113. int main(int argc, char* argv[]) {
  114.     try {
  115.         if (argc != 2) {
  116.             std::cerr << "Usage: websocket-server <port>\n";
  117.             return EXIT_FAILURE;
  118.         }
  119.         // 解析命令行参数
  120.         auto const port = static_cast<unsigned short>(std::atoi(argv[1]));
  121.         // 创建 io_context
  122.         net::io_context ioc{1};
  123.         // 创建并启动监听器
  124.         std::make_shared<listener>(ioc, tcp::endpoint{tcp::v4(), port})->run();
  125.         // 运行 io_context
  126.         ioc.run();
  127.     } catch (const std::exception& e) {
  128.         std::cerr << "Error: " << e.what() << std::endl;
  129.         return EXIT_FAILURE;
  130.     }
  131.     return EXIT_SUCCESS;
  132. }
复制代码
解析
运行方式: 编译并运行服务器步伐,例如:
在 Linux 上

假设将服务器代码生存为 websocket_server.cpp,使用以下下令进行编译和运行:
  1. # 编译服务器代码
  2. g++ -o websocket-server websocket_server.cpp -lboost_system -lboost_thread -lssl -lcrypto -lboost_beast
  3. # 运行服务器
  4. ./websocket-server 8080
复制代码
在 Windows 上

假设将服务器代码生存为 websocket_server.cpp,使用以下下令进行编译和运行(需要安装 MinGW):
  1. # 编译服务器代码
  2. g++ -o websocket-server websocket_server.cpp -lboost_system -lws2_32 -lssl -lcrypto
  3. # 运行服务器
  4. ./websocket-server 8080
复制代码
 
3. WebSocket 客户端实现

客户端代码

  1. #include <boost/beast/core.hpp>
  2. #include <boost/beast/websocket.hpp>
  3. #include <boost/asio/ip/tcp.hpp>
  4. #include <cstdlib>
  5. #include <iostream>
  6. #include <string>
  7. namespace beast = boost::beast;         // from <boost/beast.hpp>
  8. namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
  9. namespace net = boost::asio;            // from <boost/asio.hpp>
  10. using tcp = net::ip::tcp;               // from <boost/asio/ip/tcp.hpp>
  11. int main(int argc, char* argv[]) {
  12.     try {
  13.         if (argc != 3) {
  14.             std::cerr << "Usage: websocket-client <host> <port>\n";
  15.             return EXIT_FAILURE;
  16.         }
  17.         auto const host = argv[1];
  18.         auto const port = argv[2];
  19.         // 创建 io_context
  20.         net::io_context ioc;
  21.         // 解析地址
  22.         tcp::resolver resolver(ioc);
  23.         auto const results = resolver.resolve(host, port);
  24.         // 创建 WebSocket 流
  25.         websocket::stream<tcp::socket> ws{ioc};
  26.         // 连接到服务器
  27.         net::connect(ws.next_layer(), results.begin(), results.end());
  28.         // 执行 WebSocket 握手
  29.         ws.handshake(host, "/");
  30.         // 发送消息
  31.         ws.write(net::buffer(std::string("Hello from client")));
  32.         // 读取响应
  33.         beast::flat_buffer buffer;
  34.         ws.read(buffer);
  35.         std::cout << "Received: " << beast::make_printable(buffer.data()) << std::endl;
  36.         // 关闭 WebSocket 连接
  37.         ws.close(websocket::close_code::normal);
  38.     } catch (const std::exception& e) {
  39.         std::cerr << "Error: " << e.what() << std::endl;
  40.         return EXIT_FAILURE;
  41.     }
  42.     return EXIT_SUCCESS;
  43. }
复制代码
解析
运行方式: 编译并运行客户端步伐,例如:
在 Linux 上

假设将客户端代码生存为 websocket_client.cpp,使用以下下令进行编译和运行:
  1. # 编译客户端代码
  2. g++ -o websocket-client websocket_client.cpp -lboost_system -lboost_thread -lssl -lcrypto -lboost_beast
  3. # 运行客户端
  4. ./websocket-client localhost 8080
复制代码
在 Windows 上

假设将客户端代码生存为 websocket_client.cpp,使用以下下令进行编译和运行(需要安装 MinGW):
  1. # 编译客户端代码
  2. g++ -o websocket-client websocket_client.cpp -lboost_system -lws2_32 -lssl -lcrypto
  3. # 运行客户端
  4. ./websocket-client localhost 8080
复制代码
 
运行结果
  1. Received: Echo: Hello from server
复制代码
五、总结

        本文深入解析了 WebSocket 的基础概念、工作原理及其在 C++ 中的实现,并联合 Boost.Asio 和 Boost.Beast 库实现了 WebSocket 服务器和客户端。通过详细的示例代码息争析,展示了如何在 C++ 中构建高效、及时的双向通讯应用。希望本文能帮助读者更好地明白和把握 WebSocket 技术及其在 C++ 中的应用,进步网络编程技能。
        本文提供的示例代码可以在 Linux 和 Windows 上运行,重要依赖于跨平台的 Boost.Asio 和 Boost.Beast 库。无论您使用哪种操作体系,都需要确保体系上安装了相应的编译器和 Boost 库。通过本文的详细表明和示例,您应该能够在 C++ 环境中实现高效的 WebSocket 客户端和服务器。

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




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4