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

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

目录

  • 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.ccg++ -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.mrgr.cn/news/44312.html

相关文章:

  • 河网结构指标对应的英文名称
  • Crypto虐狗记---”你“和小鱼(六)
  • NRF52832
  • 调试意义、步骤及方式
  • 在Ubuntu 16.04上使用Logrotate管理日志文件
  • 通信工程学习:什么是IOT物联网
  • scipy.stats.nakagami简介
  • 智能制造领域的系统都有啥,MES、APS、PLC、SCADA等
  • import torch报错问题:OSError: [WinError 126] 找不到指定的模块。
  • rocketmq
  • 05:(寄存器开发)定时器一
  • 内网Debian\Ubuntu服务器安装dep包,基于apt-rdepends下载相关依赖
  • ZJYYC2360. 圆球的最大得分
  • 【python实操】python小程序之定义类
  • 【Linux】Linux命令与操作详解(一)文件管理(文件命令)、用户与用户组管理(创建、删除用户/组)
  • cisco交换机命令大全
  • [SAP ABAP] 程序调用
  • 解决方案:batch_size跟epoch有什么不同
  • 学校周赛(3)
  • 【Llamaindex RAG实践】