【网络编程】协议定制+Json序列化与反序列化

2023-11-17


需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网,轻量型云服务器低至112元/年,新用户首次下单享超低折扣。


 目录

一、序列化与反序列化的概念

二、自定义协议设计一个网络计算器

2.1TCP协议,如何保证接收方收到了完整的报文呢?

2.2自定义协议的实现

2.3自定义协议在客户端与服务器中的实现

三、使用Json进行序列化和反序列化

3.1jsoncpp库的安装

3.2改造自定义协议

3.3自定义协议的命名区分


网络版计算器代码可参考博主gitee。

一、序列化与反序列化的概念

        序列化是指将对象转换为字节流或其他可存储或传输的格式,以便将其存储在文件中或通过网络发送到另一个系统。反序列化是指将序列化的数据重新转换为对象。在序列化和反序列化过程中,对象的状态信息被保存和恢复,以保证数据的完整性和正确性。在分布式系统中,序列化和反序列化是实现远程方法调用和消息传递的重要技术。

        例如微信发送一条消息,会将头像、昵称、消息内容、发送时间等“结构化”数据进行序列化,形成一个字节流报文,通过网络将该报文发送给接收方,接收方进行反序列化将报文重新拆解为头像、昵称、消息内容、发送时间等“结构化”数据。

二、自定义协议设计一个网络计算器

2.1TCP协议,如何保证接收方收到了完整的报文呢?

1、我们调用的所有发送/接收函数,并不是直接从网络中发送/接收数据,应用层调用的发送/接收函数,本质是一个拷贝函数。
例如客户端发送数据时,应用层调用发送函数将会把应用层的发送缓冲区数据拷贝至传输层的发送缓冲区。传输层自主决定何时将发送缓冲区的数据发送至网络里,再通过网络发送至服务器的接收缓冲区中,所以TCP协议是一种传输控制协议。

2、TCP协议的通信双方的发送缓冲区和接收缓冲区互不干扰,可以双向同时进行通信。TCP是一种全双工的通信协议。

3、如果TCP服务器的读取速度跟不上客户端的发送速度,将会导致服务器接收缓冲区积攒大量的报文,这些报文数据可是一连串的粘连在一起的,如何一条一条的将完整的报文提取出来呢?使用协议!协议设计方式:

  • 定长(例如规定该报文定长为1024字节)
  • 特殊符号(在报文和报文之间增加特殊符号)
  • 自描述方式(自己设计协议)

本文代码协议设计如下图所示:使用该协议设计一个网络计算器。

        如果是UDP协议,UDP客户端,发送报文时只需创建请求,对请求进行序列化后即可发送;接收报文时只需将接收的数据进行反序列化即可。无需进行协议内容的添加与解析。这是因为UDP每次发送与接收都是以数据报的形式,数据是完整的,不像TCP是面向字节流,需要使用相关的协议进行界定报文边界。

2.2自定义协议的实现

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
enum
{
    OK=0,
    DIV_ZERO_ERR,
    MOD_ZERO_ERR,
    OP_ZERO_ERR,
};
#define SEP " "
#define SEP_LEN strlen(SEP)//不能使用sizeof,用sizeof会统计到'\0'
#define LINE_SEP "\r\n"
#define LINE_SEP_LINE strlen(LINE_SEP)
//"_exitcode result" -> "content_len"\r\n"_exitcode result"\r\n
//"_x _op _y" -> "content_len"\r\n"_x _op _y"\r\n
std::string enLength(const std::string& text)//text:_x _op _y。添加协议规则,用于构建一个完整的报文(类似"打包")
{
    std::string send_string=std::to_string(text.size());//计算有效载荷的长度"_x _op _y"
    send_string+=LINE_SEP;
    send_string+=text;
    send_string+=LINE_SEP;
    return send_string;
}
//_exitcode result
bool deLength(const std::string& package,std::string* text)//获取报文中的有效载荷(类似"解包")
{
    auto pos=package.find(LINE_SEP);
    if(pos==std::string::npos){return false;}
    int textLen=std::stoi(package.substr(0,pos));//计算有效载荷的长度
    *text=package.substr(pos+LINE_SEP_LINE,textLen);
    return true;
}
class Request//请求类
{
public:
    Request(int x,int y,char op)
        :_x(x)
        ,_y(y)
        ,_op(op)
    {}
    Request()
        :_x(0)
        ,_y(0)
        ,_op(0)
    {}
    bool serialize(std::string* out)//序列化,将成员变量转字符串
    {
        //结构化->"_x _op _y"
        *out="";//清空string对象
        std::string x_tostring=std::to_string(_x);
        std::string y_tostring=std::to_string(_y);
        *out=x_tostring+SEP+_op+SEP+y_tostring;//_x _op _y
        return true;
    }
    bool deserialize(const std::string& in)//反序列化
    {
        //"_x _op _y"->结构化
        auto leftSpace=in.find(SEP);//左边的空格
        auto rightSpace=in.rfind(SEP);//右边的空格
        if(leftSpace==std::string::npos||rightSpace==std::string::npos){return false;}
        if(leftSpace==rightSpace){return false;} 
        //子串提取
        std::string x_tostring=in.substr(0,leftSpace);
        if(rightSpace-(leftSpace+SEP_LEN)!=1){return false;}//表示操作符一定只占1位
        _op=in.substr(leftSpace+SEP_LEN,rightSpace-(leftSpace+SEP_LEN))[0];
        std::string y_tostring=in.substr(rightSpace+SEP_LEN);
        //对x,y进行转换
        _x=std::stoi(x_tostring); 
        _y=std::stoi(y_tostring);
        return true;
    }
public:
    //_x _op _y
    int _x;//左操作数
    int _y;//右操作数
    char _op;//操作符
};

class Response//响应类
{
public:
    Response()
        :_exitCode(0)
        ,_result(0)
    {}
    Response(int exitCode,int result)
        :_exitCode(exitCode)
        ,_result(result)
    {}
    bool serialize(std::string* out)//序列化,将成员变量转string对象
    {
        *out="";//清空string对象
        std::string outString=std::to_string(_exitCode)+SEP+std::to_string(_result);
        *out=outString;
        return true; 
    }
    bool deserialize(const std::string& in)//反序列化
    {
        auto space=in.find(SEP);//找空格
        if(space==std::string::npos){return false;}
        std::string exitString=in.substr(0,space);
        std::string resString=in.substr(space+SEP_LEN);
        if(exitString.empty()||resString.empty()){return false;}//一个字符串为空就false
        _exitCode=std::stoi(exitString);
        _result=std::stoi(resString);
        return true;
    }
public:
    int _exitCode;//0表示计算成功,非零代表除零等错误
    int _result;//运算结果
};

bool recvPackage(int sock,std::string& inbuffer,std::string* text)//服务器/客户端读取报文
{
    //将缓冲区数据拆分成一个个报文"content_len"\r\n"_x _op _y"\r\n
    char buffer[1024];
    while(1)
    {
        ssize_t n=recv(sock,buffer,sizeof(buffer)-1,0);//阻塞式读取,等价于read接口
        if(n>0)
        {
            buffer[n]=0;//字符串末尾添加'\0'
            inbuffer+=buffer;
            //拆分成一个个报文
            auto pos=inbuffer.find(LINE_SEP);//找\r\n的起始位置
            if(pos==std::string::npos)//没找到说明暂时还没找到\r\n分隔符,跳过本次循环,等待下次读取
            {
                continue;
            }
            std::string textLenString=inbuffer.substr(0,pos);
            int textLen=std::stoi(textLenString);//拿出有效载荷的长度
            int totalLen=textLenString.size()+2*LINE_SEP_LINE+textLen;//单个报文总长度
            if(inbuffer.size()<totalLen)//说明缓冲区长度还不到一个报文大小,需要跳过本次循环继续读取
            {
                continue;
            }
            std::cout<<"截取报文前inbuffer中的内容:\n"<<inbuffer<<std::endl;
            //走到这里,一定有一个完整的报文
            *text=inbuffer.substr(0,totalLen);//取出一个报文
            inbuffer.erase(0,totalLen);//删掉缓冲区中刚刚被提取走的报文数据
            std::cout<<"截取报文后inbuffer中的内容:\n"<<inbuffer<<std::endl;
            break;
        }
        else
        {
            return false;
        }
    }
    return true;
}

代码解释:

本协议设计了一个Request请求类和一个Response响应类,请求类存储计算器的操作数和操作符,响应类存储计算结果和退出码。这两个类中各自实现了对有效载荷的序列化与反序列化的接口。

enLength用于给有效载荷添加报头,即自定义协议的规则。deLength则用于解析收到的报文,剔除报文中的协议报头,提取出其中的有效载荷。协议是明确缓冲区中报文与报文之间边界的一种特殊格式,而enLength和deLength用于添加报头和去掉报头

2.3自定义协议在客户端与服务器中的实现

三、使用Json进行序列化和反序列化

3.1jsoncpp库的安装

        从上方代码可以看到,使用string对象手动进行序列化与反序列化非常麻烦。可以使用Json进行序列化与反序列化操作。

        Json(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于Web应用程序中的数据传输。它是一种基于文本的格式,易于读写和解析。Json格式的数据可以被多种编程语言支持,包括JavaScript、Python、Java、C#、C++等。Json数据由键值对组成,使用大括号表示对象,使用方括号表示数组。

        C++使用Json需要包含Jsoncpp库,yum安装Jsoncpp库指令:先执行第二句,如果报错再执行第一句!

sudo mv /var/lib/rpm/__db.00* /tmp/&&yum clean all
sudo yum install -y jsoncpp-devel

3.2改造自定义协议

makefile:使用jsoncpp库记得在编译时加上-ljsoncpp

cc=g++#将cc变量设置为g++编译器
LD=#-DMYSELF
.PHONY:all
all:calClient calServer

calClient:calClient.cc
	$(cc) -o $@ $^ -std=c++11 -ljsoncpp ${LD}
calServer:calServer.cc
	$(cc) -o $@ $^ -std=c++11 -ljsoncpp ${LD}
	
.PHONY:clean
clean:
	rm -f calClient calServer

改造的协议: 

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <jsoncpp/json/json.h>
#include <sys/types.h>
#include <sys/socket.h>
enum
{
    OK=0,
    DIV_ZERO_ERR,
    MOD_ZERO_ERR,
    OP_ZERO_ERR,
};
#define SEP " "
#define SEP_LEN strlen(SEP)//不能使用sizeof,用sizeof会统计到'\0'
#define LINE_SEP "\r\n"
#define LINE_SEP_LINE strlen(LINE_SEP)
//"_exitcode result" -> "content_len"\r\n"_exitcode result"\r\n
//"_x _op _y" -> "content_len"\r\n"_x _op _y"\r\n
std::string enLength(const std::string& text)//text:_x _op _y。添加协议规则,用于构建一个完整的报文(类似"打包")
{
    std::string send_string=std::to_string(text.size());//计算有效载荷的长度"_x _op _y"
    send_string+=LINE_SEP;
    send_string+=text;
    send_string+=LINE_SEP;
    return send_string;
}
//_exitcode result
bool deLength(const std::string& package,std::string* text)//获取报文中的有效载荷(类似"解包")
{
    auto pos=package.find(LINE_SEP);
    if(pos==std::string::npos){return false;}
    int textLen=std::stoi(package.substr(0,pos));//计算有效载荷的长度
    *text=package.substr(pos+LINE_SEP_LINE,textLen);
    return true;
}
class Request//请求类
{
public:
    Request(int x,int y,char op)
        :_x(x)
        ,_y(y)
        ,_op(op)
    {}
    Request()
        :_x(0)
        ,_y(0)
        ,_op(0)
    {}
    bool serialize(std::string* out)//序列化,将成员变量转字符串
    {
#ifdef MYSELF
        //结构化->"_x _op _y"
        *out="";//清空string对象
        std::string x_tostring=std::to_string(_x);
        std::string y_tostring=std::to_string(_y);
        *out=x_tostring+SEP+_op+SEP+y_tostring;//_x _op _y
#else
        //Json序列化
        Json::Value root;//Json::Value万能对象,可接收任何对象
        root["first"]=_x;//自动将_x转换为字符串
        root["second"]=_y;
        root["oper"]=_op;
        //序列化
        Json::FastWriter writer;//Json::StyledWriter write;等价
        *out=writer.write(root);//将root进行序列化,返回值为string对象,接收即可
#endif
        return true;
    }
    bool deserialize(const std::string& in)//反序列化
    {
#ifdef MYSELF
        //"_x _op _y"->结构化
        auto leftSpace=in.find(SEP);//左边的空格
        auto rightSpace=in.rfind(SEP);//右边的空格
        if(leftSpace==std::string::npos||rightSpace==std::string::npos){return false;}
        if(leftSpace==rightSpace){return false;} 
        //子串提取
        std::string x_tostring=in.substr(0,leftSpace);
        if(rightSpace-(leftSpace+SEP_LEN)!=1){return false;}//表示操作符一定只占1位
        _op=in.substr(leftSpace+SEP_LEN,rightSpace-(leftSpace+SEP_LEN))[0];
        std::string y_tostring=in.substr(rightSpace+SEP_LEN);
        //对x,y进行转换
        _x=std::stoi(x_tostring); 
        _y=std::stoi(y_tostring);
#else
        //Json反序列化
        Json::Value root;//Json::Value万能对象,可接收任何对象
        Json::Reader reader;
        reader.parse(in,root);//第一个参数:解析哪个流;第二个参数:将解析的数据存放到对象中
        //反序列化
        _x=root["first"].asInt();//默认是字符串,转换为整型
        _y=root["second"].asInt();
        _op=root["oper"].asInt();//转换为整型,整型可以给char类型。
#endif
        return true;
    }
public:
    //_x _op _y
    int _x;//左操作数
    int _y;//右操作数
    char _op;//操作符
};

class Response//响应类
{
public:
    Response()
        :_exitCode(0)
        ,_result(0)
    {}
    Response(int exitCode,int result)
        :_exitCode(exitCode)
        ,_result(result)
    {}
    bool serialize(std::string* out)//序列化,将成员变量转string对象
    {
#ifdef MYSELF
        *out="";//清空string对象
        std::string outString=std::to_string(_exitCode)+SEP+std::to_string(_result);
        *out=outString;
#else
        //Json序列化
        Json::Value root;//Json::Value万能对象,可接收任何对象
        root["exitCode"]=_exitCode;//自动将_exitCode转换为字符串
        root["result"]=_result;
        //序列化
        Json::FastWriter writer;//Json::StyledWriter write;等价
        *out=writer.write(root);//将root进行序列化,返回值为string对象,接收即可
#endif
        return true; 
    }
    bool deserialize(const std::string& in)//反序列化
    {
#ifdef MYSELF
        auto space=in.find(SEP);//找空格
        if(space==std::string::npos){return false;}
        std::string exitString=in.substr(0,space);
        std::string resString=in.substr(space+SEP_LEN);
        if(exitString.empty()||resString.empty()){return false;}//一个字符串为空就false
        _exitCode=std::stoi(exitString);
        _result=std::stoi(resString);
#else
        //Json反序列化
        Json::Value root;//Json::Value万能对象,可接收任何对象
        Json::Reader reader;
        reader.parse(in,root);//第一个参数:解析哪个流;第二个参数:将解析的数据存放到对象中
        //反序列化
        _exitCode=root["exitCode"].asInt();//默认是字符串,转换为整型
        _result=root["result"].asInt();
#endif
        return true;
    }
public:
    int _exitCode;//0表示计算成功,非零代表除零等错误
    int _result;//运算结果
};

bool recvPackage(int sock,std::string& inbuffer,std::string* text)//服务器/客户端读取报文
{
    //将缓冲区数据拆分成一个个报文"content_len"\r\n"_x _op _y"\r\n
    char buffer[1024];
    while(1)
    {
        ssize_t n=recv(sock,buffer,sizeof(buffer)-1,0);//阻塞式读取,等价于read接口
        if(n>0)
        {
            buffer[n]=0;//字符串末尾添加'\0'
            inbuffer+=buffer;
            //拆分成一个个报文
            auto pos=inbuffer.find(LINE_SEP);//找\r\n的起始位置
            if(pos==std::string::npos)//没找到说明暂时还没找到\r\n分隔符,跳过本次循环,等待下次读取
            {
                continue;
            }
            std::string textLenString=inbuffer.substr(0,pos);
            int textLen=std::stoi(textLenString);//拿出有效载荷的长度
            int totalLen=textLenString.size()+2*LINE_SEP_LINE+textLen;//单个报文总长度
            if(inbuffer.size()<totalLen)//说明缓冲区长度还不到一个报文大小,需要跳过本次循环继续读取
            {
                continue;
            }
            std::cout<<"截取报文前inbuffer中的内容:\n"<<inbuffer<<std::endl;
            //走到这里,一定有一个完整的报文
            *text=inbuffer.substr(0,totalLen);//取出一个报文
            inbuffer.erase(0,totalLen);//删掉缓冲区中刚刚被提取走的报文数据
            std::cout<<"截取报文后inbuffer中的内容:\n"<<inbuffer<<std::endl;
            break;
        }
        else
        {
            return false;
        }
    }
    return true;
}
bool recvPackageAll(int sock,std::string& inbuffer,std::vector<std::string>* out)
{
    std::string line; 
    while(recvPackage(sock,inbuffer,&line))
    {
        out->push_back(line);
    }
}

3.3自定义协议的命名区分

        未来在一套系统中可以自定义多种协议,为了区分不同的自定义协议,可以参照如下格式设计协议的格式:

当然前人已经设计好了常见的网络协议,例如http/https。

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

【网络编程】协议定制+Json序列化与反序列化 的相关文章

  • 在 ASP.NET Core 2.0 Web Api 中返回“原始”json

    AFAIK 在 ASP NET Core Web Api 中返回数据的标准方法是使用IActionResult并提供例如一个OkObject结果 这对于对象来说效果很好 但是如果我以某种方式获得了一个 JSON 字符串 并且我只想将该 JS
  • Rails 3.2:用 json 序列化中的空字符串替换 null 值

    我正在使用 Rails 3 2序列化 http www simonecarletti com blog 2010 04 inside ruby on rails serializing ruby objects with json 将 ru
  • 从 php 到 JavaScript 的数组

    我正在尝试使用 json 将数组列表从 php 传输到 javascript 但它不起作用 JS ajax url getProfilePhotos php type post post or get method data if you
  • json_encode 返回 NULL?

    由于某种原因 项目 描述 返回NULL使用以下代码 这是我的数据库的架构 CREATE TABLE staff id int 11 NOT NULL AUTO INCREMENT name longtext COLL
  • 使用 Newtonsoft.Json.NET 搜索 JSON 根对象的正确 JsonPath 表达式是什么?

    大多数例子涉及Stefan G ssner 的书店示例 http goessner net articles JsonPath index html e3 但是我正在努力为简单对象 无数组 定义正确的 JsonPath 表达式 Id 1 N
  • 在单行上获取 jq 的输出

    我使用以下输出 https stackoverflow com a 40330344 https stackoverflow com a 40330344 issues key status fields status name assig
  • CodeIgniter 控制器 - JSON - AJAX

    我正在尝试通过 AJAX 使用 CodeIgniter 发送表单构建 并尝试使用 JSON 获取响应 但是 我只在打开开发人员选项卡时看到响应 我什至不确定这是否实际上是响应 因为它显示了两个 json 数据 它所显示的只是加载旋转器 然后
  • 无法将数据加载到 mvc 4 中的 jTable 中

    好的 我第一次尝试 jTable 我可以加载表 但这对我没有什么好处 因为它不会加载我的任何数据 当我调试程序时 我想要的表中的所有行都存储在我的列表中 因此我很困惑为什么当我运行应用程序时会弹出一个对话框 显示 与服务器通信时发生错误 H
  • JSON 数组到 C# 列表

    如何将这个简单的 JSON 字符串反序列化为 C 中的列表 on4ThnU7 n71YZYVKD CVfSpM2W 10kQotV 这样 List
  • CouchDB 通过三个索引键进行查询和过滤

    我目前正在尝试按具有三个值的键进行排序和排序 但让我们从文档结构开始 id DOCIDGOESHERE01 type MESSAGE date 2011 08 24 06 49 02 author USERIDGOESHERE01 rece
  • 使用 Javascript/JQuery 的 JSON 对象的差异

    我在 Javascript 中有两个 JSON 对象 除了数值之外 它们都是相同的 它看起来像这样 var data eth0 Tx 4136675 Rx 13232319 eth1 Tx 4 Rx 0 lo Tx 471290 Rx 47
  • 如何为所有 API 端点全局设置 http.ResponseWriter Content-Type 标头?

    我是 Go 新手 现在正在用它构建一个简单的 API package main import encoding json fmt github com gorilla mux github com gorilla handlers log
  • 写入 JSON 会产生 TypeError: dump() 需要至少 2 个参数(给定 1 个)

    我正在尝试加载 json 文件 更新它并写回来 这是我的尝试 但出现错误 类型错误 dump 至少需要 2 个参数 给定 1 个 with open employees json as data file employees json lo
  • 如何在 C# 中获取 Json 数组?

    我有一个像这样的 Json 字符串 我想将它加载到 C 数组中 当我尝试这样做时 我收到异常 我的字符串 customerInformation customerId 123 CustomerName Age 39 Gender Male
  • json_encode 返回 200 且未定义

    我想要一个代码来添加或删除数据库书签 代码已准备就绪 它可以正确地从数据库书签中添加和删除书签 但是当我调用该函数时 它会不断返回json error反而json success即使代码有效 我想知道代码 我从其他地方获得并改编的 有什么问
  • React Native / Laravel - 向 API 发送请求

    我正在实现一个移动应用程序 它使用 Laravel 作为 API 与数据库进行通信 我想将用户名和密码从我的 React Native 应用程序发送到 Laravel 我正在使用以下代码来执行此操作 fetch mysite com api
  • 来自 ajax 的 Bootstrap 表 json

    我有 ajax 和 bootstrap 表的问题 我有一个 ajax JSON 我用这个方法调用 document ready function ajax url php process php method fetchdata dataT
  • 加载腌制字典对象或加载 JSON 文件哪个更快? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 什么更快 A Unpickling 加载 一个 pickled 字典对象 使用pickle load or B 使用以下命令将 JSON
  • 使用 JSON 的 Pentaho HTTP Post

    我是 Pentaho 的新手 我正在尝试执行以下工作流程 从数据库中读取一堆行 做一些转换 将它们以 JSON 格式发布到 REST Web 服务 我已经使用输入步骤和 Json 输出步骤解决了前两个问题 但是 我在执行最后一步时遇到两个问
  • 如何为 json 请求对象指定可选元素

    在 API 蓝图中 我希望为 POST 消息指定一个可选的 json 元素 示例 Add a new User POST To add a User send a JSON Request application json name A n

随机推荐

  • Ubuntu_Crontab

    Ubuntu Crontab BasicUsage 编辑定时任务 crontab e 显示定时任务 crontab l 定时任务不执行的解决方案 首先手动执行定时任务命令 排查是否任务本身是否出问题 没问题的话 去日志中看 crontab日
  • C - C语言实验——求两个整数之中较大者

    Description 输入两个整数 请编程求其中的较大者 Input 在一行中输入用空格隔开的两个整数 例如5 9 Output 输出两个整数之中较大者 输出形式举例 max 9 Sample Input 5 9 Output max 9
  • 编程任务

    任务源自旧版的Brilliant数学讨论问题 2019 09 02我曾经发布过 可惜已经下线 幸活大喵做足备份 该问题看似是概率问题 实则不然 官方给出的解法透露出一个非常重要的数学思维方法 数学语言 为何以及如何构造一个函数 f n 运用
  • 互联网公司MySQL数据库采用读已提交的隔离级别原因

    开始我们的内容 相信大家一定遇到过下面的一个面试场景 面试官 讲讲mysql有几个事务隔离级别 你 读未提交 读已提交 可重复读 串行化四个 默认是可重复读 面试官 为什么mysql选可重复读作为默认的隔离级别 你面露苦色 不知如何回答 面
  • SAR ADC基本原理学习

    今天我们来学习SAR ADC喽 逐次逼近寄存器型模数转换器 Successive Approximation Analog to Digital Converter 是一种常用的A D转换结构 其较低的功耗表现 还不错的转换速率 在有低功耗
  • Shiro错误之No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util

    提示 No SecurityManager accessible to the calling code either bound to the org apache shiro util ThreadContext or as a vm
  • [深度学习] 模型集成方法

    模型集成方法 集成学习 ensemble learning 是机器学习中一类学习算法 值训练多个学习器并将它们组合起来使用的方法 这类算法通常在实践中会取得比单个学习器更好的预测结果 数据层面的集成方法 在训练阶段的数据扩充在测试阶段仍然使
  • ERROR:unable to read the cmd header on the pmi context, Error = -1

    win7 vs2010 MPI 以下仅在单机下做的测试 电脑之前装了MPICH2和Microsoft HPC Pack 2008 SDK 用vs2010链接MPICH2的库编译了一个小程序 在cmd下用mpiexec执行该程序时出现下面问题
  • linux——ifcfg-ens33文件参数解释

    早上在用ifconfig命令的时候得到的IP是192 168 137 132 但是看ifcfg ens33文件里面IP配置的是192 168 137 129 通过请教大神和百度得知 是与ifcfg ens33文件配置有关系 BOOTPROT
  • 2021年蓝桥杯A组省赛-左children右sibling

    CXXX有毛病 左孩子右兄弟 字眼很敏感吗 题目 题目链接 题解 贪心 DFS 以 u u u 为根的子树选择包含节点最多的以 v v v 为根的子树作为最后连接的右兄弟能保证树向下延展的最多 所以重点转换为了计算以
  • 二分特训上------刷题部分----Week4(附带LeetCode特训)

    二分特训上 理论部分 Week4 附带LeetCode特训 小杰312的博客 CSDN博客 如果需要理论 请移步上一篇 注意 我们把 0000001111111模型中 0称呼为左边区间 1称呼为右边区间 答案第一个1在右区间 1111100
  • 模拟器检测

    往期推荐 文件检测 签名验证 资源文件混淆 apk保护策略 Java代码混淆 模拟器检测的就是指通过检测确认软件 手游等不能运行在模拟器上面 比如一个游戏 它能够在模拟器上实现批量刷金币或者是其他功能 但模拟器又无法启动起来 在这种情况下
  • WPF CommunityToolkit.Mvvm

    文章目录 前言 Toolkit Nuget安装 简单使用 SetProperty 通知更新 RealyCommand CanExecute 新功能 代码生成器 ObservableProperty NotifyCanExecuteChang
  • eclipse的下载及安装教程

    第一步 从官网下载eclipse 进行安装 下载链接https www eclipse org downloads packages 根据自己的电脑和需求去选择对应的版本 点击download 进行下载 然后会跳转到一个打赏页面 无需理会
  • You must set CMAKE_CUDA_ARCHITECTURES to e.g. ‘native‘, ‘all-major‘, ‘70‘,

    You must set CMAKE CUDA ARCHITECTURES to e g native all major 70 cmake 报错 CMake Error at CMakeLists txt 255 message You
  • Python并发编程之多线程

    前言 本文介绍并发编程中另一个重要的知识 线程 线程介绍 我们知道一个程序的运行过程是一个进程 在操作系统中每个进程都有一个地址空间 而且每个进程默认有一个控制线程 打个比方 在一个车间中有很多原材料通过流水线加工产品 而线程就是这个车间中
  • 小程序代码体积优化

    微信小程序在发布的时候 对提交的代码有 2 MB 大小的限制 开发之前就需要提前有个心理准备 由于我也是第一次做小程序开发代码大小就超过了2MB 开发者工具都无法预览了 这就很尴尬了 我自己的优化代码积的方式也不多 如果你有更好的方法 可以
  • linux分区满了,如何进行扩容

    图片中可以看到挂载点 的利用率移到100 空间不够 所以要对其进行分区 1 先进入虚拟机设置里增大磁盘空间 注意 将25改成50 以扩大空间 这里一定要写比25大的数 因为他是 增加到 50GB 而不是 增加了25GB 2 下图可以看到 硬
  • 统计学习方法(九)EM算法

    参考博客 https www cnblogs com bigmoyan p 4550375 html https en wikipedia org wiki Expectation E2 80 93maximization algorith
  • 【网络编程】协议定制+Json序列化与反序列化

    需要云服务器等云产品来学习Linux的同学可以移步 gt 腾讯云 lt gt 阿里云 lt gt 华为云 lt 官网 轻量型云服务器低至112元 年 新用户首次下单享超低折扣 目录 一 序列化与反序列化的概念 二 自定义协议设计一个网络计算