【Linux网络编程七】网络序列化和反序列化(网络版本计算器)

news2024/10/5 20:23:47

【Linux网络编程七】网络序列化和反序列化(网络版本计算器)

  • 一.网络读取问题
    • 【解决方案】
    • 1.定制协议
    • 2.序列化和反序列化
    • 3.添加报头
      • ①封包
      • ②解包
    • 4.框架总结
  • 二.自定义协议:网络计算器协议
    • Ⅰ.客户端发送请求,服务器端接收请求
      • 1.构建请求(结构化数据)
      • 2.请求序列化
      • 3.添加报头,发送到网络
      • 4.服务器读取请求
      • 5.解除报头
      • 6.请求反序列化
    • Ⅱ.服务器端发送响应,客户端接收响应
      • 1.构建响应(结构化数据)
      • 2.响应序列化
      • 3.添加报头,发送到网络
      • 4.客户端读取响应
      • 5.解除报头
      • 6.响应反序列化
  • 三.自动序列化和反序列化Json
  • 四.理解OSI七层协议

一.网络读取问题

在网络通信时,通信双方是无法保证读取时,能够正确的读取到想要的内容的。
这是什么意思呢?
在这里插入图片描述

【解决方案】

在这里插入图片描述

1.定制协议

什么叫定制协议呢?就是让双方都要能知道,约定好的一些字段,然后以结构化的形式发送和接收。
在这里插入图片描述
定制的协议双方都要能认识才可以通信。不然一方认识,另一方不认识就无法通信了。
在这里插入图片描述

2.序列化和反序列化

定制好结构体后,然后构建一个对象,是不是就可以直接发送过去了呢?
当然不可以!为什么呢?

1.我们不能直接将结构体对象直接发送给对端机器,因为双方可能机器不同,对于结构体的解读会不一样,最终就会解析错误。所以通常我们不直接发送结构化数据到网络里,而是发送字符串形式的数据给对端。
2.也就是我们需要在构建完结构化数据后,在发送到网络里之前还需要将它转换成字符串形式,才能发送。这个过程就叫做序列化
3.而对端机器从网络里接收到字符串后,它并不认识这个字符串是什么意思,只有将这个字符串转成结构化化数据,它才能知道对方发送的是什么信息。而将字符串数据再转成结构化数据,就叫做反序列化。
在这里插入图片描述

在这里插入图片描述

这里是引用

3.添加报头

那么问题又回来了,对端是如何正确获取到想要的完整报文的呢?
在这里插入图片描述

我们可以利用一些特殊字符,来区别报文与报文。而如果想要对方准确的接收到一个完整的报文,那么就可以通过在报文前面添加一个长度单位,标识这个报文总长度有多少,一旦对端读取到这个长度,就可以直接从后面截取报文的长度,就可以直接完整的获取到一个报文。
而在报文前面添加一个长度单位这个行为,我们可以称为添加一个报头。

添加报头的目的就是为了让对端在读取的时候,能够根据报头,来完整的获取一个报文。所以添加报头也是属于定制协议的部分。通信的双方都要能识别。

①封包

所以构建完结构化数据后,在发送到网络之前,需要将之转换成字符串形式,也就是序列化。然后为了让对端能够准确的获取到一个完整的报文,我们还需要对这个字符串添加报头。

这里是引用

②解包

对端获取到从网络里发送来的数据后,并不理解是什么意思,所以需要反序列化,将字符串数据转换成结构化数据,这样它就可以理解是什么意思了。
但是这里存在的问题就是:它并不能确定对方发送的是一个报文还是多个报文,还是半个报文。因为从网络里发送来的就是一个字符串形式的数据。它分析不出来。而反序列化,是以一个完整的报文进行反序列化的,因为当时序列化的时候就是一个完整的结构体数据进行序列化的。

所以定制协议的人,考虑到这点,就在报文的前面添加了一个报头:表明报文的长度的字段。这样只要对端接收到报文,然后依据报头,就能分析出对方发送的数据是否是完整的了。如果是完整的,那么直接获取有效的报文。如果不是完整的,那么重新去读取,如果是多个报文,那么我们只要一个完整的报文即可。剩下的等下次再处理。

这里是引用

4.框架总结

这里是引用

在这里插入图片描述
在这里插入图片描述

网络部分套接字:

Socket.hpp
#pragma once
//将网络套接字编程部分直接封装打包,因为服务器和客户端都需要使用创建套接字等操作。
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include <cstdlib>
#include <cstring>
#include <unistd.h>
enum
{
  SocketErr=1,
  BindErr,
  ListenErr,
};
const int backlog=10;
class Sock
{

public:
    Sock()
    {}
    ~Sock()
    {}

    void Socket()//创建套接字
    {
     _socket=socket(AF_INET,SOCK_STREAM,0);
     if(_socket<0)
     {
        lg(Fatal,"socket err:%s :%d",strerror(errno),errno);
        exit(SocketErr);
     }
    }
    void Bind(uint16_t &port)//绑定套接字
    {
      struct sockaddr_in local;
      memset(&local,0,sizeof(local));
      local.sin_addr.s_addr=INADDR_ANY;//将ip地址初始化成0
      local.sin_family=AF_INET;
      local.sin_port=htons(port);
      if(bind(_socket,(struct sockaddr*)&local,sizeof(local))<0)
      {
        lg(Fatal,"bind err :%s :%d",strerror(errno),errno);
        exit(BindErr);
      }
    }
    void Listen()//将套接字设置成监听状态
    {
       if(listen(_socket,backlog)<0)
       {
        lg(Fatal,"listen err :%s :%d",strerror(errno),errno);
        exit(ListenErr);
       }
    }
    int Accept(std::string *clientip,std::uint16_t* clientport)//服务器获取连接,并获取对方的网络信息,将获取的到的新连接交给服务函数操作
    {
        struct sockaddr_in client;
        socklen_t len=sizeof(client);
        int newsock=accept(_socket,(struct sockaddr*)&client,&len);
        if(newsock<0)
        {
            lg(Warning,"accept err :%s :%d",strerror(errno),errno);
            return -1;
        }
        *clientport=ntohs(client.sin_port);
        char Clientip[32];
        inet_ntop(AF_INET,&client.sin_addr,Clientip,sizeof(Clientip));
        *clientip=Clientip;
        return newsock;
    }
    bool Connect(const std::string &serverip,const uint16_t &serverport)//需要知道要连接的对方的网络信息
    {
        struct sockaddr_in local;
        socklen_t len=sizeof(local);
        memset(&local,0,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(serverport);
        inet_pton(AF_INET,serverip.c_str(),&local.sin_addr);
     
        int n=connect(_socket,(struct sockaddr*)&local,len);
        if(n==-1)
        {
            std::cerr<<"connect to"<<serverip<<":"<<serverport<<"error"<<std::endl;
            return false;
        }
        return true;
    }
    void Close()
    {
        close(_socket);
    }
    int Fd()
    {
      return _socket;
    }
private: 
  int _socket;
};

协议部分

Protocol.hpp
#pragma once
//#define MySelf 1
// 在网络通信之前,我们服务器端和客户端都需要知道协议。我们也可以自己定制协议,这个协议要被双方都能识别
// 比如我们可以定制一个计数器协议。协议就是一种约定,除了数据本身还有其他的字段。
// 1.我们要求将数据以结构化的形式保存这样双方都可以识别这个结构体对象,但传入网络里时,需要转换成字符类型。这个过程就是序列化.序列化的过程就是在构建有效载荷
// 2.对方接收到字符串类型的数据时,想要用服务操作时,发现是不能操作的,是因为它不认识,这时还需要将字符类型转成结构体类型,这个过程叫做反序列化。
// 3.为了能让对方接收时,能接收读取到对方想要的完整报文时,我们采取添加报头的形式来解决。
// 4.所以在将报文传入到网络里时,还需要添加报文,当对端接收到报文时,想要对它进行处理之前,还需要将报文的报头解包才可以正确处理。
#include <iostream>
#include <jsoncpp/json/json.h>
#include <string>
const std::string blank_space = " ";
const std::string protocol_space="\n";
// 封包:报文在发送到网络之前需要添加一些报头,来达到一些要求
std::string Encode(const std::string &content)//content就是有效载荷
{
  //"x + y"------>"len"\n"x + y"\n"   添加了一个报文长度和两个\n
  std::string packpage=std::to_string(content.size());
  packpage+=protocol_space;
  packpage+=content;
  packpage+=protocol_space;
  return packpage;
}

// 解包:对端读取到报文(可能读取到的不是想要的,根据原先添加上去的报头来获取准确想要的报文),想要处理它,需要先解除报头才能处理
bool Decode(std::string &packpage, std::string *content)
{ 
  //"len"\n"x + y"\n"---->"x + y"
  std::size_t pos=packpage.find(protocol_space);
  if(pos==std::string::npos)
  return false;

  std::string len_str=packpage.substr(0,pos);
  //判断一下是否读取的内容是全部的
  std::size_t len =std::stoi(len_str);
  std::size_t total_len=len_str.size()+len+2;
  if(packpage.size()<total_len)//说明不是一个完整的报文
  return false;
  *content=packpage.substr(pos+1,len);
  //为了真正的拿走报文,还需要将响应inbuffer里的报文移除erase,这样才是真正的拿走报文
  
  packpage.erase(0,total_len);
  return true;
}

class Request
{
public:
  Request()
  {}
  Request(int data1, int data2, char op) : _x(data1), _y(data2), _op(op) // 最初形成结构化数据
  {
  }
  bool Serialize(std::string *out) // 序列化,单纯的就是将结构体转换成字符串
  {
#ifdef MySelf    // 构建报文的有效载荷
    // struct==》"x + y"
    std::string s = std::to_string(_x);
    s += blank_space;
    s += _op;
    s += blank_space;
    s += std::to_string(_y);
    *out = s;
    return true;
 #else
     Json::Value root;//定义一个万能对象,可以存储数据,k-v形式的结构体
     root["x"]=_x;
     root["y"]=_y;
     root["op"]=_op;
     //Json::FastWriter w;
     Json::StyledWriter w;
     *out=w.write(root);//序列化成字符串
     return true;   
    
 #endif

  }
  bool Deserialize(std::string &in) // 反序列化,就单纯的将字符串类型转成结构体
  {
#ifdef MySelf   
    //"x + y"==>struct
    //获取左操作数x
    std::size_t left=in.find(blank_space);
    if(left==std::string::npos)
    return false;
    std::string part_x=in.substr(0,left);
    //获取右操作数y
    std::size_t right=in.rfind(blank_space);
    if(right==std::string::npos)
    return false;
    std::string part_y=in.substr(right+1);
    //获取操作码op
    if(left+2!=right)
    return false;

    _op=in[left+1];
    _x=std::stoi(part_x);
    _y=std::stoi(part_y);
    return true;
#else
    Json::Value root;//定义一个万能对象,将序列化的数据存储在里面
    Json::Reader r;
    r.parse(in,root);
    //将数据存到万能对象里后,我们就可以根据key值找到
    _x=root["x"].asInt();
    _y=root["y"].asInt();
    _op=root["op"].asInt();
    return true;
#endif    
  }
    void DebugPrint()
    {
        std::cout<<"新请求构建完毕:"<<_x<<_op<<_y<<"=???"<<std::endl;
    }
public: // x + y
  int _x;
  int _y;
  char _op;
};
class Response
{
public:
  Response(int reslut, int code) : _reslut(reslut), _code(code)
  {
  }
  Response()
  {}
  bool Serialize(std::string *out) // 序列化,单纯的就是将结构体转换成字符串
  {
#ifdef MySelf
    //"reslut code"
    //构建报文的有效载荷
    std::string s=std::to_string(_reslut);
    s+=blank_space;
    s+=std::to_string(_code);
    *out=s;
    return true;
#else
     Json::Value root;
     root["reslut"]=_reslut;
     root["code"]=_code;
     //Json::FastWriter w;
     Json::StyledWriter w;
     *out=w.write(root);
     return true;
#endif    
  }
   bool Deserialize(std::string &in)
   {
#ifdef MySelf
    //"reslut code"-->结构体类型
    std::size_t pos=in.find(blank_space);
    if(pos==std::string::npos)
    return false;

    std::string part_left=in.substr(0,pos);
    std::string part_right=in.substr(pos+1);

    _reslut=std::stoi(part_left);
    _code=std::stoi(part_right);
    return true;
#else
    Json::Value root;
    Json::Reader r;
    r.parse(in,root);//将字符串数据存到万能对象里

    _reslut=root["reslut"].asInt();
    _code=root["code"].asInt();
    return true;
#endif
   }

   void DebugPrint()
   {
    std::cout<<"结果响应完成,reslut: "<<_reslut<<",code: "<<_code<<std::endl;
   }

public:
  int _reslut;
  int _code;
};

服务器服务部分:

ServerCal.hpp
#pragma once
#include "Protocol.hpp"
#include <iostream>
#include <string>
// 服务器端,从网络里读取到数据后,就要进行处理服务。
// 1.首先需要对报文进行解包,2.解包后还需要将报文转成结构体类型对方才能识别
enum
{
  Div_Zero = 1,
  Mod_Zero,
  Other_Oper
} ;
class ServerCal
{
public:
  Response Calculatorhelpor(const Request &req)
  {
    Response resp(0, 0);
    switch (req._op)
    {
    case '+':
      resp._reslut = req._x + req._y;
      break;
    case '-':
      resp._reslut = req._x - req._y;
      break;
    case '*':
      resp._reslut = req._x * req._y;
      break;
    case '/':
    {
      if (req._y == 0)
        resp._code = Div_Zero;
      else
        resp._reslut = req._x / req._y;
    }
    break;
    case '%':
    {
      if (req._y == 0)
        resp._code = Mod_Zero;
      else
        resp._reslut = req._x % req._y;
    }
    break;

    default:
     resp._code=Other_Oper;
      break;
    }
    return resp;
  }

  std::string Calculator(std::string &package)
  {
    std::string content;                //"len""\n""20 + 10""\n"
    bool r = Decode(package, &content); //"20 + 10"
    if (!r)
      return "";
    Request req; // 反序列化
    r = req.Deserialize(content);
    if (!r)
      return "";

    // 服务器端解包获取到报文后,就可以进行计算,再将计算结果返回回到网络里,网络里需要序列化的数据

    Response res = Calculatorhelpor(req); // reslut=30  code=0
    content = "";
    res.Serialize(&content);   //"30 0"
    content = Encode(content); //"len""\n""30 0""\n"

    return content;
  }
};

二.自定义协议:网络计算器协议

Ⅰ.客户端发送请求,服务器端接收请求

ClientCal.cc
#include <iostream>
#include <time.h>
#include <unistd.h>
#include <assert.h>
#include "Socket.hpp"
#include "Protocol.hpp"
void Usage(std::string proc)
{
    std::cout<<"\n\rUsage: "<<proc<<" port[1024+]\n"<<std::endl;
}
//./tcpclient ip port
int main(int args,char* argv[])
{
    if(args!=3)
    {
     Usage(argv[0]);
     exit(1);
    }
    std::string serverip=argv[1];
    uint16_t serverport=std::stoi(argv[2]);
    
    Sock sockfd;
    sockfd.Socket();//创建套接字
    bool r=sockfd.Connect(serverip,serverport);//发起连接
    if(!r)return 1;

    
    srand(time(nullptr)^getpid());
    int cnt=1;
    std::string oper="+-*/%=$";
    std::string inbuffer_stream;
    while(cnt<=10)
    {
        std::cout<<"========第"<<cnt<<"次测试"<<"============"<<std::endl;
        //1.开始构建请求
        int x=rand()%100+1;
        usleep(1234);
        int y=rand()%100;
        usleep(4321);
        char op=oper[rand()%oper.size()];
        Request req(x,y,op);
        //2.请求构建完毕
        req.DebugPrint();
        //3.数据序列化形成报文
        std::string content;
        req.Serialize(&content);
        //4.添加报头
        std::string packpage=Encode(content);
        //5.发送到网络里
        write(sockfd.Fd(),packpage.c_str(),packpage.size());

        //6.接收服务器端发送来的响应
        char buffer[128];
        ssize_t n=read(sockfd.Fd(),buffer,sizeof(buffer));
       //6.1处理读取
        if(n>0)
        {
            buffer[n]=0;
            inbuffer_stream+=buffer;//接收到的是一个协议报文"len"\n"reslut code"\n
            std::cout<<std::endl;
            std::cout<<"获取到的网络答应:"<<std::endl;
            std::cout<<inbuffer_stream<<std::endl;//将从网络里获取到的报文打印出来

            //7.首先需要解包检测
            std::string content;
            bool r =Decode(inbuffer_stream,&content);
            assert(r);
            //8.反序列化,将答应变成客户端可认识的形式
            Response resp;
            r=resp.Deserialize(content);
            assert(r);
            //9.结果响应完成
            resp.DebugPrint();
        }
        std::cout<<"============================="<<std::endl;
        sleep(1);
        cnt++;

    }

    sockfd.Close();
}

1.构建请求(结构化数据)

2.请求序列化

3.添加报头,发送到网络

4.服务器读取请求

5.解除报头

6.请求反序列化

Ⅱ.服务器端发送响应,客户端接收响应

Main.cc
#include "Tcpserver.hpp"
#include "ServerCal.hpp"
#include <memory>
void Usage(std::string proc)
{
    std::cout << "\n\rUsage: " << proc << " port[1024+]\n"
              << std::endl;
}

int main(int args, char *argv[])
{

    if (args != 2)
    {
        Usage(argv[0]);
        exit(0);
    }

    uint16_t port = std::stoi(argv[1]);
    ServerCal cal;
    Tcpserver *tcpsvr = new Tcpserver(port, std::bind(&ServerCal::Calculator, &cal, std::placeholders::_1));
    tcpsvr->Init();
    tcpsvr->Start();
    return 0;
}
Tcpserver.hpp
#pragma once
#include <iostream>
#include <string>
#include <functional>
#include "Log.hpp"
#include <signal.h>
#include "Socket.hpp"
#include "ServerCal.hpp"
Sock sock;
using func_t =std::function<std::string(std::string &package)>;

class Tcpserver
{

public:
    Tcpserver(uint16_t port,func_t callback) : _port(port),_callback(callback)
    {
    }
    bool Init()
    {
        _listensock.Socket();    // 创建套接字
        _listensock.Bind(_port); // 绑定套接字
        _listensock.Listen();    // 将套接字设置成监听状态
        lg(Info, "init server...done");
        return true;
    }
    void Start() // 启动服务器
    {            // 启动之前需要先忽略一些信号
        signal(SIGPIPE, SIG_IGN);
        signal(SIGCHLD, SIG_IGN);
        // 获取连接
        while (true)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = _listensock.Accept(&clientip, &clientport);
            if (sockfd < 0)
                continue;
            lg(Info, "accept a new link, sockfd:%d, clientip:%s ,clientport: %d",sockfd,clientip.c_str(),clientport);
            
            // 提供服务-->让子进程提供服务
            if (fork() == 0)
            {
                _listensock.Close();
                std::string inbuffer_stream;
                while (true)
                {
                    // 1.读取网络中的数据流
                    char buffer[128];
                    size_t n = read(sockfd, buffer, sizeof(buffer));
                    if (n > 0)
                    {
                        buffer[n]=0;
                        //将读取的报文进行处理
                       inbuffer_stream+=buffer;//注意读取的内容必须是一个完整的内容,不然调用回调时,就回调用失败
                       lg(Debug,"获取的网络请求:\n %s",inbuffer_stream.c_str());
                       std::string info=_callback(inbuffer_stream);
                       
                       if(info.empty())continue;//如果进行计算时,发现报文有问题,就重新回来读取。

                       // 2.将处理的结果发送回网络中
                       write(sockfd,info.c_str(),info.size());
                    }
                    else if(n==0)break;
                    else break;

                    
                }
                exit(0);
            }
            close(sockfd);
        }
    }
    ~Tcpserver()
    {
    }

private:
    uint16_t _port;
    Sock _listensock;
    func_t _callback;
};

1.构建响应(结构化数据)

2.响应序列化

3.添加报头,发送到网络

4.客户端读取响应

5.解除报头

6.响应反序列化

三.自动序列化和反序列化Json

在这里插入图片描述

 bool Serialize(std::string *out) // 序列化,单纯的就是将结构体转换成字符串
  {
     Json::Value root;//定义一个万能对象,可以存储数据,k-v形式的结构体
     root["x"]=_x;
     root["y"]=_y;
     root["op"]=_op;
     //Json::FastWriter w;
     Json::StyledWriter w;
     *out=w.write(root);//序列化成字符串
     return true;  

  }
  bool Deserialize(std::string &in) // 反序列化,就单纯的将字符串类型转成结构体
  {
    Json::Value root;//定义一个万能对象,将序列化的数据存储在里面
    Json::Reader r;
    r.parse(in,root);
    //将数据存到万能对象里后,我们就可以根据key值找到
    _x=root["x"].asInt();
    _y=root["y"].asInt();
    _op=root["op"].asInt();
    return true;
  }

四.理解OSI七层协议

在这里插入图片描述

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

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

相关文章

VS Code安装Live Server插件搭建web网页结合内网穿透实现公网访问

文章目录 前言1. 编写MENJA小游戏2. 安装cpolar内网穿透3. 配置MENJA小游戏公网访问地址4. 实现公网访问MENJA小游戏5. 固定MENJA小游戏公网地址 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&…

SAP Business Application Studio(BAS) 中Git的使用

1. 概要 本文将介绍如何在SAP BAS中使用Git。 2. BAS中Git功能的集成方式 2.1 简化版Git视图&#xff08;Simplified Git View&#xff09; 通过简化版Git视图&#xff0c;开发人员可以执行最常用的一些Git操作&#xff0c;例如&#xff1a; 初始化或克隆一个仓库reposito…

【matlab】如何将.mat文件与.nii文件互转

【matlab】如何将.mat文件与.nii文件互转 .mat转为.nii文件 有时候代码需要读取的是.nii文件&#xff0c;但是如何现有的数据是.mat格式&#xff0c;需要将.mata转化为.nii文件 1、先加载.mat文件 % 加载.mat文件 load(your_mat_file.mat); % 请将your_mat_file.mat替换为实…

曹洞佛学院2024年 “中国传统文化(书法)研究班”招生简章

曹洞佛学院 中国传统文化 &#xff08;书法&#xff09; 研究班 一、曹洞佛学院简介 2016年10月&#xff0c;曹洞佛学院经国家宗教事务局批准正式成立。曹洞佛学院是全国唯一一所以宗派命名的佛学院&#xff0c;学院坐落于江西省抚州市宜黄县曹洞宗祖庭——曹山宝积寺。   …

Dagger2相关知识

目录 一、Dagger简介1.1 什么是Dagger?1.2 Dagger用来干什么&#xff1f;1.3 使用Dagger2注入对象1.4 Dagger注解 二、Dagger2使用2.1 非单例2.2 局部单例2.3 全局单例 三、参考链接 一、Dagger简介 1.1 什么是Dagger? Dagger 2 是一个由 Google 开发的依赖注入框架&#x…

【论文阅读】MSGNet:学习多变量时间序列预测中的多尺度间序列相关性

MSGNet&#xff1a;学习多变量时间序列预测中的多尺度间序列相关性 文献介绍摘要总体介绍背景及当前面临的问题现有解决方案及其局限性本文的解决方案及其贡献 背景知识的相关工作背景知识问题表述&#xff1a; Method论文主要工作1.输入嵌入和剩余连接 (Input Embedding and R…

git:码云gitee仓库提交以及React项目创建

git&#xff1a;码云gitee仓库提交以及React项目创建 1 前言 先注册准备好码云gitee的账户&#xff0c;并在gitee上新建react仓库并提交代码至远程仓库。 2 操作方式 准备新建React项目并提交到码云gitee上。 &#xff08;1&#xff09;进入官网&#xff1a;https://gitee…

Java面试相关问题

一.MySql篇 1优化相关问题 1.1.MySql中如何定位慢查询&#xff1f; 慢查询的概念&#xff1a;在MySQL中&#xff0c;慢查询是指执行时间超过一定阈值的SQL语句。这个阈值是由long_query_time参数设定的&#xff0c;它的默认值是10秒1。也就是说&#xff0c;如果一条SQL语句的执…

【Leetcode-19.删除链表的第N个节点】

题目详情&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1…

什么是Vector Database?

此为看完视频What is a Vector Database?后的笔记。 作者首先对数据库做了分类&#xff0c;其中RTweb表示real time web app。 然后对用例做了分类&#xff0c;最后一个就是适合于AI的近似搜索。 好处&#xff0c;包括灵活性&#xff0c;可扩展性和性价比。 本视频最重要的…

【bioinformation 10】ADMET-CYPs抑制剂预测实战

&#x1f31e;欢迎来到AI医学的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f4c6;首发时间&#xff1a;&#x1f339;2024年3月17日&am…

/usr/local/bin/docker-compose: line 1: Not: command not found

安装docker-compose 检查是否安装成功 docker-compose --version 出错 /usr/local/bin/docker-compose: line 1: Not: command not found 检查下载连接是否正确 官网 https://dockerdocs.cn/compose/install/ 根据官网上连接下载 发现下载不了 在版本前加个V 就可以解决 版…

4.1_4 文件的物理结构

文章目录 4.1_4 文件的物理结构&#xff08;一&#xff09;文件块、磁盘块&#xff08;二&#xff09;文件分配方式——连续分配&#xff08;三&#xff09;文件分配方式——链接分配&#xff08;1&#xff09;链接分配——隐式链接&#xff08;2&#xff09;链接分配——显式链…

JETSON 配置并跑通 NanoDet

JETSON 配置 NanoDet 文章目录 JETSON 配置 NanoDetNanoDet 介绍源码环境搭建及测试配置 NanoDet 的环境环境配置过程中遇到的问题&#xff1a;环境配置完毕验证 NanoDet NanoDet 介绍 可以参考这个博客&#xff1a;NanoDet&#xff1a;这是个小于4M超轻量目标检测模型 源码 …

什么是网站?为什么要搭建网站?

网站&#xff1a;简单来说&#xff0c;网站就是通过互联网来展示信息的页面集合。它可以在电脑或者手机上打开&#xff0c;提供各种功能&#xff0c;比如查看新闻、购买商品、搜索信息等。 一、建网站的目的&#xff1a;展示个人或企业的存在 网站建设的首要目的之一是展示个人…

23-分支和循环语句_习题练习

1、转换以下ASClI码为对应字符并输出他们&#xff1a;73,32,99, 97,110,32,100,111,32,105,116,33 输入&#xff1a;无 输出&#xff1a;一行输出转换题目中给出的所有ASClI码对应的字符&#xff0c;无需以空格隔开。 输入&#xff1a; int main() {int i 0;int arr[] { …

加拿大光量子计算公司Xanadu入局英国多企业量子合作计划

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 编辑丨慕一 编译/排版丨沛贤 深度好文&#xff1a;1200字丨8分钟阅读 英国航空发动机制造商罗尔斯罗伊斯&#xff08;Rolls-Royce&#xff09;、英国量子计算公司Riverlane和加拿大量子计算公…

【Nutx3】middleware目录介绍

简言 记录下nuxt3middleware目录的使用方法。 middleware middleware是存放路由中间件的文件目录。 路由中间件有三种&#xff1a; 匿名&#xff08;或内联&#xff09;路由中间件直接在页面中定义。已命名的路由中间件&#xff0c;放在 middleware/ 中&#xff0c;页面使用…

leetcode代码记录(移除元素

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1)…

Docker入门二(应用部署、迁移与备份、DockerFile、docker私有仓库、Docker-Compose)

文章目录 一、应用部署1.MySQL部署2.Redis部署3.Nginx部署 二、迁移与备份1.容器做成镜像2.镜像备份和恢复(打包成压缩包&#xff09; 三、DockerFile0.镜像从哪里来&#xff1f;1.什么是DockerFile2.DockerFile 构建特征3.DockerFile命令描述4.构建一个带vim的centos镜像案例5…