[C++][第三方库][Websocket]详细讲解

news2024/10/11 14:17:15

目录

  • 1.Websocket 协议
    • 1.介绍
    • 2.原理简介
  • 2.Websocketpp
    • 1.介绍
    • 2.安装
  • 3.常用接口
  • 4.使用


1.Websocket 协议

1.介绍

  • WebSocket是从HTML5开始支持的一种网页端和服务端保持长连接的消息推送机制
  • 产生原因
    • 传统的web程序都是属于"一问一答"的形式
      • 即客户端给服务器发送了一个HTTP请求,服务器给客户端返回一个HTTP响应
      • 这种情况下服务器是属于被动的一方,如果客户端不主动发起请求服务器就无法主动给客户端响应
    • 类似网页即时聊天这样的程序都是非常依赖"消息推送"的
      • 即需要服务器主动推动消息到客户端
      • 如果只是使用原生的HTTP协议,要想实现消息推送一般需要通过"轮询"的方式实现, 而轮询的成本比较高并且也不能及时的获取到消息的响应
    • 基于上述两个问题, 就产生了WebSocket协议,WebSocket更接近于TCP这种级别的通信方式,一旦连接建立完成客户端或者服务器都可以主动的向对方发送数据
  • 本质:一个应用层的TCP长连接协议
    • 搭建一个Websocket服务器其实就是搭建了一个TCP服务器,只不过应用层使用Websocket协议格式进行处理

2.原理简介

  • HTTP通信支持Websocket协议的切换
    • 客户端浏览器首先要向服务器发起一个HTTP请求

    • 这个请求和通常的HTTP请求不同,包含了一些附加头信息

    • 通过这个附加头信息完成握手过程并升级协议的过程
      请添加图片描述

      请添加图片描述


2.Websocketpp

1.介绍

  • WebSocketpp是一个跨平台的开源头部专用C++库
    • 它实现了WebSocket协议和WebSocketCompression Extensions
    • 它允许将WebSocket客户端和服务器功能集成到C++程序中
    • 在最常见的配置中,全功能网络I/O由Asio网络库提供
  • WebSocketpp的主要特性
    • 事件驱动的接口
    • 支持HTTTP/HTTPS, WS/WSS, IPv6
    • 灵活的依赖管理 — Boost库/C++11标准库
    • 可移植性:Posix/Windows,32/64bit,Intel/ARM
    • 线程安全
  • WebSocketpp同时支持HTTPWebsocket两种网络协议, 比较适用于本项目, 所以选用该库作为项目的依赖库用来搭建WebSocket服务
  • 该项目常用网站
    • Github
    • 用户手册
    • 官网

2.安装

sudo apt-get install libboost-dev libboost-system-dev libwebsocketpp-dev

3.常用接口

namespace websocketpp 
{ 
    typedef lib::weak_ptr<void> connection_hdl;
    
    template <typename config>
    class endpoint : public config::socket_type 
    { 
        typedef lib::shared_ptr<lib::asio::steady_timer> timer_ptr; 
        typedef typename connection_type::ptr connection_ptr; 
        typedef typename connection_type::message_ptr message_ptr; 

		// 回调函数类型
        typedef lib::function<void(connection_hdl)> open_handler; 
        typedef lib::function<void(connection_hdl)> close_handler; 
        typedef lib::function<void(connection_hdl)> http_handler; 
        typedef lib::function<void(connection_hdl, message_ptr)> message_handler;
         
        /* websocketpp::log::alevel::none  禁止打印所有日志*/ 
        void set_access_channels(log::level channels);/*设置日志打印等级*/ 
        void clear_access_channels(log::level channels);/*清除指定等级的日志*/ 
        
        /*设置指定事件的回调函数*/ 
        void set_open_handler(open_handler h);/*websocket握手成功回调处理函数*/ 
        void set_close_handler(close_handler h);/*websocket连接关闭回调处理函数*/ 
        void set_message_handler(message_handler h);/*websocket消息回调处理函数*/ 
        void set_http_handler(http_handler h);/*http请求回调处理函数*/ 
        
        /*发送数据接口*/ 
        void send(connection_hdl hdl, std::string& payload, 
                  frame::opcode::value op); 
        void send(connection_hdl hdl, void* payload, size_t len, 
                  frame::opcode::value op); 
                  
        /*关闭连接接口*/ 
        void close(connection_hdl hdl, close::status::value code, 
                   std::string& reason); 
                   
        /*获取connection_hdl 对应连接的connection_ptr*/ 
        connection_ptr get_con_from_hdl(connection_hdl hdl); 
        /*websocketpp基于asio框架实现,init_asio用于初始化asio框架中的io_service调度器*/ 
        void init_asio(); 
        /*设置是否启用地址重用*/ 
        
        void set_reuse_addr(bool value); 
        /*设置endpoint的绑定监听端口*/ 
        
        void listen(uint16_t port); 
        /*对io_service对象的run接口封装,用于启动服务器*/ 
        
        std::size_t run(); 
        /*websocketpp提供的定时器,以毫秒为单位*/ 
        
        timer_ptr set_timer(long duration, timer_handler callback); 
    }; 

    template <typename config> 
    class server : public endpoint<connection<config>,config> 
    { 
        /*初始化并启动服务端监听连接的accept事件处理*/ 
        void start_accept(); 
    }template <typename config> 
	class connection 
	: public config::transport_type::transport_con_type 
	, public config::connection_base 
	{ 
		/*发送数据接口*/ 
		error_code send(std::string&payload, 
						frame::opcode::value op = frame::opcode::text); 
		/*获取http请求头部*/ 
		std::string const & get_request_header(std::string const & key);
		/*获取请求正文*/ 
		std::string const & get_request_body(); 
		/*设置响应状态码*/ 
		void set_status(http::status_code::value code); 
		/*设置http响应正文*/ 
		void set_body(std::string const & value); 
		/*添加http响应头部字段*/ 
		void append_header(std::string const & key, std::string 
						   const & val); 
		/*获取http请求对象*/ 
		request_type const & get_request();
		/*获取connection_ptr 对应的 connection_hdl */ 
		connection_hdl get_handle(); 
	}; 

    namespace http 
    { 
        namespace parser 
        { 
            class parser 
            { 
                std::string const & get_header(std::string const & key);
                std::string const & get_body();
                typedef std::map<std::string, 
		                std::string, utility::ci_less> header_list; 
                header_list const & get_headers();
            };

            class request : public parser 
            { 
                /*获取请求方法*/ 
                std::string const & get_method();
                /*获取请求uri接口*/ 
                std::string const & get_uri(); 
            }; 
        }
    }

    namespace message_buffer 
    { 
        /*获取websocket请求中的payload数据类型*/ 
        frame::opcode::value get_opcode(); 
        /*获取websocket中payload数据*/ 
        std::string const & get_payload(); 
    }

    namespace log 
    { 
        struct alevel 
        { 
            static level const none = 0x0; 
			// ...
        }; 
    } 

    namespace http 
    { 
        namespace status_code 
        { 
            enum value 
            { 
                uninitialized = 0, 

                continue_code = 100, 
                switching_protocols = 101, 

                ok = 200, 
                created = 201, 
                accepted = 202, 
                non_authoritative_information = 203, 
                no_content = 204, 
                reset_content = 205, 
                partial_content = 206, 

                multiple_choices = 300, 
                moved_permanently = 301, 
                found = 302, 
                see_other = 303, 
                not_modified = 304, 
                use_proxy = 305, 
                temporary_redirect = 307, 

                bad_request = 400, 
                unauthorized = 401, 
                payment_required = 402, 
                forbidden = 403, 
                not_found = 404, 
                method_not_allowed = 405, 
                not_acceptable = 406, 
                proxy_authentication_required = 407, 
                request_timeout = 408, 
                conflict = 409, 
                gone = 410, 
                length_required = 411, 
                precondition_failed = 412, 
                request_entity_too_large = 413, 
                request_uri_too_long = 414, 
                unsupported_media_type = 415, 
                request_range_not_satisfiable = 416, 
                expectation_failed = 417, 
                im_a_teapot = 418, 
                upgrade_required = 426, 
                precondition_required = 428, 
                too_many_requests = 429, 
                request_header_fields_too_large = 431, 

                internal_server_error = 500, 
                not_implemented = 501, 
                bad_gateway = 502, 
                service_unavailable = 503, 
                gateway_timeout = 504, 
                http_version_not_supported = 505, 
                not_extended = 510, 
                network_authentication_required = 511 
            };
        }
    } 
    
    namespace frame 
    { 
        namespace opcode 
        { 
            enum value 
            { 
                continuation = 0x0, 
                text = 0x1, 
                binary = 0x2, 
                rsv3 = 0x3, 
                rsv4 = 0x4, 
                rsv5 = 0x5, 
                rsv6 = 0x6, 
                rsv7 = 0x7, 
                close = 0x8, 
                ping = 0x9, 
                pong = 0xA, 
                control_rsvb = 0xB, 
                control_rsvc = 0xC, 
                control_rsvd = 0xD, 
                control_rsve = 0xE, 
                control_rsvf = 0xF, 
            };
        }
    } 
}

4.使用

  • main.cc
    #include <iostream>
    #include <websocketpp/config/asio_no_tls.hpp>
    #include <websocketpp/server.hpp>
    
    // 0.定义server_t类型
    typedef websocketpp::server<websocketpp::config::asio> server_t;
    
    void OnOpen(websocketpp::connection_hdl hdl)
    {
        std::cout << "Websocket长连接建立成功" << std::endl;
    }
    
    void OnClose(websocketpp::connection_hdl hdl)
    {
        std::cout << "Websocket长连接断开" << std::endl;
    }
    
    void OnMessage(server_t* svr, websocketpp::connection_hdl hdl, server_t::message_ptr msg)
    {
        std::string body = msg->get_payload();
        std::cout << "Get Msg: " << body << std::endl;
    
        auto conn = svr->get_con_from_hdl(hdl);
    
        conn->send(body + "-Response", websocketpp::frame::opcode::value::text);
    }
    
    int main()
    {
        // 1.实例化服务器对象
        server_t svr;
        
        // 2.初始化日志输出 --> 关闭日志输出
        svr.set_access_channels(websocketpp::log::alevel::none);
    
        // 3.初始化ASIO框架
        svr.init_asio();
    
        // 4.设置消息处理/连接握手成功/连接关闭回调函数
        svr.set_open_handler(OnOpen);
        svr.set_close_handler(OnClose);
        auto msg_handler = std::bind(OnMessage, &svr, std::placeholders::_1,
    							     std::placeholders::_2);
        svr.set_message_handler(msg_handler);
    
        // 5.启用地址重用
        svr.set_reuse_addr(true);
    
        // 6.设置监听端口
        svr.listen(8686);
    
        // 7.开始监听
        svr.start_accept();
    
        // 8.启动服务器
        svr.run();
    
        return 0;
    }
    
  • makefile
    main: main.cc
    	g++ -o $@ $^ -std=c++17 -lboost_system
    
    .PHONY:clean
    clean:
    	rm main
    
  • WS客户端
    <!DOCTYPE html> 
    <html lang="en"> 
        <head> 
            <meta charset="UTF-8"> 
            <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
            <meta name="viewport" content="width=device-width, 
                                           initial-scale=1.0"> 
            <title>Test Websocket</title> 
        </head> 
        <body> 
            <input type="text" id="message"> 
            <button id="submit">提交</button> 
    
            <script> 
                let websocket = new WebSocket("ws://IP:PORT"); 
    
                // 处理连接打开的回调函数 
                websocket.onopen = function() { 
                    console.log("连接建立"); 
                } 
                // 处理收到消息的回调函数 
                // 控制台打印消息 
                websocket.onmessage = function(e) { 
                    console.log("收到消息: " + e.data); 
                } 
                // 处理连接异常的回调函数 
                websocket.onerror = function() { 
                    console.log("连接异常"); 
                } 
                // 处理连接关闭的回调函数 
                websocket.onclose = function() { 
                    console.log("连接关闭"); 
                } 
    
                // 实现点击按钮后, 通过 websocket实例 向服务器发送请求 
                let input = document.querySelector('#message'); 
                let button = document.querySelector('#submit'); 
                button.onclick = function() { 
                    console.log("发送消息: " + input.value); 
                    websocket.send(input.value); 
                } 
            </script> 
        </body> 
    </html>
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2205010.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【王道视频笔记】红黑树的定义和性质

文章目录 关于黑高的结论红黑树的插入 平衡二叉树 AVL:插入/删除 很容易破坏“平衡”特性&#xff0c;需要频繁调整树的形态。如:插入操作导致不平衡&#xff0c;则需要先计算平衡因子&#xff0c;找到最小不平衡子树(时间开销大)&#xff0c;再进行 LL/RR/LR/RL 调整 红黑树 R…

极狐GitLab X 某轨道交通控制系统龙头企业,助力业务研发敏捷化

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 60天专业…

Linux常用应急溯源命令

常用命令 1、账号相关命令 1、查询特权用户特权用户(uid 为0)&#xff1a;awk -F: $30{print $1} etc/passwd 2、查询可以远程登录的帐号信息&#xff1a;awk /\$1|\$6/{print $1} etc/shadow 2、程序相关命令 1、查看当前开放端口netstat -tnlp 2、查看当前系统上运行的所…

华为中级认证HCIP知识点总结,建议收藏

01 OSPF知识点 OSPF基本配置&#xff0c;OSPF 5种报文&#xff0c;7种邻居状态&#xff0c;4种网络类型&#xff0c;4种特殊区域&#xff0c;7类LSA&#xff0c;4种link type&#xff0c;标识一条LSA的3个要素&#xff0c;OSPF邻居域邻接关系&#xff0c;单区域&#xff0c;多区…

生成对抗网络GAN——学习笔记

经过大量阅读资料和博客&#xff0c;对GAN的认识和学习做一个记录。个人粗浅的认识&#xff0c;不管是什么模型都离不开最基础的神经网络。主要借鉴的博客内容如下 新型的神经网络模型&#xff0c;从CNN到BERT都有介绍。_最新的神经网络模型-CSDN博客 生成对抗网络——GAN&am…

Open WebUI | 自托管的类 ChatGPT 网站

Open WebUI 是一个扩展性强、功能丰富且用户友好的自托管 WebUI&#xff0c;支持 ChatGPT 网页端的大部分功能&#xff0c;支持各类模型服务&#xff0c;包括 Ollama 和 OpenAI 的 API。该项目在 GitHub 上已有 38k 星&#xff0c;非常受欢迎。 功能介绍 本篇介绍该项目的功能…

(Kafka源码五)Kafka服务端处理消息

Kafka 服务端&#xff08;Broker&#xff09;采用 Reactor 的架构思想&#xff0c;通过1 个 Acceptor&#xff0c;N 个 Processor(N默认为3)&#xff0c;M 个 KafkaRequestHandler&#xff08;M默认为8&#xff09;&#xff0c;来处理客户端请求&#xff0c;这种模式结合了多线…

眼镜店会员积分卡系统软件试用版下载 佳易王配镜顾客信息管理系统使用操作教程

一、前言 【软件试用版资源文件下载可以点文章最后卡片了解】 眼镜店会员积分软件是专门为眼镜店设计的管理工具&#xff0c;旨在通过积分活动提升顾客的忠诚度&#xff0c;促进复购率&#xff0c;并优化顾客体验。 眼镜店会员积分卡系统软件试用版下载 佳易王配镜顾客信息管…

WEB攻防-python考点CTF与CMS-SSTI模板注入PYC反编译

知识点&#xff1a; 1、PYC&#xff08;python编译后的文件&#xff09;文件反编译&#xff1b; 2、Python-Web-SSTI&#xff1b; 3、SSTI模板注入利用分析&#xff1b; &#xff08;Server-Side Template Injection&#xff09; SSTI 就是服务器端模板注入 当前使用的一…

高级算法设计与分析-MaxFlow网络流基础知识

MaxFlow网络流 1 网络流基础概念 source:源点 sink:终点 Flow:流量 capacity:容量 Residual:残量 Residual Network:残量网络 Augmenting path:增广路径,表示从源点 s 到终点 t 不包含环的路径 Bottleneck capacity:瓶颈容量 2 最大流 2.1 基础概念 2.2 增广路算法 …

C++刷怪笼(7)string类

目录 1.前言 2.正文 2.1标准库中的string类 2.1.1string类 2.1.2auto和范围for 2.1.3string类的常用接口说明 2.2string类的模拟实现 2.2.1经典的string类问题 2.2.2浅拷贝 2.2.3深拷贝 ​编辑 2.2.4写时拷贝 3.小结 1.前言 前面我们对C的封装这一大特性进行了详细…

Win10电脑录屏全攻略:轻松掌握屏幕录制技巧

在日常生活和工作中&#xff0c;我们经常需要录制屏幕来展示操作步骤、制作教程视频或记录重要内容。如果你正在使用Win10系统&#xff0c;那么有多种方法可以轻松实现屏幕录制。下面就给大家分享五种不同的录屏工具&#xff0c;让你轻松掌握屏幕录制技巧。 一、嗨格式录屏大师…

从数据到资产,数据资产管理的风口能撑多久?

从数据到资产&#xff0c;数据资产管理的风口能撑多久&#xff1f; 前言从数据到资产 前言 在今天的大数据和人工智能世界里&#xff0c;数据的价值已被推到了前所未有的高度。作为一家企业&#xff0c;如何有效管理这些数据并从中提取出最具价值的部分&#xff0c;成了各行各…

AI产品经理指南| 面试了100位AI产品经理后的心得总结

AI正深刻地变革着各行各业&#xff0c;而在这场技术革命中&#xff0c;首先受到影响的或许正是那些与AI紧密相连的专业人士——产品经理。 我们本篇中的对话始于Vanessa对「面试了100位AI产品经理」的心得总结。 &#x1f469;&#x1f3fb; Vanessa&#xff1a; 字节跳动AI产…

NTAG_8654

NTAG_8654 产品型号 NTAG_8654 标签尺寸 85.5*54*4.3MM 芯片类型 NFC Ntag 213/215/216 工作频率 13.56MHZ 工作温度 -30C~100C 标签材质 ABS 支持协议 14443A 协议 标签材质 黑/白 安装方式 背胶粘贴或柳钉安装 应用领域 物业巡更&#xff0c;设备巡检&…

工业智能化的安全护盾,CodeMeter如何实现高效授权与防护

工业自动化的快速发展对技术创新提出了越来越高的要求。为了在全球竞争中保持领先&#xff0c;制造企业不仅需要提高生产效率&#xff0c;还必须确保软件的安全性和可靠性。如何在保证高效运营的同时&#xff0c;保护核心知识产权和防止软件盗用&#xff0c;成为了行业内的重要…

拓扑排序基础及应用案例

文章目录 基础内容应用案例&#xff1a;软件构建系统的依赖管理背景描述解决方案具体步骤示例代码 基础内容 拓扑排序&#xff08;Topological Sort&#xff09;是一种针对有向无环图&#xff08;Directed Acyclic Graphs, DAG&#xff09;的排序方法。它的目的是找出一种图中…

【树莓派5B】IO串口通信使用

超级简单的串口使用 前言零、检查准备&#xff08;可略&#xff09;0.1 查看UART引脚&#xff1a;0.2 扩展一下引脚查看的方法 一、配置准备1.1 检查端口配置1.2 查看串口映射1.3 下载minicom串口调试工具1.4 通过命令获取串口上的数据 二、python的serial进行收发测试总结 前言…

Llama-3.2-3B-Instruct PyTorch模型微调最佳实践

1 引言 Meta Llama 3.2多语言大型语言模型集合&#xff08;LM&#xff09;是一个1B和3B大小&#xff08;文本输入/文本输出&#xff09;的预训练和指令微调模型集合。Llama 3.2指令调整的纯文本模型针对多语言对话用例进行了优化&#xff0c;包括智能检索和总结任务。它们在常…

【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系

看到这句话的时候证明&#xff1a;此刻你我都在努力 加油陌生人 个人主页&#xff1a;Gu Gu Study 专栏&#xff1a;用Java学习数据结构系列 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹 喜欢的话可以点个赞谢谢了。 作者&#xff…