学懂C++(四十一):网络编程——深入详解 C++ 网络编程之 WebSocket 应用 ...

一给  金牌会员 | 2024-8-24 04:14:27 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 994|帖子 994|积分 2982

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

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

x
目次
一、引言
二、WebSocket 概念
1. WebSocket 概述
2. WebSocket 协议
WebSocket 握手哀求示例
三、WebSocket 工作原理
四、WebSocket 的实现方式
1. 预备工作
2. WebSocket 服务器实现
服务器代码
3. WebSocket 客户端实现
客户端代码
五、总结


一、引言

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

1. WebSocket 概述

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


  • 持久连接:一旦连接建立,客户端和服务器之间可以连续通讯,避免了频仍的连接建立和关闭过程。
  • 低开销:淘汰了 HTTP 哀求/响应头部的开销,得当高频率数据交换。
  • 双向通讯:答应客户端和服务器随时发送数据,支持及时应用场景。
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 的工作流程重要包罗以下几个步骤:

  • 建立连接:客户端发起 HTTP 哀求,包含特定的头部字段,用于哀求将连接升级为 WebSocket 协议。
  • 协议升级:服务器接收到哀求后,返回相应的头部字段,确认升级为 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 的示例:

  • 下载并安装 vcpkg。
  • 使用 vcpkg 安装 Boost 库:
  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. }
复制代码
解析

  • session 类:处理惩罚 WebSocket 会话,包罗握手、读写消息等。
  • listener 类:负责监听传入的 TCP 连接,并创建新的 WebSocket 会话。
  • main 函数:解析下令行参数,创建 io_context,启动监听器并运行。
运行方式: 编译并运行服务器步伐,例如:
在 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. }
复制代码
解析

  • 解析下令行参数:host 和 port。
  • 创建 io_context:管理 I/O 操作。
  • 解析服务器地址:通过 tcp::resolver。
  • 创建 WebSocket 流:通过 websocket::stream<tcp::socket>。
  • 连接到服务器:通过 net::connect。
  • 执行 WebSocket 握手:通过 ws.handshake。
  • 发送消息:通过 ws.write。
  • 读取响应:通过 ws.read。
  • 关闭 WebSocket 连接:通过 ws.close。
运行方式: 编译并运行客户端步伐,例如:
在 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企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

一给

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表