网络编程 -- 简易TCP网络程序

一 字符串回响

1.1 核心功能

  字符串回响程序类似于 echo 指令,客户端向服务器发送消息,服务器在收到消息后会将消息发送给客户端,该程序实现起来比较简单,同时能很好的体现 socket 套接字编程的流程。

  

1.2 程序结构

  这个程序我们已经基于 UDP 协议实现过了,换成 TCP 协议实现时,程序的结构是没有变化的,同样需要 server.hppserver.ccclient.hppclient.cc 这几个文件。

server.hpp 头文件

 #pragma once

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include "err.hpp"
#include<cstring>

namespace My_server{

    const uint16_t default_port = 8888; // 默认端口号
    class server{
    public:

        server(const uint16_t port = default_port)
            :_port(port)
        {}

        ~server()
        {}

        // 初始化服务器
        void InitServer(){
         
        }

        // 启动服务器
        void StartServer()
        {}

    private:
        int _sock; // 套接字(存疑)
        uint16_t _port; // 端口号
    };
}

注意: 这里的 _sock 套接字成员后面需要修改

server.cc 头文件

//智能指针头文件
#include<memory>
#include"server.hpp"

using namespace My_server;

int main(){

    std::unique_ptr<server> usvr(new server());
     
    usvr->InitServer();
    
    usvr->StartServer();

    return 0;
}

创建 client.hpp 客户端头文件

#pragma once

#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"err.hpp"

namespace My_client{
   
   class client{
     public:
        client(const std::string& ip,const uint16_t port)
         :server_ip(ip)
         ,server_port(port)
        {}

        ~client(){}
        
        //初始化客户端
        void InitClient(){}

        // 启动客户端
        void StartClient(){}

     private:
       int _sock;// 套接字
       std::string server_ip;//服务器ip
       uint16_t server_port; //服务器端口号

   };
}

创建client.cc文件
 

#include"client.hpp"
#include<memory>

using namespace My_client;

void Usage(char* program){

    std::cout<<"Usage : "<<std::endl;
    std::cout<<"\t "<<program<<" ServerIP ServerPort"<<std::endl;

}

int main(int argc,char *argv[]){
   
   if(argc!=3){
      Usage(argv[0]);
      return USAGE_ERR;
   }
   
   //获取服务器IP地址和端口号
    std::string ip(argv[1]);
    uint16_t port=std::stoi(argv[2]);

    std::unique_ptr<client> usvr(new client(ip,port));

    usvr->InitClient();
    usvr->StartClient();
    
    return 0;
}

同时需要Makefile文件

.PHONY:all
all:server client

server:server.cc
	g++ -o $@ $^ -std=c++14

client:client.cc
	g++ -o $@ $^ -std=c++14

.PHONY:clean
clean:
	rm -rf server client

和 err.hpp 头文件

#pragma once

// 错误码
enum
{
    USAGE_ERR=1 ,
    SOCKET_ERR,
    BIND_ERR
};

1.3 服务端

1.3.1 初始化服务端  

  基于 TCP 协议实现的网络程序也需要 创建套接字、绑定 IP 和端口号

在使用 socket 函数创建套接字时,UDP 协议需要指定参数2为 SOCK_DGRAMTCP 协议则是指定参数2为 SOCK_STREAM

InitServer() 初始化服务器函数 — 位于 server.hpp 服务器头文件中的 server

 #pragma once

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include "err.hpp"
#include<cstring>

namespace My_server{

    const uint16_t default_port = 8888; // 默认端口号
    class server{
    public:

        server(const uint16_t port = default_port)
            :_port(port)
        {}

        ~server()
        {}

        // 初始化服务器
        void InitServer(){

          //1 创建套接字
           _sock = socket(AF_INET,SOCK_STREAM,0);
           if(_sock==-1){
              //绑定失败
              std::cerr<<"Create Socket Fail!"<<strerror(errno)<<std::endl;
              exit(SOCKET_ERR);
           }

           std::cout<<"Create Socket Success!"<<_sock<<std::endl;
          //2 绑定端口号和IP地址
          
          struct sockaddr_in lockal;
          bzero(&lockal,sizeof lockal);

          lockal.sin_family = AF_INET;
          lockal.sin_addr.s_addr = INADDR_ANY;
          lockal.sin_port = htons(_port);

          if(bind(_sock,(const sockaddr*)&lockal,sizeof(lockal))){
            std::cout<<"Bind IP&&Port Fali:"<<strerror(errno)<<std::endl;
            exit(BIND_ERR);
          }
         
        }

        // 启动服务器
        void StartServer()
        {}

    private:
        int _sock; // 套接字(存疑)
        uint16_t _port; // 端口号
    };
}

注意: 在绑定端口号时,一定需要把主机序列转换为网络序列

  为什么在绑定端口号阶段需要手动转换为网络序列,而在发送信息阶段则不需要? 这是因为在发送信息阶段,recvfrom / sendto 等函数会自动将需要发送的信息转换为网络序列,接收信息时同样会将其转换为主机序列,所以不需要手动转换

  如果使用的 UDP 协议,那么初始化服务器到此就结束了,但我们本文中使用的是 TCP 协议,这是一个 面向连接 的传输层协议,意味着在初始化服务器时,需要设置服务器为 监听 状态

  使用到的函数是 listen 函数

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int listen(int sockfd, int backlog);

返回值:监听成功返回 0,失败返回 -1.

  listen函数 使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。

  这里的参数2需要设置一个整数,通常为 16、32、64...,表示 全连接队列 的最大长度,关于 全连接队列 的详细知识放到后续博客中讲解,这里只需要直接使用。

server.hpp 服务器头文件

  我们改变一下网络文件的名字

 #pragma once

#include<iostream>
#include<cerrno>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include "err.hpp"
#include<cstring>

namespace My_server{

    const uint16_t default_port = 8888; // 默认端口号
    const int backlog=32; //全连接队列的最大长度

    class server{
    public:

        server(const uint16_t port = default_port)
            :_port(port)
        {}

        ~server()
        {}

        // 初始化服务器
        void InitServer(){

          //1 创建套接字
           _listensock = socket(AF_INET,SOCK_STREAM,0);
           if(_listensock==-1){
              //绑定失败
              std::cerr<<"Create Socket Fail!"<<strerror(errno)<<std::endl;
              exit(SOCKET_ERR);
           }

           std::cout<<"Create Socket Success!"<<_listensock<<std::endl;

          //2 绑定端口号和IP地址
          struct sockaddr_in local;
          bzero(&local,sizeof(local));
          local.sin_family = AF_INET;
          local.sin_addr.s_addr = INADDR_ANY;//绑定任意可用IP地址
          local.sin_port = htons(_port);

          if(bind(_listensock,(const sockaddr*)&local,sizeof(local))){

            std::cout<<"Bind IP&&Port Fali:"<<strerror(errno)<<std::endl;
            exit(BIND_ERR);

          }
         
         //3. 监听
         if(listen(_listensock,backlog) == -1){
            std::cerr << "Listen Fail!" << strerror(errno) << std::endl;
            //新增一个报错
            exit(LISTEN_ERR);
         }
         std::cout<<"Listen Success!"<<std::endl;
         
        }

        // 启动服务器
        void StartServer()
        {}

    private:
        int _listensock; // 套接字(存疑)
        uint16_t _port; // 端口号
    };
}

  至此基于  TCP 协议 实现的初始化服务器函数就填充完成了,编译并运行服务器,显示初始化服务器成功。

1.3.2 启动服务器

1.3.2.1 处理连接请求

  TCP 是面向连接,当有客户端发起连接请求时,TCP 服务器需要正确识别并尝试进行连接,当连接成功时,与其进行通信,可使用 accept 函数进行连接。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数解读:

  • sockfd 服务器用于处理连接请求的 socket 套接字
  • addr 客户端的 sockaddr 结构体信息
  • addrlen 客户端的 sockaddr 结构体大写

  其中 addraddrlen 是一个 输入输出型 参数,类似于 recvfrom 中的参数。

  返回值:连接成功返回一个用于通信的 socket 套接字(文件描述符),失败返回 -1。

  这也就意味着之前我们在 TcpServer 中创建的类内成员 sock_ 并非是用于通信,而是专注于处理连接请求,在 TCP 服务器中,这种套接字称为 监听套接字

使用 accept 函数处理连接请求

server.hpp 服务器头文件

 #pragma once

#include<iostream>
#include<cerrno>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include "err.hpp"
#include<cstring>

namespace My_server{

    const uint16_t default_port = 8888; // 默认端口号
    const int backlog=32; //全连接队列的最大长度

    class server{
    public:

        server(const uint16_t port = default_port)
            :_port(port)
        {}

        ~server()
        {}

        // 初始化服务器
        void InitServer(){

          //1 创建套接字
           _listensock = socket(AF_INET,SOCK_STREAM,0);
           if(_listensock==-1){
              //绑定失败
              std::cerr<<"Create Socket Fail!"<<strerror(errno)<<std::endl;
              exit(SOCKET_ERR);
           }

           std::cout<<"Create Socket Success!"<<_listensock<<std::endl;

          //2 绑定端口号和IP地址
          struct sockaddr_in local;
          bzero(&local,sizeof(local));
          local.sin_family = AF_INET;
          local.sin_addr.s_addr = INADDR_ANY;//绑定任意可用IP地址
          local.sin_port = htons(_port);

          if(bind(_listensock,(const sockaddr*)&local,sizeof(local))){

            std::cout<<"Bind IP&&Port Fali:"<<strerror(errno)<<std::endl;
            exit(BIND_ERR);

          }
         
         //3. 监听
         if(listen(_listensock,backlog) == -1){
            std::cerr << "Listen Fail!" << strerror(errno) << std::endl;
            //新增一个报错
            exit(LISTEN_ERR);
         }
         std::cout<<"Listen Success!"<<std::endl;
         
        }

        // 启动服务器
        void StartServer(){
            
            while(!_quit){
                //1 处理连接请求
                struct sockaddr_in client;
                socklen_t len=sizeof(client);

                int sock=accept(_listensock,(struct sockaddr*)&client,&len);

                //2 如果连接失败 继续尝试连接
                if(sock==-1){
                  std::cerr<<"Accept Fail!"<<strerror(errno)<<std::endl;
                  continue;
                }

                //连接成功,获取客户端信息
                std::string clientip=inet_ntoa(client.sin_addr);
                uint16_t clientport= ntohs(client.sin_port);

                std::cout<<"Server accept"<<clientip + "-"<<clientport<<sock<<" from "<<_listensock<<" success!"<<std::endl;

                //3 这里因为是字节流传递,一般而言我们会自己写一个函数
                Service(sock,clientip,clientport);
            }

        }

    private:
        int _listensock; // 套接字(存疑)
        uint16_t _port; // 端口号
        bool _quit; // 判断服务器是否结束运行
    };
}
1.3.2.2 业务处理

对于 TCP 服务器来说,它是面向字节流传输的,我们之前使用的文件相关操作也是面向字节流,凑巧的是在 Linux 中网络是以挂接在文件系统的方式实现的,种种迹象表明:可以通过文件相关接口进行通信

  • read 从文件中读取信息(接收消息)
  • write 向文件中写入信息(发送消息)

这两个系统调用的核心参数是 fd文件描述符),即服务器与客户端在连接成功后,获取到的 socket 套接字,所以接下来可以按文件操作的套路,完成业务处理

Service() 业务处理函数 — 位于 server.hpp 服务器头文件中的 server

  void Service(int sock,const std::string& clientip,const uint16_t& clientport){

            char buff[1024];
            std::string who=clientip + "-" + std::to_string(clientport);
            while(true){
                //以C语言格式读取,预留'\0'的位置
                ssize_t n = read(sock,buff,sizeof(buff)-1);
                if(n>0){
                //读取成功
                std::cout<<"Server get: "<<buff<<" from "<<who<<std::endl;
                //实际处理可以交给上层逻辑指定
                std::string respond = _func(buff);
                //发送给服务器
                write(sock,buff,strlen(buff));
               }
               else if(n==0){

                //表示当前读到了文件末尾,结束读取
                std::cout<<"Client "<<who<<" "<<sock<<" quit!"<<std::endl;
                close(sock);
                break;
               }
               else{
                 // 读取出问题(暂时)
                  std::cerr << "Read Fail!" << strerror(errno) << std::endl;
                  close(sock); // 关闭文件描述符
                   break;
               }
            }
        }
1.3.2.2.1 回调函数

为了更好的实现功能解耦,这里将真正的业务处理函数交给上层处理,编写完成后传给 TcpServer 对象即可,当然,在 TcpServer 类中需要添加对应的类型

这里设置回调函数的返回值为 string,参数同样为 string

server.hpp 服务器头文件

 #pragma once

#include<iostream>
#include<cerrno>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include "err.hpp"
#include<cstring>
#include <unistd.h>
#include<functional>

namespace My_server{

    const uint16_t default_port = 8888; // 默认端口号
    const int backlog=32; //全连接队列的最大长度
    
    using func_t = std::function<std::string(std::string)>;
    class server{
    public:

        server(const func_t &func,const uint16_t port = default_port)
            :_func(func)
            ,_port(port)
            ,_quit(false)
        {}

        ~server()
        {}

        // 初始化服务器
        void InitServer(){

          //1 创建套接字
           _listensock = socket(AF_INET,SOCK_STREAM,0);
           if(_listensock==-1){
              //绑定失败
              std::cerr<<"Create Socket Fail!"<<strerror(errno)<<std::endl;
              exit(SOCKET_ERR);
           }

           std::cout<<"Create Socket Success!"<<_listensock<<std::endl;

          //2 绑定端口号和IP地址
          struct sockaddr_in local;
          bzero(&local,sizeof(local));
          local.sin_family = AF_INET;
          local.sin_addr.s_addr = INADDR_ANY;//绑定任意可用IP地址
          local.sin_port = htons(_port);

          if(bind(_listensock,(const sockaddr*)&local,sizeof(local))){

            std::cout<<"Bind IP&&Port Fali:"<<strerror(errno)<<std::endl;
            exit(BIND_ERR);

          }
         
         //3. 监听
         if(listen(_listensock,backlog) == -1){
            std::cerr << "Listen Fail!" << strerror(errno) << std::endl;
            //新增一个报错
            exit(LISTEN_ERR);
         }
         std::cout<<"Listen Success!"<<std::endl;
         
        }

        // 启动服务器
        void StartServer(){
            
            while(!_quit){
                //1 处理连接请求
                struct sockaddr_in client;
                socklen_t len=sizeof(client);

                int sock=accept(_listensock,(struct sockaddr*)&client,&len);

                //2 如果连接失败 继续尝试连接
                if(sock==-1){
                  std::cerr<<"Accept Fail!"<<strerror(errno)<<std::endl;
                  continue;
                }

                //连接成功,获取客户端信息
                std::string clientip=inet_ntoa(client.sin_addr);
                uint16_t clientport= ntohs(client.sin_port);

                std::cout<<"Server accept"<<clientip + "-"<<clientport<<sock<<" from "<<_listensock<<" success!"<<std::endl;

                //3 这里因为是字节流传递,一般而言我们会自己写一个函数
                Service(sock,clientip,clientport);
            }
        }

        void Service(int sock,const std::string& clientip,const uint16_t& clientport){

            char buff[1024];
            std::string who=clientip + "-" + std::to_string(clientport);
            while(true){
                //以C语言格式读取,预留'\0'的位置
                ssize_t n = read(sock,buff,sizeof(buff)-1);
                if(n>0){
                //读取成功
                std::cout<<"Server get: "<<buff<<" from "<<who<<std::endl;
                //实际处理可以交给上层逻辑指定
                std::string respond = _func(buff);
                //发送给服务器
                write(sock,buff,strlen(buff));
               }
               else if(n==0){

                //表示当前读到了文件末尾,结束读取
                std::cout<<"Client "<<who<<" "<<sock<<" quit!"<<std::endl;
                close(sock);
                break;
               }
               else{
                 // 读取出问题(暂时)
                  std::cerr << "Read Fail!" << strerror(errno) << std::endl;
                  close(sock); // 关闭文件描述符
                   break;
               }
            }
        }

    private:
        int _listensock; // 套接字(存疑)
        uint16_t _port; // 端口号
        bool _quit; // 判断服务器是否结束运行
        func_t _func;// 回调函数
    };
}
1.3.2.2.2 server.cc文件

对于当前的 TCP 网络程序(字符串回响)来说,业务处理函数逻辑非常简单,无非就是直接将客户端发送过来的消息,重新转发给客户端

server.cc 服务器源文件

//智能指针头文件
#include<memory>
#include"server.hpp"
#include<string>

using namespace My_server;
// 业务处理回调函数(字符串回响)
std::string echo(std::string request){
    return request;
}

int main(){

    std::unique_ptr<server> usvr(new server(echo));
     
    usvr->InitServer();
    
    usvr->StartServer();

    return 0;
}

  尝试编译并运行服务器,可以看到当前 bash 已经被我们的服务器程序占用了,重新打开一个终端,并通过 netstat 命令查看网络使用情况(基于 TCP 协议)

1.4 客户端

1.4.1 初始化客户端

 对于客户端来说,服务器的 IP 地址与端口号是两个不可或缺的元素,因此在客户端类中,  server_ipserver_port 这两个成员是少不了的,当然得有 socket 套接字

初始化客户端只需要干一件事:创建套接字,客户端是主动发起连接请求的一方,也就意味着它不需要使用 listen 函数设置为监听状态

注意: 客户端也是需要 bind 绑定的,但不需要自己手动绑定,由操作系统帮我们自动完成

client.hpp 客户端头文件

#pragma once

#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"err.hpp"
#include<cerrno>
#include<cstring>

namespace My_client{
   
   class client{
     public:
        client(const std::string& ip,const uint16_t port)
         :server_ip(ip)
         ,server_port(port)
        {}

        ~client(){}
        
        //初始化客户端
        void InitClient(){

           // 1. 创建套接字
            _sock = socket(AF_INET, SOCK_STREAM, 0);
            if (_sock == -1)
            {
                std::cerr << "Create Socket Fail!" << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }   
            std::cout << "Create Sock Succeess! " << _sock << std::endl;
            

        }

        // 启动客户端
        void StartClient(){}

     private:
       int _sock;// 套接字
       std::string server_ip;//服务器ip
       uint16_t server_port; //服务器端口号

   };
}

1.4.2 启动客户端

1.4.2.1 尝试进行连接

  因为 TCP 协议是面向连接的,服务器已经处于处理连接请求的状态了,客户端现在需要做的就是尝试进行连接,使用 connect 函数进行连接。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数解读:

  • sockfd 需要进行连接的套接字
  • addr 服务器的 sockaddr 结构体信息
  • addrlen 服务器的 sockaddr 结构体大小

返回值:连接成功返回 0,连接失败返回 -1.

  在连接过程中,可能遇到很多问题,比如 网络传输失败、服务器未启动 等,这些问题的最终结果都是客户端连接失败,如果按照之前的逻辑(失败就退出),那么客户端的体验感会非常不好,因此在面对连接失败这种常见问题时,客户端应该尝试重连,如果重连数次后仍然失败,才考虑终止进程

注意: 在进行重连时,可以使用 sleep() 等函数使程序睡眠一会,给网络恢复留出时间

StartClient() 启动客户端函数 — 位于 client.hpp 中的client 类.

#pragma once

#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"err.hpp"
#include<cerrno>
#include<cstring>
#include<unistd.h>
namespace My_client{
   
   class client{
     public:
        client(const std::string& ip,const uint16_t port)
         :server_ip(ip)
         ,server_port(port)
        {}

        ~client(){}
        
        //初始化客户端
        void InitClient(){

           // 1. 创建套接字
            _sock = socket(AF_INET, SOCK_STREAM, 0);
            if (_sock == -1)
            {
                std::cerr << "Create Socket Fail!" << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }   
            std::cout << "Create Sock Succeess! " << _sock << std::endl;
            

        }

        // 启动客户端
        void StartClient(){
          
          //填充服务器的sockaddr_int 结构体信息
          struct sockaddr_in server;
          socklen_t len=sizeof(server);
          bzero(&server,len);
          server.sin_family = AF_INET;
          inet_aton(server_ip.c_str(), &server.sin_addr); // 将点分十进制转化为二进制IP地址的另一种方法
          server.sin_port = htons(server_port);

          //尝试重连五次
          int n=5;
          while(n){
            int ret = connect(_sock,(const struct sockaddr*)&server,len);
            if(ret==0){
               // 连接成功,可以跳出循环
               break;
            }
                 // 尝试进行重连
             std::cerr << "网络异常,正在进行重连... 剩余连接次数: " << --n << std::endl;
             sleep(1);
          }

            // 如果剩余重连次数为 0,证明连接失败
          if(n == 0)
         {
           std::cerr << "连接失败! " << strerror(errno) <<    std::endl;
           close(_sock);
           exit(CONNECT_ERR);//新加错误标识符

          }

           // 连接成功
          std::cout << "连接成功!" << std::endl;

         // 进行业务处理
         // Service();
        }

     private:
       int _sock;// 套接字
       std::string server_ip;//服务器ip
       uint16_t server_port; //服务器端口号

   };
}
1.4.2.2 业务处理

客户端在进行业务处理时,同样可以使用 readwrite 进行网络通信

Service() 业务处理函数 — 位于 client.hpp 客户端头文件中的 TcpClient

// 业务处理
void Service()
{
    char buff[1024];
    std::string who = server_ip + "-" + std::to_string(server_port);
    while(true)
    {
        // 由用户输入信息
        std::string msg;
        std::cout << "Please Enter >> ";
        std::getline(std::cin, msg);

        // 发送信息给服务器
        write(_sock, msg.c_str(), msg.size());
        // 接收来自服务器的信息
        ssize_t n = read(_sock, buff, sizeof(buff) - 1);
        if(n > 0)
        {
            // 正常通信
            buff[n] = '\0';
            std::cout << "Client get: " << buff << " from " << who << std::endl;
        }
        else if(n == 0)
        {
            // 读取到文件末尾(服务器关闭了)
            std::cout << "Server " << who  << " quit!" << std::endl;
            close(_sock); // 关闭文件描述符
            break;
        }
        else
        {
            // 读取异常
            std::cerr << "Read Fail!" << strerror(errno) << std::endl;
            close(_sock); // 关闭文件描述符
            break;
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python编程玩转二维码

文章目录 Python编程玩转二维码第一部分&#xff1a;背景介绍第二部分&#xff1a;qrcode库是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;库函数使用方法第五部分&#xff1a;场景应用第六部分&#xff1a;常见Bug及解决方案第七部分…

动力学重构/微分方程参数拟合 - 基于模型

这一篇文章&#xff0c;主要是给非线性动力学&#xff0c;对微分方程模型参数拟合感兴趣的朋友写的。笼统的来说&#xff0c;这与混沌系统的预测有关&#xff1b;传统的机器学习的模式识别虽然也会谈论预测结果&#xff0c;但他们一般不会涉及连续的预测。这里我们考虑的是&…

Git ignore、exclude for TortoiseGit 小结

1.Ignore Type&#xff1a;忽略类型&#xff0c;也即忽略规则&#xff0c;如何去忽略文件? 1.1.Ignore item(s) only in containing folder(s)&#xff1a;仅忽略在包含在文件夹中项目。 仅忽略该文件夹下选定的patterns。the patterns其实就是文件类型&#xff0c;比如.txt后…

文本美学:text-image打造视觉吸引力

当我最近浏览 GitHub 时&#xff0c;偶然发现了一个项目&#xff0c;它能够将文字、图片和视频转化为文本&#xff0c;我觉得非常有趣。于是我就花了一些时间了解了一下&#xff0c;发现它的使用也非常简单方便。今天我打算和家人们分享这个发现。 项目介绍 话不多说&#xf…

面试(05)————Redis篇

目录 一、项目中哪些地方使用了redis 问题一&#xff1a;发生了缓存穿透该怎么解决&#xff1f; 方案一&#xff1a;缓存空数据 方案二&#xff1a;布隆过滤器 模拟面试 问题二&#xff1a; 发生了缓存击穿该怎么解决&#xff1f; 方案一&#xff1a;互斥锁 方案二&#xff…

【GPTs分享】GPTs分享之Image Recreate | img2img​

简介 该GPT是一个专门用于图像编辑、重建和合并的工具。它通过详细的自动图像描述和生成&#xff0c;帮助用户从源图像中重现或修改图像。此工具设计用于为视障用户提供图像内容的详细描述&#xff0c;并生成全新的图像&#xff0c;以满足特定的视觉需求。 主要功能 \1. 图像…

Clion 2023.1.5 最新详细破解安装教程

CLion 最大的优点是跨平台&#xff0c;在Linux、Mac、Windows 上都可以运行。CLion 还同时支持 GCC、Clang、MSVC 这 3 种编译器&#xff0c;使用 CLion 编写程序&#xff0c;程序员可以根据需要随意切换使用的编译器。 第一步: 下载最新的 Clion 2023.1.5 版本安装包 我们先…

掌握字幕艺术:pysrt 库指南

文章目录 掌握字幕艺术&#xff1a;pysrt 库指南第一部分&#xff1a;背景介绍第二部分&#xff1a;库是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;库函数使用方法第五部分&#xff1a;场景应用第六部分&#xff1a;常见Bug及解决方…

Hive基础3

一、表的分区 大数据开发数据量较大&#xff0c;在进行数据查询计算时&#xff0c;需要对数据进行拆分&#xff0c;提升的查询速度 1-1 单个分区 单个分区是创建单个目录 -- 创建表指定分区&#xff0c;对原始数据进行分区保存 create table new_tb_user(id int,name string,ag…

Linux嵌入式驱动开发-linux中断

文章目录 linux中断原理中断控制器GIC中断源分类 中断ID、中断线(中断号/中断源)中断ID中断线(中断号/中断源)MX6U中断源 上半部与下半部&#xff08;顶半部和底半部&#xff09;下半部实现机制linux软中断注册软中断触发软中断初始化软中断 taskletasklet_init&#xff1a;初始…

【AIGC】文本与音频生成引领行业革新

AIGC技术崛起 一、AIGC技术概述二、文本生成&#xff1a;结构化与创作型并进三、实例与代码解析四、音频生成&#xff1a;语音合成技术大放异彩五、结语 在科技的浪潮中&#xff0c;人工智能与大数据的结合不断推动着时代的进步。其中&#xff0c;AIGC&#xff08;Artificial I…

安居水站:水站经营秘籍:年入30万不是梦。水站创业指南。

在这个快节奏的社会里&#xff0c;初创企业家们总是在寻找一条明路&#xff0c;以在竞争激烈的市场中立足。为了帮助他们更好地实现这一目标&#xff0c;我根据经验决定制定一份水站经营指导手册。这份手册将详细阐述如何从零起步&#xff0c;如何运营&#xff0c;如何进行市场…

智慧浪潮下的产业园区:解读智慧化转型如何打造高效、绿色、安全的新产业高地

随着信息技术的飞速发展&#xff0c;智慧化转型已经成为产业园区发展的重要趋势。在智慧浪潮的推动下&#xff0c;产业园区通过集成应用物联网、大数据、云计算、人工智能等先进技术手段&#xff0c;实现园区的智慧化、高效化、绿色化和安全化&#xff0c;从而打造成为新产业高…

x-cmd ai | x openai - 用于发送 openai API 请求,以及与 ChatGPT 对话

介绍 Openai 模块是 Openai 大模型 Chatgpt 3 和 ChatGPT 4 命令行实现。x-cmd 提供了多个不同平台间多种 AI 大模型的调用能力。无论是本地模型还是 Web 服务上的模型&#xff0c;用户都可以在不同的 AI 大模型间直接无缝切换&#xff0c;并能把之前的聊天记录发送给新的大模…

【PCL】教程conditional_euclidean_clustering 对输入的点云数据进行条件欧式聚类分析...

[done, 3349.09 ms : 19553780 points] Available dimensions: x y z intensity 源点云 Statues_4.pcd 不同条件函数output.pcd 【按5切换到强度通道可视化】 终端输出&#xff1a; Loading... >> Done: 1200.46 ms, 19553780 points Downsampling... >> Done: 411…

【JavaWeb】Day50.Mybatis的XML配置文件

XML配置文件规范 使用Mybatis的注解方式&#xff0c;主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能&#xff0c;建议使用XML来配置映射语句&#xff0c;也就是将SQL语句写在XML配置文件中。 在Mybatis中使用XML映射文件方式开发&#xff0c;需要符合一定的规…

Nginx解决跨域访问难题:轻松实现跨域资源共享!

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ 跨域资源共享&#xff08;CORS&#xff0c;Cross-Origin Resource Sharing&#xff09;是一种网络浏览器的安全功能&#xff0c;它限制了一个源&#xff08;域、协议和端口…

学习空间转换-3D转换

1.什么是空间转换&#xff1f; 使用的是transform属性实现元素在空间内的位移&#xff0c;旋转&#xff0c;缩放等效果。 空间&#xff1a;是从坐标轴角度定义的。x,y,z三条坐标轴构成的一个立体空间&#xff0c;Z轴位置与视线方向相同。 所以空间转换也被叫做3D转换 语法&a…

docker+awk=无敌?!

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 dockerawk无敌&#xff1f;&#xff01; 前言需求分析容器间通过容器名称访问脚本实现一键部署命令解释 前言 当今软件开发的世界充满了数据&#xff0c;而 Docker 则是许多开发者首选的容器化解决方…

嵌入式学习55-ARM4(ADC和I²C)

1、什么是ADC,模拟量和数字量有什么特点&#xff1f; ADC&#xff1a; …