封装利用libwebsockets写出的客户端、服务端程序为客户端服务端类

2023-05-16

封装利用libwebsockets写出的客户端、服务端程序为客户端服务端类


文章目录

  • 封装利用libwebsockets写出的客户端、服务端程序为客户端服务端类
    • 1.封装
    • 2.封装后写wss客户端、服务端
    • 3.测试结果
    • 4.客户端、服务端类程序

1.封装

我们后续将使用c++来开发程序,因此有必要将用c写成的wss客户端、服务端程序作进一步封装,使其成为wss客户端类和服务端类,这样更便于调用。封装后的程序结构:

ubuntu@ubuntu-virtual-machine:~/work/test_libwebsockets/lws_class$ tree 
.
├── client
│   ├── client
│   ├── compile.sh
│   ├── lws_client.cpp
│   ├── lws_client.h
│   └── test.cpp
└── server
    ├── compile.sh
    ├── lws_server.cpp
    ├── lws_server.h
    ├── server
    └── test.cpp

2 directories, 10 files

2.封装后写wss客户端、服务端

封装后写wss客户端和服务端将非常方便,只需要几行即可创建一个客户端或者服务端:

服务端创建测试程序:

#include "lws_server.h"
#include <signal.h>

static int interrupted;

void sigint_handler(int sig)
{
	interrupted = 1;
}

int main(int argc,char **argv)
{
    //接收SIGINT(ctrl+c)信号
    signal(SIGINT, sigint_handler);
    int n = 0;

    //创建服务器对象(可以指定端口,这里指定了8000)
    lws_server server(8000);

    //初始化服务器
    server.init();
    lwsl_notice("port:%d\n",server.get_port());

    //设置ssl(不使用ssl则传空,使用则传入证书文件路径)
    server.set_ssl(NULL,NULL,NULL,0);

    //创建服务器
    server.create();

    //服务器运行(运行时可设置间隔等待时间,这里为1000,单位为ms)
    while(n >= 0 && !interrupted)
        n = server.run(1000);

    //销毁资源
    server.destroy();

    return 0;
}

客户端创建测试程序:

#include "lws_client.h"
#include <signal.h>

static int interrupted;

void sigint_handler(int sig)
{
	interrupted = 1;
}

int main(int argc,char **argv)
{
    signal(SIGINT, sigint_handler);
    int n = 0;

    //创建客户端对象(传入服务器地址和端口)
    lws_client client("127.0.0.1",8000);

    //初始化客户端
    client.init();

    //设置ssl
    client.set_ssl(NULL,NULL,NULL,0);

    //创建客户端
    client.create();

    //连接服务器(需要ssl连接时传入1,否则传0)
    client.connect(0);

    //客户端运行
    while(n >= 0 && !interrupted)
        n = client.run(1000);

    //销毁资源
    client.destroy();

    return 0;
}

3.测试结果

运行服务端:

ubuntu@ubuntu-virtual-machine:~/work/test_libwebsockets/lws_class/server$ ./server 
[2018/09/12 18:34:56:3472] NOTICE: port:8000
[2018/09/12 18:34:56:3493] NOTICE: Creating Vhost 'default' port 8000, 1 protocols, IPv6 off

运行客户端:

ubuntu@ubuntu-virtual-machine:~/work/test_libwebsockets/lws_class/client$ ./client 
[2018/09/12 18:35:43:4919] NOTICE: Creating Vhost 'default' (serving disabled), 1 protocols, IPv6 off
[2018/09/12 18:35:43:4947] NOTICE: Connected to server ok!
[2018/09/12 18:35:43:4964] NOTICE: Tx: 你好 1
[2018/09/12 18:35:43:4987] NOTICE: Tx: 你好 2
[2018/09/12 18:35:43:4994] NOTICE: Rx: 你好 1
[2018/09/12 18:35:43:4999] NOTICE: Rx: 你好 2
[2018/09/12 18:35:43:5000] NOTICE: Tx: 你好 3
[2018/09/12 18:35:43:5007] NOTICE: Rx: 你好 3

服务端:

ubuntu@ubuntu-virtual-machine:~/work/test_libwebsockets/lws_class/server$ ./server 
[2018/09/12 18:34:56:3472] NOTICE: port:8000
[2018/09/12 18:34:56:3493] NOTICE: Creating Vhost 'default' port 8000, 1 protocols, IPv6 off
[2018/09/12 18:35:43:4939] NOTICE: Client connect!
[2018/09/12 18:35:43:4979] NOTICE: recvied message:你好 1
[2018/09/12 18:35:43:4989] NOTICE: recvied message:你好 2
[2018/09/12 18:35:43:5001] NOTICE: recvied message:你好 3

测试通信成功。目前服务器为回显服务器,其底层采用的poll机制。

4.客户端、服务端类程序

服务端程序类:

#include "lws_server.h"

#define MAX_PAYLOAD_SIZE  (10 * 1024)

static struct lws_context_creation_info ctx_info = { 0 };
static struct lws_context *context = NULL;

/**
 * 会话上下文对象,结构根据需要自定义
 */
struct session_data {
    int msg_count;
    unsigned char buf[LWS_PRE + MAX_PAYLOAD_SIZE];
    int len;
    bool bin;
    bool fin;
};

/*
构造函数
*/
lws_server::lws_server(int listen_port)
{
    port = listen_port;
}

/*
析构函数
*/
lws_server::~lws_server()
{
    lwsl_notice("析构完成\n");
}

/*
拷贝构造
*/
lws_server::lws_server(const lws_server &obj)
{
    
}

int lws_server::get_port()
{
    return port;
}

/*
服务器底层实现的回调函数
*/
static int protocol_my_callback(struct lws *wsi, 
                        enum lws_callback_reasons reason, 
                        void *user, 
                        void *in, 
                        size_t len )
{
    struct session_data *data = (struct session_data *) user;

    switch ( reason ) {
        case LWS_CALLBACK_ESTABLISHED:       // 当服务器和客户端完成握手后
            lwsl_notice("Client connect!\n");
            break;

        case LWS_CALLBACK_RECEIVE:           // 当接收到客户端发来的帧以后
            // 判断是否最后一帧
            data->fin = lws_is_final_fragment( wsi );
            // 判断是否二进制消息
            data->bin = lws_frame_is_binary( wsi );
            // 对服务器的接收端进行流量控制,如果来不及处理,可以控制之
            // 下面的调用禁止在此连接上接收数据
            lws_rx_flow_control( wsi, 0 );
 
            // 业务处理部分,为了实现Echo服务器,把客户端数据保存起来
            memcpy( &data->buf[ LWS_PRE ], in, len );
            data->len = len;
            lwsl_notice("recvied message:%s\n",&data->buf[ LWS_PRE ]);
 
            // 需要给客户端应答时,触发一次写回调
            lws_callback_on_writable( wsi );
            data = NULL;
            break;

        case LWS_CALLBACK_SERVER_WRITEABLE:   // 当此连接可写时
            lws_write( wsi, &data->buf[ LWS_PRE ], data->len, LWS_WRITE_TEXT );
            // 下面的调用允许在此连接上接收数据
            lws_rx_flow_control( wsi, 1 );
            break;
    }

    // 回调函数最终要返回0,否则无法创建服务器
    return 0;
}

/**
 * 支持的WebSocket子协议数组
 * 子协议即JavaScript客户端WebSocket(url, protocols)第2参数数组的元素
 * 你需要为每种协议提供回调函数
 */
struct lws_protocols protocols[] = {
    {
        //协议名称,协议回调,接收缓冲区大小
        "ws", protocol_my_callback, sizeof( struct session_data ), MAX_PAYLOAD_SIZE,
    },
    {
        NULL, NULL,   0 // 最后一个元素固定为此格式
    }
};

void lws_server::init()
{
    ctx_info.port = 8000;
    ctx_info.iface = NULL; // 在所有网络接口上监听
    ctx_info.protocols = protocols;
    ctx_info.gid = -1;
    ctx_info.uid = -1;
    ctx_info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
}

int lws_server::set_ssl(const char* ca_filepath, 
                            const char* server_cert_filepath,
                            const char*server_private_key_filepath,
                            bool is_support_ssl)
{
    if(!is_support_ssl)
    {
        ctx_info.ssl_ca_filepath = NULL;
        ctx_info.ssl_cert_filepath = NULL;
        ctx_info.ssl_private_key_filepath = NULL;
    }
    else
    {
        ctx_info.ssl_ca_filepath = ca_filepath;
        ctx_info.ssl_cert_filepath = server_cert_filepath;
        ctx_info.ssl_private_key_filepath = server_private_key_filepath;
        ctx_info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
    //ctx_info.options |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
    }

    return is_support_ssl;
}


int lws_server::create()
{
    context = lws_create_context(&ctx_info);
    if (!context) {
		lwsl_err("lws_server create failed\n");
		return -1;
	}
    return 1;
}


int lws_server::run(int wait_time)
{
    return lws_service(context, wait_time);
}

void lws_server::destroy()
{
    lws_context_destroy(context);
}
/******************************************************************************

                  版权所有 (C), 2017-2019, ZY

 ******************************************************************************
  文 件 名   : lws_server.h
  版 本 号   : 初稿
  作    者   : ZY
  生成日期   : 2018年9月12日 星期三
  最近修改   :
  功能描述   : lws_server.cpp 的头文件
  函数列表   :
  修改历史   :
  1.日    期   : 2018年9月12日 星期三
    作    者   : ZY
    修改内容   : 创建文件

******************************************************************************/

/*----------------------------------------------*
 * 包含头文件                                   *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 外部变量说明                                 *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 外部函数原型说明                             *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 内部函数原型说明                             *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 全局变量                                     *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 模块级变量                                   *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 常量定义                                     *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 宏定义                                       *
 *----------------------------------------------*/

#ifndef __LWS_SERVER_H__
#define __LWS_SERVER_H__


#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */

#include <libwebsockets.h>

class lws_server
{
    private:
        int port;

    public:
        lws_server(int listen_port);
        
        ~lws_server();

        lws_server(const lws_server &obj);

        int get_port();

        void init();

        int set_ssl(const char* ca_filepath, 
                            const char* server_cert_filepath,
                            const char*server_private_key_filepath,
                            bool is_support_ssl);

        int create();

        int run(int wait_time);

        void destroy();
};

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */


#endif /* __LWS_SERVER_H__ */

客户端程序类:

#include "lws_client.h"

#define MAX_PAYLOAD_SIZE  10 * 1024

static struct lws_context_creation_info ctx_info = { 0 };
static struct lws_context *context = NULL;
static struct lws_client_connect_info conn_info = { 0 };
static struct lws *wsi = NULL;

/**
 * 会话上下文对象,结构根据需要自定义
 */
struct session_data {
    int msg_count;
    unsigned char buf[LWS_PRE + MAX_PAYLOAD_SIZE];
    int len;
};

/**
 * 某个协议下的连接发生事件时,执行的回调函数
 *
 * wsi:指向WebSocket实例的指针
 * reason:导致回调的事件
 * user 库为每个WebSocket会话分配的内存空间
 * in 某些事件使用此参数,作为传入数据的指针
 * len 某些事件使用此参数,说明传入数据的长度
 */
int lws_client_callback( struct lws *wsi, 
                enum lws_callback_reasons reason, 
                void *user, 
                void *in, 
                size_t len )
{
    struct session_data *data = (struct session_data *) user;

    switch ( reason ) {

        case LWS_CALLBACK_CLIENT_ESTABLISHED:   // 连接到服务器后的回调
            lwsl_notice( "Connected to server ok!\n" );
            break;
 
        case LWS_CALLBACK_CLIENT_RECEIVE:       // 接收到服务器数据后的回调,数据为in,其长度为len
            lwsl_notice( "Rx: %s\n", (char *) in );
            break;

        case LWS_CALLBACK_CLIENT_WRITEABLE:     // 当此客户端可以发送数据时的回调
            if ( data->msg_count < 3 ) {
                // 前面LWS_PRE个字节必须留给LWS
                memset( data->buf, 0, sizeof( data->buf ));
                char *msg = (char *) &data->buf[ LWS_PRE ];
                data->len = sprintf( msg, "你好 %d", ++data->msg_count );
                lwsl_notice( "Tx: %s\n", msg );
                // 通过WebSocket发送文本消息
                lws_write( wsi, &data->buf[ LWS_PRE ], data->len, LWS_WRITE_TEXT );
            }
            break;

        default:
            break;
//            lwsl_notice("not support\n");
    }

    return 0;
}

/**
 * 支持的WebSocket子协议数组
 * 子协议即JavaScript客户端WebSocket(url, protocols)第2参数数组的元素
 * 你需要为每种协议提供回调函数
 */
struct lws_protocols protocols[] = {
    {
        //协议名称,协议回调,接收缓冲区大小
        "ws", lws_client_callback, sizeof( struct session_data ), MAX_PAYLOAD_SIZE,
    },
    {
        NULL, NULL,   0 // 最后一个元素固定为此格式
    }
};

/*
构造函数
*/
lws_client::lws_client(char *_address,int _port)
{
    server_address = _address;
    port = _port;
}

/*
析构函数
*/
lws_client::~lws_client()
{
    lwsl_notice("析构完成\n");
}

/*
拷贝构造
*/
lws_client::lws_client(const lws_client &obj)
{
    
}

/*
初始化
*/
void lws_client::init()
{
    ctx_info.port = CONTEXT_PORT_NO_LISTEN;
    ctx_info.iface = NULL;
    ctx_info.protocols = protocols;
    ctx_info.gid = -1;
    ctx_info.uid = -1;
}

/*
设置ssl
*/
int lws_client::set_ssl(const char* ca_filepath, 
                            const char* server_cert_filepath,
                            const char*server_private_key_filepath,
                            bool is_support_ssl)
{
    if(!is_support_ssl)
    {
        ctx_info.ssl_ca_filepath = NULL;
        ctx_info.ssl_cert_filepath = NULL;
        ctx_info.ssl_private_key_filepath = NULL;
    }
    else
    {
        ctx_info.ssl_ca_filepath = ca_filepath;
        ctx_info.ssl_cert_filepath = server_cert_filepath;
        ctx_info.ssl_private_key_filepath = server_private_key_filepath;
        ctx_info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
    //ctx_info.options |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
    }

    return is_support_ssl;
}

/*
创建客户端
*/
int lws_client::create()
{
    // 创建一个WebSocket处理器
    context = lws_create_context( &ctx_info );
    if(!context)
        return -1;
    return 0;
}

/*
连接客户端
*/
int lws_client::connect(int is_ssl_support)
{
    char addr_port[256] = { 0 };
    sprintf(addr_port, "%s:%u", server_address, port & 65535 );
 
    // 客户端连接参数
    conn_info = { 0 };
    conn_info.context = context;
    conn_info.address = server_address;
    conn_info.port = port;

    if(!is_ssl_support)
        conn_info.ssl_connection = 0;
    else
        conn_info.ssl_connection = 1;
    conn_info.path = "./";
    conn_info.host = addr_port;
    conn_info.origin = addr_port;
    conn_info.protocol = protocols[ 0 ].name;
 
    // 下面的调用触发LWS_CALLBACK_PROTOCOL_INIT事件
    // 创建一个客户端连接
    wsi = lws_client_connect_via_info( &conn_info );
    if(!wsi)
        return -1;
    return 1;
}

/*
运行客户端
*/
int lws_client::run(int wait_time)
{
    lws_service( context, wait_time );
    /**
     * 下面的调用的意义是:当连接可以接受新数据时,触发一次WRITEABLE事件回调
     * 当连接正在后台发送数据时,它不能接受新的数据写入请求,所有WRITEABLE事件回调不会执行
     */
    lws_callback_on_writable( wsi );
}

/*
销毁
*/
void lws_client::destroy()
{
    lws_context_destroy(context);
}
/******************************************************************************

                  版权所有 (C), 2017-2019, ZY

 ******************************************************************************
  文 件 名   : lws_client.h
  版 本 号   : 初稿
  作    者   : ZY
  生成日期   : 2018年9月12日 星期三
  最近修改   :
  功能描述   : lws_client.cpp 的头文件
  函数列表   :
  修改历史   :
  1.日    期   : 2018年9月12日 星期三
    作    者   : ZY
    修改内容   : 创建文件

******************************************************************************/

/*----------------------------------------------*
 * 包含头文件                                   *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 外部变量说明                                 *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 外部函数原型说明                             *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 内部函数原型说明                             *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 全局变量                                     *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 模块级变量                                   *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 常量定义                                     *
 *----------------------------------------------*/

/*----------------------------------------------*
 * 宏定义                                       *
 *----------------------------------------------*/

#ifndef __LWS_CLIENT_H__
#define __LWS_CLIENT_H__


#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */

#include "libwebsockets.h"

class lws_client
{
    private:

        char *server_address;

        int port;

    public:

        lws_client(char *lws_server_address,int port);

        ~lws_client();

        lws_client(const lws_client &obj);

        void init();

        int set_ssl(const char* ca_filepath, 
                            const char* server_cert_filepath,
                            const char*server_private_key_filepath,
                            bool is_support_ssl);

        int create();

        int connect(int is_ssl_support);

        int run(int wait_time);

        void destroy();
};


#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */


#endif /* __LWS_CLIENT_H__ */
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

封装利用libwebsockets写出的客户端、服务端程序为客户端服务端类 的相关文章

  • 广播地址、组播地址、网关和子网掩码

    一 IP地址分类 IP地址一共32位 xff0c 由两部分组成 xff0c 网络号和主机号 网络号标识当前设备处于Internet的哪一个网络 xff0c 主机号标识当前设备属于该网络中的那一台主机 IP地址一共分为5类 xff1a 地址分
  • URL格式

    一 URL基本格式 一个完整的url包含方案 用户名 密码 主机名 端口 路径 参数 查询和片段 xff0c 格式如下 xff1a lt scheme gt lt user gt lt password gt 64 lt host gt l
  • c++构造函数和析构函数

    一 构造函数和析构函数的特点 构造函数和析构函数是一种特殊的公有成员函数 xff0c 每一个类都有一个默认的构造函数和析构函数 xff1b 构造函数在类定义时由系统自动调用 xff0c 析构函数在类被销毁时由系统自动调用 xff1b 构造函
  • linux下常用压缩命令

    一 tar命令 tar命令用来打包一个目录 xff0c 它支持三种格式 xff1a tar bz2 34 和 gz 34 1 1 压缩 tar cvf 文件名 tar 文件目录 打包成 tar文件 tar jcvf 文件名 tar bz2
  • 用vscode开发autojs,输出窗口不显示任何输出结果

    我的情况是 xff1a 我vscode开发autojs 程序 xff0c 之前在一切正常的情况下 xff0c 输出窗口可以正常显示程序运行结果 xff0c 右侧红圈里可以选择我连接的手机型号 如下图 xff1a 但是现在出现问题 xff1a
  • ubuntu开机没有ens33解决方法

    最近重新安装了VMware xff0c 使用之前的ubuntu镜像 xff0c 发现只有一个lo网卡 xff0c 没有ens33 xff0c 虚拟机无法获取ip地址 xff0c samba服务器也无法正常使用 root 64 ubuntu
  • ubuntu下arm-none-eabi-gcc安装

    一 下载安装包 下载地址 xff1a https launchpad net gcc arm embedded 43 download 选择linux版本下载 xff1a gcc arm none eabi 5 4 2016q3 20160
  • 2.4G-WiFi连接路由器过程

    一 概述 WiFi的数据通信基于802 11协议进行 xff0c 无线AP在工作时会定时向空中发送beacon数据包 xff0c 基站 xff08 STA xff09 从beacon中解析出AP的名称 加密方式等信息 xff0c 从而发起连
  • STM32f103时钟树详解

    一 概述 stm32有四种时钟信号源 xff0c HSE 高速外部时钟 HSI xff08 高速内部时钟 xff09 LSE xff08 低速外部时钟 xff09 LSI xff08 低速内部时钟 xff09 HSE通常接8M晶振 xff0
  • 头文件重复包含

    一 头文件重复包含问题分析 1 问题重现 举例说明 假设在某个C 43 43 头文件 或 源文件 中 xff0c 包含了A h和B h两个头文件 xff1a span class token macro property span clas
  • Netty 学习(六)实现自定义协议通信

    目录 前言一 通信协议设计通用协议自定义协议网络协议需要具备的要素1 魔数2 协议版本号3 序列化算法4 报文类型5 长度域字段6 请求数据7 状态8 校验字段9 保留字段 二 Netty 实现自定义通信协议Netty 中编解码器分类 三
  • ABB机器人与上位机进行Socket通信的RAPID代码实现(服务端)

    文章目录 前言1 实现的功能2 建立Socket通信2 1 ABB机器人的IP地址 xff1a 2 2 SocketAccept的说明 3 服务端接发信息3 1 核心代码3 2 CurrentPos函数 4 完整代码5 实现效果 前言 本文
  • ros使用自定义消息时,编译不成功,在Cmake中报错.

    在使用自定义消息时 xff0c 按照教程添加依赖和cmakelist文件后 xff0c 保证几条Cmake语句顺序无误的情况下 xff0c 考虑msg文件夹的位置 xff0c 应在功能包的第一级目录中
  • C语言加强--韦老师公开课

    目录 1 变量与指针 摘要 xff1a 普通变量 指针变量所占的内存空间大小 xff0c 变量在内存中的分配方式 xff08 首地址要求 长度 分配长度与实际使用长度区别 需要填充字节数 全局与局部变量在内存中的位置 xff09 xff1b
  • 大小端转换(一篇文章了解所有情况下的大小端转换方法)

    总述 xff1a 字节间字节内大端低地址的数据放在高字节位域 xff1a 先从低地址对应数据字节的高bit开始分配小端低地址的数据放在低字节位域 xff1a 先从低地址对应数据字节的低bit开始分配 注释 xff1a 对于大小端的几个结论
  • C语言程序内存四区——栈区,堆区,全局区,代码区

    1 全局区 xff1a 全局区比较特殊 xff0c 里面还分成了全局变量区 xff0c 静态变量区 xff0c 常量区 全局变量区用来存放全局变量 xff0c 静态变量区用来存放带有static修饰的变量 xff08 包括静态局部变量和静态
  • Linux 用户和组

    用户和组 前言一 查看用户二 基本操作1 添加用户2 查看3 修改密码4 切换用户5 其他6 登出 前言 一个用户可以属于多个组 xff0c 并且拥有这些组的权限 一 查看用户 输入命令 cat span class token opera
  • pip 清华镜像

    pip 清华镜像 一 地址二 使用 一 地址 https pypi tuna tsinghua edu cn simple 二 使用
  • requests库将cookieJar对象转换为cookies字典

    requests库将cookieJar对象转换为cookies字典 转字典转cookieJar 使用requests获取的resposne对象 xff0c 具有cookies属性 该属性值是一个cookieJar类型 转字典 cookies
  • mybatis-generator-core插件无法下载解决办法

    mybatis generator core插件无法下载解决办法 前言一 解决办法二 插件可用 前言 maven mybatis generator core插件无法下载 一 解决办法 二 插件可用

随机推荐

  • idea 去绿色波浪线

    idea 去绿色波浪线 如图 如图
  • stop-writes-on-bgsave-error

    redis RDB持久化配置 RDB持久化 配置 stop writes on bgsave error 选项 如果 61 yes xff1a redis 会创建一个新的后台进程dump rdb 假设 xff1a 创建快照 xff08 硬盘
  • px4_simple_example和uorb机制

    px4 simple app PX4 Autopilot src exampes px4 simple app xff0c 这个程序是用c语言调用orb API和poll机制订阅和发布通讯数据 xff0c 但是这个例子并不是既有接收又有发送
  • 四旋翼无人机硬件基础

    四旋翼无人机硬件基础 材料分析无刷电机型号转速 电子调速器作用规格四轴专用电调 xff1f 电调编程 xff1f 螺旋桨机制 规格 飞行控制器原理作用四轴 字四轴十字 电池锂电池 xff1f 电池容量电池片数放电能力插头类型T插XT60JS
  • AndroidStudio NDK开发环境配置及示例

    AndroidStudio NDK开发环境配置及示例 版本说明 版本作者日期备注0 1loon2020 8 26初稿 目录 文章目录 AndroidStudio NDK开发环境配置及示例版本说明目录一 Android Studio NDK环
  • Onvif协议学习:10、获取音视频流

    Onvif协议学习 xff1a 10 获取音视频流 文章目录 Onvif协议学习 xff1a 10 获取音视频流1 原理简介2 编码流程3 VLC播放RTSP视频4 准备FFmpeg库5 示例代码 原文链接 xff1a https blog
  • (ROS)RLException: [display_mrobot_with_camera.launch] is neither a launch file等一系列错误解决办法

    前提 xff1a 运行 roslaunch mrobot description display mrobot chassis urdf launch 有误 错误1 xff1a rviz直接打不开 错误显示 xff1a RLExceptio
  • 9款好用的SSH客户端软件推荐

    9款好用的SSH客户端软件推荐 文章目录 9款好用的SSH客户端软件推荐MobaXtermXshellTermiusPuTTYSimpleRemoteZOC TerminalFinalshellJuiceSSHServerCat SSH客户
  • 几款数据库连接工具

    几款数据库连接工具 文章目录 几款数据库连接工具1 前言2 Navicat3 DBeaver4 DataGrip5 phpMyAdmin 1 前言 我目前使用sqlite3和mysql数据库比较多 xff0c 所以对数据库客户端的需求主要是
  • win10文件资源管理器右键卡死现象解决方案大全

    win10文件资源管理器右键卡死现象解决方案大全 文章目录 win10文件资源管理器右键卡死现象解决方案大全一 右键桌面卡死 xff0c 过了许久都未反应二 右键文件夹或文件卡死2 1 方案12 2 方案22 3 方案3 xff08 靠谱
  • CLion常用插件及c文件模板配置

    CLion常用插件及c文件模板配置 文章目录 CLion常用插件及c文件模板配置1 常用插件2 模板2 1 c源文件模板 xff1a xff08 使用文件模板 xff09 2 2 c头文件模板 xff1a xff08 使用文件模板 xff0
  • Windows下安装及卸载程序可用的添加和删除当前路径到环境变量的bat脚本以及如何和inno setup结合使用的实例

    文章目录 1 安装bat脚本 install bat 将当前路径添加到环境变量中 2 卸载bat脚本 uninstall bat 搜索当前路径并删除 3 inno setup添加安装和卸载时执行上述bat脚本4 安装到 C盘权限不足问题处理
  • 浏览器播放rtsp视频流:4、jsmpeg+go实现局域网下的rtsp视频流web端播放

    文章目录 1 前言2 资料准备3 兼容性及适用性说明4 jsmpeg架构5 基于以上架构的go方案可行性分析6 编译和结果展示 xff08 编译坑点 xff09 7 最后 1 前言 之前的rtsp转webrtc的方案存在如下缺陷 xff1a
  • TCP套接字编程实例(一)

    TCP套接字编程实例 xff08 一 xff09 TCP套接字编程第一部分我们先用单线程简单实现客户端的 发 和服务器的 收 话不多说 xff0c 直接上代码 1 Client部分 xff1a include include include
  • Vm虚拟机扩展Ubuntu系统磁盘空间

    Vm虚拟机扩展Ubuntu系统磁盘空间 前言 一般我们在安装虚拟机时都会选择默认的20G磁盘空间 xff0c 但是一旦需要搭建一两个交叉编译环境后 xff0c 20G的空间就无法满足了 xff0c 我就是出现了这样的情况 xff0c 所以也
  • Qt添加菜单栏和工具栏

    Qt添加菜单栏和工具栏 版本说明 版本作者时间备注0 1loon2018 10 24初稿 目录 文章目录 Qt添加菜单栏和工具栏版本说明目录一 需求与目的二 详细说明三 最后 一 需求与目的 一般常规的PC软件都会有主窗口 xff0c 主窗
  • Qt关于tabwidget的使用及注意事项

    Qt关于tabwidget的使用及注意事项 版本说明 版本作者日期备注0 1loon2018 11 12初稿 目录 文章目录 Qt关于tabwidget的使用及注意事项版本说明目录一 需求和目的二 了解QTabWIDget类及用法1 详细描
  • SLIC算法介绍

    SLIC xff08 simple linear iterativeclustering xff09 xff0c 即 简单线性迭代聚类 x1f49b 它是2010年提出的一种思想简单 实现方便的算法 xff0c 将彩色图像转化为CIELAB
  • 利用libwebsockets写ws、wss服务端和客户端

    利用libwebsockets写ws wss服务端和客户端 文章目录 利用libwebsockets写ws wss服务端和客户端服务端 xff1a 客户端官网例子坑点 服务端 xff1a server c span class token
  • 封装利用libwebsockets写出的客户端、服务端程序为客户端服务端类

    封装利用libwebsockets写出的客户端 服务端程序为客户端服务端类 文章目录 封装利用libwebsockets写出的客户端 服务端程序为客户端服务端类1 封装2 封装后写wss客户端 服务端3 测试结果4 客户端 服务端类程序 1