我们来谈谈websocket

这篇具有很好参考价值的文章主要介绍了我们来谈谈websocket。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我们来谈谈websocket,项目,linux小黑板,websocket

 "你一无所有地闯荡。"


一、初始WebSocket

(1) 什么是websocket

        WebSocket是一种在单个TCP连接上进行全双工通信的协议。

        WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

                                                                                                                        WebSocket介绍

        websocket是从HTML5开始⽀持的⼀种⽹⻚端和服务端保持 "⻓连接" 的消息推送机制。可是,我们了解到,我们使用中最广泛的 就是http\https,为什么突然又 像 "一拍脑袋般” 地搞出另一套协议呢? websocket协议又和http\https协议有何关系呢?

(2) 为什么已经有了http协议,却仍然需要websocket?

        我们传统的web程序交互,基本属于 " 一问一答方式 ", 譬如这里有很多商品,你看上了哪一个,直接点击该商品周围位置,即可向服务器发送跳转请求。我们来谈谈websocket,项目,linux小黑板,websocket           此时,客户端向服务器发送一个Http跳转请求,服务器那么也就会想当然地返回一个跳转后的Http响应结果。

        从该举的例子开看,

        "服务端永远是被动的一方",如果客户端不主动如果客⼾端不主动发起请求服务器就⽆法主动给客⼾端响应。

        这种感觉像什么?就像你心爱的女生,从不会主动发消息找你一样。

        可是,现实生活中也有这样的场景,你打开一个页面游戏,一进去此时就算你什么也不干,会看到一个 小卡拉咪 开始疯狂攻击你,像这样……

我们来谈谈websocket,项目,linux小黑板,websocket

         可是你知道,你什么也没干,按以往理解的传统web交互方式是,“一问一答”。但对于这种场景而言,非常依赖 "服务器"消息推送,告知客户端一些"状态"(例如: 你现在被打掉血了)。此时,就即需要服务器主动推动消息到客⼾端。

        原生的http能实现吗? 当然!客户端显然可以采用一种 "轮询"的⽅式,不停向服务器发送http报头,得到结果反馈。但这其实是一种 "伪服务器推"的方式,并且 轮询的成本⽐较⾼,服务端也不能及时的获取到消息的响应。因此,对于网页游戏这种在同一时间会产生大量的数据推送,这种方式一定是不高效的。

        我们来谈谈websocket,项目,linux小黑板,websocket

        我们都知道tcp是全双工的(即两端都可以互发数据,互接收数据)。可是,按照http的发送方式,"一问一答",好好的全双工机制,反而成了半双工了! 当然,这也不能怪http,因为很早网络没那么发达时,对于http应用层协议设计考虑之初,仅仅着眼于,看网页文本资源,压根没考虑网页游戏等,需要大量服务器向客户端推送数据的场景。

        由此,新的应该层协议,websocket被设计出来。

    

(3) websocket与http有什么区别?

websocket协议切换(升级)

        我们大概会使用网页做如下的三种场景: 看文本信息、刷视频、玩玩页游。我们来谈谈websocket,项目,linux小黑板,websocket

         三次请求的首先都是向服务器发送http请求,进行第一次通信。对于client1、client2而言,使用普通的http请求就能完成正常的数据交互过程,那么这它们就会继续保持用http协议进行交互。可是,对于client3而言,使用http协议并不能满足数据交互的需求,因此对它而言,就需要建立websocket来与服务器进行数据交互。

        此时,第二次http请求会在请求报头中携带一些特殊的报头信息:

        我们来谈谈websocket,项目,linux小黑板,websocket

响应报头:

我们来谈谈websocket,项目,linux小黑板,websocket

        我们来谈谈websocket,项目,linux小黑板,websocket

        

也许你会看到这样的言论,

websocket是基于http的协议,这对吗?

        这其实是不对的,因为websocket是在建立连接时,才进行切换的协议。

        我们来谈谈websocket,项目,linux小黑板,websocket

        而websocket是需要http来进行协议切换的,升级完成之后和http就没有任何关系了。 

        就像你喜欢的女神,借你搭线要到了你室友的联系方式。接下来之后他们就开始聊了起来,把你晾在了一边。

        websocket完美继承了tcp的全双工能力,适用于服务器和客户端需要大量数据交互的场景,            如:网页游戏、小程序游戏、网路聊天室……

(4) websocket协议格式

我们来谈谈websocket,项目,linux小黑板,websocket

        在websocket这一层,数据包按照 "帧"称呼。 

•FIN: WebSocket传输数据以 "消息" 为概念单位,⼀个消息有可能由⼀个或多个帧组成,FIN字段为1表⽰末尾帧。

• RSV1~3:保留字段,只在扩展时使⽤,若未启⽤扩展则应置1,若收到不全为0的数据帧,且未协商扩展则⽴即终⽌连接。
 

• opcode(0000~1111):标志当前数据帧的类型
0x0:表⽰这是个延续帧,当opcode为0表⽰本次数据传输采⽤了数据分⽚,当前收到的帧为其中⼀个分⽚
0x1:表⽰这是⽂本帧
0x2:表⽰这是⼆进制帧
0x3-0x7:保留,暂未使⽤
0x8:表⽰连接断开
0x9:表⽰ping帧
0xA:表⽰pong帧
0xB-0xF:保留,暂未使⽤

• mask:表⽰Payload数据是否被编码,若为1则必有Mask-Key,⽤于解码Payload数据。仅 "客⼾端发送给服务端" 的消息需要设置。 这也是秘钥:我们来谈谈websocket,项目,linux小黑板,websocket

• Payloadlength:数据载荷的⻓度,单位是字节,有可能为”7位、7+16位、7+64位”。假设Payloadlength=x
x为0~125:表示payload的总共长度
x为126: 表示该范围在(126~ 7位+16位(65,535) ) 这个时候需要读16位,表示payload的真实长度。

 x为127: 表示该范围为(127,7位+64位) 按照这里获取payload的数据字段大小。

• Payloaddata:报⽂携带的载荷数据


二、  Websocketpp介绍

        WebSocketpp是⼀个跨平台的开源(BSD许可证)头部"专⽤C++库",它实现了RFC6455(WebSocket协议)和RFC7692(WebSocketCompressionExtensions)。它允许将WebSocket客⼾端和服务器功能集成到C++程序中。在最常⻅的配置中,全功能⽹络I/O由Asio⽹络库提供。

        

 WebSocketpp的主要特性包括:

• 事件驱动的接⼝
• ⽀持 ”HTTP/HTTPS”、WS/WSS、IPv6
• 灵活的依赖管理—Boost库/C++11标准库
• 可移植性:Posix/Windows、32/64bit、Intel/ARM
• 线程安全

下面是一些websocketpp库介绍网站:

⽤⼾⼿册:WebSocket++: Main Page

官⽹:WebSocket++ | Zaphoyd Studios

(1) websocket相关接口的介绍

① 服务器初始化函数:

namespace websocketpp
{
        template <typename config>
        class server : public endpoint<connection<config>,config> {
            /*websocketpp基于asio框架实现,init_asio⽤于初始化asio框架中的io_service调度器*/
            void init_asio();

            /*设置是否启⽤地址重⽤ == setsockopt*/
            void set_reuse_addr(bool value);

            /*设置endpoint的绑定监听端⼝ == listen(sockfd,backlog)*/
            void listen(uint16_t port);

            /*初始化并启动服务端监听连接的accept事件处理 == accept*/
            void start_accept();

            /*对io_service对象的run接⼝封装,⽤于启动服务器*/
            std::size_t run();
    };
}

② 连接句柄:

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;
   }
}

 ③ 相关函数设置:

namespace websocketpp
{
    // 设置⽇志打印等级
    void set_access_channels(log::level channels);
    // 清除指定等级的⽇志
    void clear_access_channels(log::level channels);
    
    // 设置bind回调函数
    void set_open_handler(open_handler h);
    void set_close_handler(close_handler h);
    void set_message_handler(message_handler h);
    void set_http_handler(http_handler h);


    // websocket发送数据接口
    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);
}

④ http相关:

报文设置

namespace websocketpp
{

    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 websocketpp
{
    namespace http {
        namespace parser {
                class parser {
                    // 取得报头
                    std::string const & get_header(std::string const & key)
                }
                class request : public parser {
                    /*获取请求⽅法*/
                    std::string const & get_method()
                    /*获取请求uri接⼝*/
                    std::string const & get_uri()
             };
         }
    }

}

状态码:

/* http 状态码 */
namespace http {
    namespace status_code {
        enum value {
        uninitialized = 0,
        continue_code = 100,
        switching_protocols = 101,

        /* 200 */
        ok = 200,
        created = 201,
        accepted = 202,
        non_authoritative_information = 203,
        no_content = 204,
        reset_content = 205,
        partial_content = 206,
        
        /* 300 */
        multiple_choices = 300,
        moved_permanently = 301,
        found = 302,
        see_other = 303,
        not_modified = 304,
        use_proxy = 305,
        temporary_redirect = 307


        //....
}

 格式类型:

namespace frame {
    namespace opcode {
        enum value {
            continuation = 0x0,
            text = 0x1,
            binary = 0x2,
            rsv3 = 0x3,
            rsv4 = 0x4,
            rsv5 = 0x5,
            rsv6 = 0x6,
            rsv7 = 0x7,
            close = 0x8,    
            // .... 
        }
    }
}

⑤ 日志等级:

namespace log {
    struct alevel {
    static level const none = 0x0;
    static level const connect = 0x1;
    static level const disconnect = 0x2;
    static level const control = 0x4;
    static level const frame_header = 0x8;
    static level const frame_payload = 0x10;
    static level const message_header = 0x20;
    static level const message_payload = 0x40;
    static level const endpoint = 0x80;
    static level const debug_handshake = 0x100;
    static level const debug_close = 0x200;
    static level const devel = 0x400;
    static level const app = 0x800;
    static level const http = 0x1000;
    static level const fail = 0x2000;
    static level const access_core = 0x00003003;
    static level const all = 0xffffffff;
    };
}

三、 搭建简易的基于websocket的服务器

(1) 初始化服务器     

① 头文件包含

        因为需要初始化服务器,因此我们得首先找到websocket库路径下的server.hpp,以及需要配置的调度器asio文件。

我们来谈谈websocket,项目,linux小黑板,websocket       创建的是server,并且不采用加密tls。因此,我们的头文件就需要包含这两个文件。

#include <iostream>
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>

int main()
{
    return 0;
}

② 基本websocket信息 

 // 配置调度器
 // 鉴于" websocketpp::server<websocketpp::config::asio> "这个类型太长了 我们进行typedef一下
typedef websocketpp::server<websocketpp::config::asio> wsser_t;
int main()
{
    wsser_t wsser;
    // 1. 设置日志等级
    wsser.set_access_channels(websocketpp::log::alevel::none);
    
    // 2. 初始化调度器
    wsser.init_asio();

    // 3. 设置地址重用
    wsser.set_reuse_addr(true);
    return 0;
}

③ 回调函数设置:

        根据库中提供的回调函数类型:

    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;

我们来谈谈websocket,项目,linux小黑板,websocket

         仅仅这样设置,对于回调函数而言,只是拿到了一个未初始化的connection_hd1, 我们需要用wsser_t 中的 方法 get_conn_from_hdl(), 才能真正拿到连接句柄。因此,我们必须要把wsser传入到函数中。可是,该函数已经设置,并且typedef好了,怎么才能给该函数增加参数呢?这里,我们就需要用到C++提供的bind函数。我们来谈谈websocket,项目,linux小黑板,websocket

 文章来源地址https://www.toymoban.com/news/detail-662027.html

④ 服务器正常启动:

我们来谈谈websocket,项目,linux小黑板,websocket

(2) http报头解析

         搭建完了简易的服务器,我们接下来通过编写回调函数,来控制我们的行为。

void http_callback(wsser_t *srv, websocketpp::connection_hdl hd1)
{
    // 交由智能指针管理
    wsser_t::connection_ptr conn = srv->get_con_from_hdl(hd1);
    // 获取正文
    std::string req_body = conn->get_request_body();
    std::cout << "req_body: " << req_body << std::endl;

    // 获取方法和uri = 解析http
    websocketpp::http::parser::request req = conn->get_request();
    std::cout << "method: " << req.get_method() << std::endl;
    std::cout << "uri: " << req.get_uri() << std::endl;

    // 构建响应
    std::string resp_body = "<html><body><h1>Hello World</h1></body></html>";
    conn->set_body(resp_body);
    conn->append_header("Content-Type","text/html");
    conn->set_status(websocketpp::http::status_code::ok);
}

        这个函数是针对处理http请求的报文,并返回一个 "Hello World" 的标签页面。

测试:
        我们来谈谈websocket,项目,linux小黑板,websocket

        这就是一个普通的http请求与响应。 

        

(3) websocket主动向客户端发消息

        这里,我们采取客户端向服务端 提交 "信息",服务端通过websocket进行将消息再继续回显到客户端上。

        在开始之前,我们得有一个前端交互的页面:

<!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>
	// 创建 websocket 实例 
    // 这里专门连接 服务器主机
	let websocket = new WebSocket("ws://47.115.203.63:8801");
	// 处理连接打开的回调函数
	websocket.onopen = function() {
		alert("连接建立");
	}
	
	// 处理收到消息的回调函数
	// 控制台打印消息
	websocket.onmessage = function(e) {
		alert("收到消息: " + e.data);
	}
	
	// 处理连接异常的回调函数
	websocket.onerror = function() {
		alert("连接异常");
	}
	
	// 处理连接关闭的回调函数
	websocket.onclose = function() {
		alert("连接关闭");
	}
	
	// 实现点击按钮后, 通过 websocket实例 向服务器发送请求
	let input = document.querySelector('#message');
	let button = document.querySelector('#submit');
	button.onclick = function() {
		alert("发送消息: " + input.value);
		websocket.send(input.value);
		input.value = ""; // 清空消息
	}
	
</script>
</body>
</html>

测试:
我们来谈谈websocket,项目,linux小黑板,websocket

走的是 websocket协议层。 

我们来谈谈websocket,项目,linux小黑板,websocket 

        最终,我们的websocket简易服务器也就搭建好了。


 

总结:

        websocket无论是在学习、还是使用上肯定都简单于手搓一个 系统层面上的建立连接和http报文Parse。它通过http进行协议切换(升级),保证服务端可以主动向客户端推送消息。

本篇到此结束,感谢你的阅读。

祝你好运,向阳而生~

我们来谈谈websocket,项目,linux小黑板,websocket

 

到了这里,关于我们来谈谈websocket的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 敲黑板!java反射机制和原理

    获取Class对象:首先,你需要获取表示要操作的类的 Class 对象。可以使用以下三种方式之一来获取 Class 对象: Class.forName() 方法:使用类的全限定名获取 Class 对象,例如: Class? clazz = Class.forName(\\\"com.example.MyClass\\\"); .class 语法:如果你已经有了类的实例,可以使用 .class 语法来获

    2024年02月08日
    浏览(43)
  • 【实战项目开发技术分享】谈谈机器人如何进行脱困

    在机器人科学和技术领域,我们经常谈论的是机器人的精密运动、

    2024年02月09日
    浏览(62)
  • 【小黑嵌入式系统第八课】初识PSoC Creator™开发——关于PSoC Creator&下载、创建项目、单片机中的hello world(点亮一个led)

    上一课: 【小黑嵌入式系统第七课】PSoC® 5LP 开发套件(CY8CKIT-050B )——PSoC® 5LP主芯片、I/O系统、GPIO控制LED流水灯的实现 下一课: 【小黑嵌入式系统第九课】PSoC 5LP第一个实验——LED、字符型LCD显示实验 本课程主要介绍了 PSoC® 5LP, 一个基于 ARM® Cortex®-M3 的可编程片上系

    2024年02月03日
    浏览(62)
  • 【Linux】谈谈vim, gdb,yum,gcc&g++的使用

    目录 一, yum ——linux软件包管理器  1. 软件包是啥子?  2.  yum基本使用  1. 步骤:  2. 开发工具推荐(centos 7.6) 二,vim —— linux文本编辑器 1. Normal mode  ——  命令模式(记不住没关系,多练就行) 2.  last line  mode——   末行模式 (如何进入;shift :) 3. Insert mode ——插

    2024年02月08日
    浏览(46)
  • UE4/5AI制作基础AI(适合新手入门,运用黑板,行为树,ai控制器,角色类,任务)

    目录 制作流程 第一步:创建资产 然后创建一个AIController 之后创建一个黑板和行为树:  第二步:制作 黑板 行为树 任务 运行行为树  结果 第一步直接复制你的人物蓝图,做一个npc: 然后创建一个AIController 之后创建一个 黑板和行为树 :   首先打开你的BP_NPC的pawn类,然后

    2024年02月16日
    浏览(95)
  • 项目中我们各个微服务的POM详解

    我们一开始一定要检查我们的IDEA中maven有没有和我们的安装的位置对应上。否则后期很容易报错 ①、在我们的父模块中有几个很重要的标签: 第一个是我们的 Modules 标签,后期我们加入新的服务会自动在里面添加 ②、打包的方式:我们在父级工程或者聚合项目中,使用POM:

    2023年04月24日
    浏览(46)
  • 谈谈linux网络编程中的应用层协议定制、Json序列化与反序列化那些事

    由于socket api的接口,在读写数据的时候是以字符串的方式发送接收的,如果需要传输 结构化的数据 ,就需要制定一个协议 结构化数据在发送到网络中之前需要完成序列化 接收方收到的是序列字节流,需要完成反序列化才能使用(如ChatInfo._name) 当我们进行网络通信的的时

    2024年02月06日
    浏览(61)
  • websocket项目 聊天室

    1.项目概述 这个项目是一个基本的实时聊天应用,适用于小型团队或群体。提供了多个聊天室供用户选择。可以通过该代码进行进一步的扩展和定制,例如添加聊天机器人、改进界面等。 2.技术栈 flask,boostrapt,websocket,twemoji 3.项目结构 4.关键特点 Web框架: 项目使用 Flask

    2024年01月20日
    浏览(50)
  • 系统设计 - 我们如何通俗的理解那些技术的运行原理 - 第八部分:Linux、安全

    本心、输入输出、结果 编辑:简简单单 Online zuozuo 地址:https://blog.csdn.net/qq_15071263 如果觉得本文对你有帮助,欢迎点赞、收藏、评论 我们使用视觉效果和简单术语来解释复杂的系统是如何运转的,帮助我们理解技术细节 我们使用视觉效果和简单术语来解释复杂的系统是如何

    2024年02月03日
    浏览(39)
  • Shizuku,小黑屋,手机冻结应用

    (来自vivo IQOO系列Android11系统,手机编辑)酷安下载app 手机连接WiFi,通过无线调试启动,点击配对 开发者选项 打开开发者选项, 打开USB调试,无线调试, 点击上图无线调试左侧,选择 在 Shizuku 的通知中填入配对码 启动 Shizuku,如下图所示,表示成功 在已授权的应用中,

    2024年02月15日
    浏览(207)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包