CentOS 编译安装Redis

news2024/9/25 21:26:33

一、编译配置hiredis.h

C++来操作redis数据库。通过hiredis接口来实现,目前只能在Linux环境使用。

  •  下载hiredis.h

  •  hiredis的下载地址为:https://github.com/redis/hiredis

  •   解压并编译hiredis

[root@localhost source_code]# pwd
/usr/local/source_code
[root@localhost source_code]# ll
总用量 5296
drwxr-xr-x. 2 root root       42 9月  18 17:32 c_demo
-rw-r--r--. 1 root root   126216 10月 10 09:42 hiredis-1.2.0.tar.gz
drwxr-xr-x. 5  500 users    8192 9月   4 15:28 jpeg-9e
-rw-r--r--. 1 root root  1046935 9月   4 15:23 jpegsrc.v9e.tar.gz
-rw-r--r--. 1 root root  4234219 8月  31 16:22 release-3.4.13.tar.gz
drwxrwxr-x. 8 root root      259 8月  31 16:33 zookeeper-release-3.4.13
[root@localhost source_code]# tar -zxvf hiredis-1.2.0.tar.gz
hiredis-1.2.0/
hiredis-1.2.0/.github/
hiredis-1.2.0/.github/release-drafter-config.yml
******
  • 执行make && make install(自动把libhiredis.so放到/usr/local/lib/中,把hiredis.h放到/usr/local/inlcude/hiredis/中)
[root@localhost source_code]# cd hiredis-1.2.0
[root@localhost hiredis-1.2.0]# make && make install
cc -std=c99 -c -O3 -fPIC   -Wall -Wextra -Werror -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers -g -ggdb  -pedantic alloc.c
cc -std=c99 -c -O3 -fPIC   -Wall -Wextra -Werror -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers -g -ggdb  -pedantic net.c
cc -std=c99 -c -O3 -fPIC   -Wall -Wextra -Werror -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers -g -ggdb  -pedantic hiredis.c
******
# 生成hredis 相关信息
mkdir -p /usr/local/include/hiredis /usr/local/include/hiredis/adapters /usr/local/lib
-- hiredis 头文件生成地址
cp -pPR hiredis.h async.h read.h sds.h alloc.h sockcompat.h /usr/local/include/hiredis
cp -pPR adapters/*.h /usr/local/include/hiredis/adapters
-- hiredis 动态库文件生成地址
cp -pPR libhiredis.so /usr/local/lib/libhiredis.so.1.1.0
cd /usr/local/lib && ln -sf libhiredis.so.1.1.0 libhiredis.so && ln -sf libhiredis.so.1.1.0 libhiredis.so.1
cp -pPR libhiredis.a /usr/local/lib
mkdir -p /usr/local/lib/pkgconfig
cp -pPR hiredis.pc /usr/local/lib/pkgconfig

在程序中包含#include <hiredis/hiredis.h>即可 

[root@localhost ~]# cd /usr/local/source_code/
[root@localhost source_code]# ll
总用量 5300
drwxr-xr-x. 2 root root       42 9月  18 17:32 c_demo
drwxrwxr-x. 6 root root     4096 10月 10 09:44 hiredis-1.2.0
-rw-r--r--. 1 root root   126216 10月 10 09:42 hiredis-1.2.0.tar.gz
drwxr-xr-x. 2 root root       50 10月 10 10:37 hiredis_demo
drwxr-xr-x. 5  500 users    8192 9月   4 15:28 jpeg-9e
-rw-r--r--. 1 root root  1046935 9月   4 15:23 jpegsrc.v9e.tar.gz
-rw-r--r--. 1 root root  4234219 8月  31 16:22 release-3.4.13.tar.gz
drwxr-xr-x. 2 root root        6 10月 10 10:58 zookeeper_demo
drwxrwxr-x. 8 root root      259 8月  31 16:33 zookeeper-release-3.4.13
[root@localhost source_code]# cd hiredis_demo/
[root@localhost hiredis_demo]# ll
总用量 16
-rwxr-xr-x. 1 root root 8608 10月 10 10:37 hiredis_demo
-rw-r--r--. 1 root root  697 10月 10 10:26 hiredis_demo.cpp
[root@localhost hiredis_demo]# cat hiredis_demo.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis/hiredis.h>

int main() {
    redisContext *c;
    redisReply *reply;

    struct timeval timeout = { 1, 500000 }; // 1.5 seconds
    c = redisConnectWithTimeout((char*)"192.168.43.80", 6379, timeout);

    if (c != NULL && c->err)
    {
        printf("Connection error: %s", c->errstr);
        redisFree(c);
        exit(1);
    }

    reply = (redisReply *)redisCommand(c, "SET %s %s", "foo", "bar");
    freeReplyObject(reply);

    reply = (redisReply *)redisCommand(c, "GET foo");

    printf("foo: %s", reply->str);
    freeReplyObject(reply);

    redisFree(c);

    return 0;
}
[root@localhost hiredis_demo]#
  • 编译代码的时候需要加链接的库及库的路径,那么编译命令如下
g++ hiredis_demo.cpp -o hiredis_demo -L/usr/local/lib/ -lhiredis 
  • 在执行的时候如果出现动态库无法加载。
    [root@localhost hiredis_demo]# ./hiredis_demo
    ./hiredis_demo: error while loading shared libraries: libhiredis.so.1.1.0: cannot open shared object file: No such file or directory

    那么需要进行如下配置。

  • 在 /etc/ld.so.conf.d/ 目录下新建文件 usr-libs.conf ,内容是: /usr/local/lib
vim /etc/ld.so.conf.d/usr-libs.conf
  • 然后使用命令 /sbin/ldconfig 更新一下配置即可。
sbin/ldconfig

二、hiredis.h核心方法

第一步:查看hiredis.h 头文件定义:

[root@localhost lib]# cd /usr/local/include/hiredis/
[root@localhost hiredis]# ll
总用量 56
drwxr-xr-x. 2 root root   197 10月 10 09:44 adapters
-rw-rw-r--. 1 root root  3130 7月  12 15:31 alloc.h
-rw-rw-r--. 1 root root  6288 7月  12 15:31 async.h
-rw-rw-r--. 1 root root 14319 7月  12 15:31 hiredis.h
-rw-rw-r--. 1 root root  4918 7月  12 15:31 read.h
-rw-rw-r--. 1 root root  9238 7月  12 15:31 sds.h
-rw-rw-r--. 1 root root  4409 7月  12 15:31 sockcompat.h
[root@localhost hiredis]# cat hiredis.h

 

核心方法定义

1.建立链接:redisConnect

redisContext* redisConnect(const char *ip, int port)

 函数说明:

  • 函数用来连接redis数据库, 两个参数分别是redis数据库的ip和端口,端口号一般为6379
  • 该函数redisConnect用于创建所谓的redisContext。上下文是Hiredis保持连接状态的地方。
  • 当连接处于错误状态时,该redisContext 结构具有一个err非零的整数字段该字段errstr将包含带有错误描述的字符串
  • 使用尝试连接到Redis后redisConnect,应检查该err字段以查看建立连接是否成功

 还提供了一个函数,供连接超时限定,即

redisContext* redisConnectWithTimeout(const char *ip, 
											int port, timeval tv)。

 Demo 示例:

 c = redisConnectWithTimeout((char*)"192.168.43.80", 6379, timeout);

    if (c != NULL && c->err)
    {
        printf("Connection error: %s", c->errstr);
        redisFree(c);
        exit(1);
    }

解释说明:

当函数调用不成功时,取决于函数NULL还是REDIS_ERR返回。err上下文中的字段将为非零值,并设置为以下常量之一:

  • REDIS_ERR_IO:创建连接,尝试写入套接字或从套接字读取时发生I /O错误。如果您包含errno.h在应用程序中,则可以使用全局errno变量来找出问题所在。
  • REDIS_ERR_EOF:服务器关闭了连接,导致读取为空。
  • REDIS_ERR_PROTOCOL:解析协议时出错。
  • REDIS_ERR_OTHER:其他任何错误。当前,仅在无法解析要连接的指定主机名时使用。

在每种情况下,errstr上下文中的字段都将设置为包含错误的字符串表示形式。
 

2. 执行redis命令:redisCommand

void *redisCommand(redisContext *c, const char *format...)

函数说明:

  • 该函数用于执行redis数据库中的命令,第一个参数为连接数据库返回的redisContext,剩下的参数为变参。 

  • 此函数的返回值为void*,但是一般会强制转换为redisReply类型,以便做进一步的处理。

 const char *format... 动态参数关联方法定义:

void * redisCommandArgv(redisContext * c,int argc,
						const  char ** argv,const  size_t * argvlen);

 函数说明:

  • 它需要参数的数量,argc字符串数组argv和参数的长度argvlen。
  • 为了方便起见,argvlen可以将设置为NULL,并且函数将strlen(3)在每个参数上使用以确定其长度。
  • 显然,当任何一个参数需要二进制安全时,argvlen都应提供整个长度数组。
  • 返回值的语义与相同redisCommand。

 Demo 示例:

 reply = (redisReply *)redisCommand(c, "SET %s %s", "foo", "bar");

3.释放redisCommand

void freeReplyObject(void *reply)

函数说明:

  • 释放redisCommand执行后返回的的redisReply所占用的内存。
  • redisCommand成功执行命令后,的返回值将保留答复。
  • 发生错误时,返回值为NULL并且err将设置上下文中的字段。返回错误后,上下文context将无法重用,您应该建立一个新的连接。

Demo 示例:

 freeReplyObject(reply);

4.断开连接:redisFree

void redisFree(redisContext *c)

函数说明:

  • 此函数立即关闭套接字,然后释放在创建上下文时完成的分配。

三、Hiredis 基于C++ 封装

redis_handler.h

#ifndef __REDIS_HANDLER_H__
#define __REDIS_HANDLER_H__
 
#include <hiredis/hiredis.h>
#include <string>

using namespace std;

enum
{
    M_REDIS_OK = 0, //执行成功
    M_CONNECT_FAIL = -1, //连接redis失败
    M_CONTEXT_ERROR = -2, //RedisContext返回错误
    M_REPLY_ERROR = -3, //redisReply错误
    M_EXE_COMMAND_ERROR = -4 //redis命令执行错误
};


class RedisHandler
{
public:
    RedisHandler();
    ~RedisHandler();
    int connect(const string &addr, int port, const string &pwd = ""); //连接redis数据库:addr:IP地址,port:端口号,pwd:密码(默认为空)
    int disConnect(); //断开连接

    int setValue(const string &key, const string &value); //添加或修改键值对,成功返回0,失败<0
    int getValue(const string &key, string &value); //获取键对应的值,成功返回0,失败<0
    int delKey(const string &key); //删除键,成功返回影响的行数,失败<0
    int printAll(); //打印所有的键值对

    string getErrorMsg(); //获取错误信息
private:
    string m_addr; //IP地址
    int m_port; //端口号
    string m_pwd; //密码
    redisContext* pm_rct; //redis结构体
    redisReply* pm_rr; //返回结构体
    string error_msg; //错误信息

    int connectAuth(const string &pwd); //使用密码登录
    int handleReply(void* value = NULL, redisReply ***array = NULL); //处理返回的结果
};


#endif

redis_handler.cpp

#include "redis_handler.h"
#include <string>
#include <cstring>
#include <iostream>
using namespace std;

RedisHandler::RedisHandler()
{
    m_addr = "";
    m_port = 0;
    m_pwd = "";
    pm_rct = NULL;
    pm_rr = NULL;
    error_msg = "";
}

RedisHandler::~RedisHandler()
{
    disConnect();
    pm_rct = NULL;
    pm_rr = NULL;
}

/*
连接redis数据库
addr: 地址,port:端口号,pwd:密码
成功返回M_REDIS_OK,失败返回M_CONNECT_FAIL
*/
int RedisHandler::connect(const string &addr = "127.0.0.1", int port = 6379, const string &pwd) {
    m_addr = addr;
    m_port = port;
    m_pwd = pwd;

    pm_rct = redisConnect(m_addr.c_str(), m_port);

    if (pm_rct->err)
    {
        error_msg = pm_rct->errstr;
        return M_CONNECT_FAIL;
    }

    if (!m_pwd.empty())
    {
        return connectAuth(m_pwd);
    }

    return M_REDIS_OK;
}

/*
断开redis连接
*/
int RedisHandler::disConnect()
{
    redisFree(pm_rct);
    freeReplyObject(pm_rr);
}

/*
添加或插入键值对
key:键,value:值
成功返回M_REDIS_OK,失败返回<0
*/
int RedisHandler::setValue(const string &key, const string &value)
{
    string cmd = "set " + key + " " + value;

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    return handleReply();
}

/*
获取键对应的值
key:键,value:值引用
成功返回M_REDIS_OK,失败返回<0
*/
int RedisHandler::getValue(const string &key, string &value)
{
    string cmd = "get " + key;

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    int ret = handleReply(&value);
}

/*
删除键
key:键
成功返回影响的行数(可能为0),失败返回<0
*/
int RedisHandler::delKey(const string &key)
{
    string cmd = "del " + key;

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    int rows = 0;
    int ret = handleReply(&rows);
    if (ret == M_REDIS_OK)
        return rows;
    else
        return ret;
}

/*
打印所有键值对到屏幕上
*/
int RedisHandler::printAll()
{
    string cmd = "keys *";

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    int len ;
    redisReply **array;
    int ret = handleReply(&len, &array);
    if (ret == M_REDIS_OK)
    {
        for (int i = 0; i < len; i++)
            cout << string(array[i]->str) << endl;
    }
    else
        return 0;
}

/*
返回错误信息
*/
string RedisHandler::getErrorMsg()
{
    return error_msg;
}

/*
使用密码登录
psw:登录密码
成功返回M_REDIS_OK,失败返回<0
*/
int RedisHandler::connectAuth(const string &psw)
{
    string cmd = "auth " + psw;

    pm_rr = (redisReply*)redisCommand(pm_rct, cmd.c_str());

    return handleReply();
}

/*
处理redis返回的信息
value:数据指针,用于保存redis返回的基本类型(value指针指向该数据)
array:数组指针,用于保存redis返回的数组
成功返回M_REDIS_OK,失败返回<0
*/
int RedisHandler::handleReply(void* value, redisReply*** array)
{
    if (pm_rct->err)
    {
        error_msg = pm_rct->errstr;
        return M_CONTEXT_ERROR;
    }

    if (pm_rr == NULL)
    {
        error_msg = "auth redisReply is NULL";
        return M_REPLY_ERROR;
    }

    switch (pm_rr->type)
    {
    case REDIS_REPLY_ERROR:
        error_msg = pm_rr->str;
        return M_EXE_COMMAND_ERROR;
    case REDIS_REPLY_STATUS:
        if (!strcmp(pm_rr->str, "OK"))
            return M_REDIS_OK;
        else
        {
            error_msg = pm_rr->str;
            return M_EXE_COMMAND_ERROR;
        }
    case REDIS_REPLY_INTEGER:
        *(int*)value = pm_rr->integer;
        return M_REDIS_OK;
    case REDIS_REPLY_STRING:
        *(string*)value = pm_rr->str;
        return M_REDIS_OK;
    case REDIS_REPLY_NIL:
        *(string*)value = "";
        return M_REDIS_OK;
    case REDIS_REPLY_ARRAY:
        *(int*)value = pm_rr->elements;
        *array = pm_rr->element;
        return M_REDIS_OK;
    default:
        error_msg = "unknow reply type";
        return M_EXE_COMMAND_ERROR;
    }
}

Demo 示例:

redis_main.cpp

#include <iostream>
#include <string>
#include "redis_handler.h"
using namespace std;

int main()
{
    RedisHandler* rh = new RedisHandler();
    int ret;

    //连接测试
    cout << "错误测试: " << "地址错误" << endl;
    ret = rh->connect("34.15.14.15", 6379, "linesum");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;

    cout << "错误测试: " << "端口错误" << endl;
    ret = rh->connect("127.0.0.1", 1234, "linesum");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;

    cout << "错误测试: " << "密码错误" << endl;
    ret = rh->connect("127.0.0.1", 6479, "linsum");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;


    ret = rh->connect("127.0.0.1", 6479, "linesum");
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }


    //set测试
    cout << "错误测试: " << "set不带value参数" << endl;
    ret = rh->setValue("key11", "");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;


    ret = rh->setValue("key11", "value11");
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }

    ret = rh->setValue("key22", "value22");
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }


    //get测试
    string str;
    cout << "错误测试: " << "get不带key参数" << endl;
    ret = rh->getValue("key1111", str);
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;

    ret = rh->getValue("key11", str);
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }
    else
        cout << "value : " << str << endl;



    //print测试
    ret = rh->printAll();
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }


    //del测试
    cout << "错误测试: " << "删除不存在的key" << endl;
    ret = rh->delKey("key1111");
    if (ret != M_REDIS_OK)
        cout << "redis error: " << rh->getErrorMsg() << endl;


    ret = rh->delKey("key11");
    if (ret != M_REDIS_OK)
    {
        cout << "redis error: " << rh->getErrorMsg() << endl;
        return ret;
    }

    delete rh;

    return 0;
}

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

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

相关文章

Django实战项目-学习任务系统-用户注册

接着上期代码框架&#xff0c;开发第2个功能&#xff0c;用户注册&#xff0c;在原有用户模型基础上&#xff0c;增加一个学生用户属性表&#xff0c;用来关联学生用户的各种属性值&#xff0c;这个属性表是参考网络小说里系统属性值设计的&#xff0c;方便直观了解用户的能力高…

华为OD机试 - 组成最大数(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#xff09;》…

香港专用服务器拥有良好的国际网络连接

香港服务器在多个领域有着广泛的应用。无论是电子商务、金融交易、游戏娱乐还是社交媒体等&#xff0c;香港服务器都能够提供高效稳定的服务。对于跨境电商来说&#xff0c;搭建香港服务器可以更好地满足亚洲用户的购物需求&#xff1b;对于金融机构来说&#xff0c;香港服务器…

安科瑞ARB5系列弧光保护装置,智能电弧光保护,保障用电安全

安科瑞虞佳豪壹捌柒陆壹伍玖玖零玖叁 什么是弧光 电弧是放电过程中发生的一种现象&#xff0c;当两点之间的电压超过其工频绝缘强度极限时就会发生。当适当的条件出现时&#xff0c;一个携带着电流的等离子产生&#xff0c;直到电源侧的保护设备断开才会消失。空气在通常条件…

31 数据分析(中)numpy介绍

文章目录 工具excelTableauPower Queryjupytermatplotlibnumpy安装导入包快速掌握&#xff08;bushi&#xff09;array和list的相互转化 np的range多维数组的属性array的改变形状array升降维度array内元素的类型数和array的运算array之间的加减法认识轴切片条件与逻辑修改值app…

大规模语言模型高效调参--混合高效微调系列(MAM Adapter,UniPELT)

近年来提出了多种参数高效的迁移学习方法&#xff0c; 这些方法仅微调少量(额外) 参数即可获得强大的性能。虽 然有效&#xff0c; 但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。 Adapter 、Prefix Tuning、 LoRA (在结构上和公式上)看起来都不太一样…

SpringCloud小项目——订单积分商城 使用Nacos、Open Feign、Gateway、Sentinel技术栈

目录 引出小项目要求创建极简数据库表订单表&#xff0c;订单明细表商品表积分表 相关微服务积分微服务产品微服务订单微服务调用积分和订单微服务 网关微服务登陆认证通过网关实现对外提供接口API走网关功能 sentinel相关使用Sentinel限流&#xff0c;流量整形Sentinel降级服务…

SparseBEV:High-Performance Sparse 3D Object Detection from Multi-Camera Videos

参考代码&#xff1a;SparseBEV 动机与主要贡献&#xff1a; BEV感知可以按照是否显式构建BEV特征进行划分&#xff0c;显式构建BEV特征的方法需要额外计算量用于特征构建&#xff0c;而类似query方案的方法则不需要这样做。比较两种类型的方法&#xff0c;前者需要更多计算资…

微服务 BFF 架构设计

在现代软件开发中&#xff0c;由于程序、团队、数据规模太大&#xff0c;需要把企业的业务能力进行复用&#xff0c;将领域服务剥离&#xff0c;提供通用能力&#xff0c;避免重复建设和代码&#xff1b;另外服务功能的弹性能力不一样&#xff0c;比如定时任务、数据同步明确的…

mysql面试题39:什么是触发器?触发器的使用场景有哪些?MySQL中都有哪些触发器?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:什么是触发器?触发器的使用场景有哪些? 触发器(Trigger)是数据库中一种特殊类型的存储过程,它在特定的数据库事件(例如插入、更新、删除操作…

软考高级架构师下篇-18大数据架构理论设计与实践

目录 1. 引言2. 传统数据处理系统的问题1.传统数据库的数据过载问题2.大数据的特点3.大数据利用过程4.大数据处理系统架构分析3.典型的大数据架构1. Lambda架构2.Kappa架构3. Lambda架构与Kappa架构的对比4.大数据架构的实践1.大规模视频网络2.广告平台3.公司智能决策大数据系统…

Redis-集群

Redis-集群 主从复制和哨兵只能在主节点进行写数据&#xff0c;从节点读取数据&#xff0c;因此本质上&#xff0c;是进行了读写的分离&#xff0c;每个节点都保存了所有的数据&#xff0c;并不能实现一个很好的分布式效果。 1.哈希求余算法 假设有N台主机&#xff0c;对每台…

对比纯软开与嵌入式硬件开发谁更好呢?

对比纯软开与嵌入式硬件开发谁更好呢&#xff1f; 你的纠结和犹豫是理解的&#xff0c;职业选择确实是一个重要的决策。我明白你在嵌入式和软件开发之间犹豫不决的原因。让我给你提供一些建议&#xff0c;帮助你做出更明智的决定。最近很多小伙伴找我&#xff0c;说想要一些嵌入…

日期时间参数,格式配置(SpringBoot)

介绍 在SpringBoot项目中&#xff0c;接口中的日期和时间类型的参数&#xff0c;配置格式。 日期格式 接口中常用的日期时间格式有两种&#xff1a; 字符串&#xff08;比如&#xff1a;yyyy-MM-dd HH:mm:ss&#xff09;时间戳&#xff08;比如&#xff1a;1696839876955&a…

【云计算网络安全】僵尸网络详解:工作原理、控制和保护方法

文章目录 一、什么是僵尸网络&#xff1f;二、僵尸网络因为什么原因而诞生&#xff1f;三、僵尸网络主要用途四、僵尸网络如何工作&#xff1f;五、如何控制僵尸网络&#xff1f;5.1 客户端/服务器僵尸网络模型5.1.1 星形网络拓扑5.1.2 多服务器网络拓扑5.1.3 分层网络拓扑 5.2…

Maven依赖解决

记一次Maven依赖冲突解决 以zookeeper为例 一、问题描述 当下载zookeeper的2.2.6.RELEASE时&#xff0c;报错 Could not find artifact org.springframework.cloud:spring-cloud-starter-zookeeper-discovery:pom:2.2.6.RELEASE in central (https://repo.maven.apache.org/ma…

3D包容盒子

原理简述 包围体&#xff08;包容盒&#xff09;是一个简单的几何空间&#xff0c;里面包含着复杂形状的物体。为物体添加包围体的目的是快速的进行碰撞检测或者进行精确的碰撞检测之前进行过滤&#xff08;即当包围体碰撞&#xff0c;才进行精确碰撞检测和处理&#xff09;。包…

Flutter中的StreamBuilder和FutureBuilder有什么区别

流行的跨平台框架 Flutter 为开发人员提供了两个强大的小部件来处理异步操作&#xff1a;StreamBuilder 和 FutureBuilder。尽管它们有相似之处&#xff0c;但了解它们的不同之处&#xff0c;以便为您的特定用例选择合适的一个是至关重要的。在这篇博文中&#xff0c;我们将深入…

matlab相机标定实验

实验原理 1. 相机标定坐标系 相机的参数对目标的识别、定位精度有很大的影响&#xff0c;相机标定就是为了求出相机的内外参数。标定中有3个不同层次的坐标系&#xff1a;世界坐标系、相机坐标系和图像坐标系&#xff08;图像物理坐标系和图像像素坐标系&#xff09;。世界坐…

HTML-注册页面

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>注册页面</title> </head> <body><from action"#" method"get"><table border"1" align&q…