【Linux网络编程三】Udp套接字编程网络应用场景

news2024/11/28 3:36:42

【Linux网络编程三】Udp套接字编程网络应用场景

  • 应用场景一:远程命令执行
  • 应用场景二:与Windos端相互通信
  • 应用场景三:简单聊天
    • 1.多线程化
    • 2.输入输出分开

应用场景一:远程命令执行

简单的服务器上一篇已经完成,接下来我,们就可以加一些应用场景了。我们知道客户端发送消息给服务器,服务器对消息加工处理再发送回去。但谁规定客户端只能发送消息的呢?我们可以发送一些命令,让服务帮我执行,然后将执行结果再发送回来。

服务器的对数据的加工处理动作是可以分离出来的,实现代码层面的分层。
通过函数回调的方法,由上层来决定加工处理动作。
在这里插入图片描述

所以我们只需要在服务器内部定义一个函数指针,将客户端发送的数据传递给函数。调用该函数,由上层传入函数来实现回调。

所以我们想实现对客户端佛发送的命令进行执行,然后将执行结果再发送回去。

在这里插入图片描述
我们利用popen()这个系统调用接口。它可以将传递进行的以字符串形式的命令,通过程序替换的形式执行。并且是自动创建子进程,让子进程程序替换,并且创建父子管道,将执行的结果通过管道返回回来。
返回的结果存放在一个文件里,我们可以通过文件描述符来访问。
在这里插入图片描述


#include "Udpserver.hpp"
#include <memory>
#include <cstdio>
#include <stdlib.h>

std::string ExcuteCommand(const std::string& cmd)
{
    std::cout<<"get a request cmd: "<<cmd<<std::endl;
    //服务器端接收到命令后,会先打印获取到一个命令
    //获取到命令后,就让服务器进行运行处理

    FILE* fp=popen(cmd.c_str(),"r");
    //popen会自动创建子进程,让子进程进行程序替换,运行字符串命令,然后会建立父子间的管道,将运行结果发送给父进程
    if(fp==nullptr)
    {
        perror("popen");
        return "error";
    }
    std::string reslut;
    char buffer[1024];
    while(true)
    {
        char*r=fgets(buffer,sizeof(buffer),fp);//按行读取,读取一行
        if(r==nullptr)break;
        reslut+=r;
    }
    pclose(fp);
    return reslut;
}
*/
#include "Udpserver.hpp"
#include <memory>
#include <cstdio>

void Usage(std::string proc)
{
    std::cout<<"\n\rUsage: "<<proc<<" port[1024+]\n"<<std::endl;
}
//服务器进程,启动时,按照./Udpserver+port的形式传递
int main(int args,char* argv[])
{
    if(args!=2)
    {
         Usage(argv[0]);
         exit(0);
    }

    uint16_t port=std::stoi(argv[1]);
    std::unique_ptr<Udpserver> svr(new Udpserver(port));//首先创建一个服务器对象指针
    //智能指针,用一个UdpServer指针来管理类对象
    svr->Init();//初始化服务器
    
    svr->Run(ExcuteCommand);//启动服务器
    return 0;
} 

在这里插入图片描述

通过这个场景,我们就应该能够理解Xshell的本质就是一个客户端,而启动时连接ip登入密码就是在连接服务器。然后我们输入的命令,将发送给xhell服务器,然后服务器将执行结果再发送给我们。
在这里插入图片描述

应用场景二:与Windos端相互通信

我们在Linux下写的网络通信其实在window下也是可以进行通信的,虽然两个操作系统不同,但是网络协议栈是相同的,所以它们是具有相同的接口的。
只不过在Windows下还需要几个windows库要使用,其他的都跟linux下是一样的。所以我们是可以在Linux下和Windows下互相通信的,让linux下程序充当服务器,让windows下的程序充当客户端。

在这里插入图片描述
以上就是在windows下通信需要的准备工作,需要包含一个新的头文件,要注意必须先包含该头文件,在包含下面的lib32库。
然后对库进行初始化。最后不使用了就关闭库。中间就是我们的网络通信部分。

这里还有一个细节,就是在windows下,将字符转换成int字节的函数inet_pton()会显示没有定义吗,但是是定义成功的,所以我们选择忽略这个警告:
在这里插入图片描述

【Windows下的客户端】


#include <iostream>
#include <WinSock2.h>
#include <Windows.h>
#include <cstdlib>
#include <cstdio>
#include <string>
#pragma comment(lib,"ws2_32.lib")

#pragma warning(disable:4996)
std::string serverip = "112.124.70.128";
//一般app客户端内置服务器的ip地址,这里我们就直接连接我们的linux服务器ip地址
uint16_t serverport = 3555;
int main()
{

	WSADATA wsd;
	WSAStartup(MAKEWORD(2, 2), &wsd);
    
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(serverip.c_str()); // 将string类型转换成int类型,并且是网络字节序
    //在windos下回存在警告,忽略即可
    server.sin_port = htons(serverport);
    int len = sizeof(server);

    // 1.创建套接字---本质就是打开网络文件
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd ==SOCKET_ERROR )
    {
        std::cout << "socket create err" << std::endl;
        return 1;
    }
    // 创建成功
    // 2.需要绑定吗?系统会给我自动绑定,首次发送的时候就会绑定

    // 3.往服务器的套接字里发送消息--需要知道服务器的ip和端口号,目的ip和目的port,将ip和port填入结构体对象里


    char outbuffer[1024];
    std::string message;
    while (true)
    {
        std::cout << "Please enter@ ";
        std::getline(std::cin, message);
        //1.发送给服务器
        sendto(sockfd, message.c_str(), message.size(), 0, (const struct sockaddr*)&server, len);

        struct sockaddr_in temp;
        int l = sizeof(temp);
        //2.接收服务器的应答

        int s = recvfrom(sockfd, outbuffer, 1023, 0, (struct sockaddr*)&temp, &l);
        if (s > 0)
        {
            //接收成功
            outbuffer[s] = 0;
            std::cout << outbuffer << std::endl;
        }

    }
    //close(sockfd);
    closesocket(sockfd);
	WSACleanup();
	return 0;
}

在这里插入图片描述
Linux和windows下的编码不同所以在windows下接收linux下加工的消息就会存在不同。
【Linux下的服务器】

@ -0,0 +1,103 @@
#pragma once

#include "Log.hpp"
#include <iostream>
#include <string>
#include <strings.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
std::string defaultip = "0.0.0.0";
uint16_t defaultport = 8080;
Log lg; // 日志,默认往显示屏打印
typedef std::function<std::string(const std::string&)> func_t;//相当于定义了一个函数指针
//返回值是string类型,函数参数也是string类型,利用函数回调的方法,将服务器端对数据的处理操作进行分离,由上层传递的函数来决定如何处理
enum
{
    SOCKET_ERR = 1,
    BIND_ERR
};
class Udpserver
{
public:
    Udpserver(const uint16_t &port = defaultport, std::string &ip = defaultip) : _sockfd(0), _port(port), _ip(ip)
    {
    }
    void Init()
    {
        // 1.创建udp套接字,本质就是打开网络套接字文件
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0) // 表示创建失败
        {
            lg(Fatal, "socket create error,socket: %d", _sockfd);
            exit(SOCKET_ERR); // 创建失败之间退出
        }
        // 创建成功
        lg(Info, "socket create success,socket: %d", _sockfd);
        // 2.绑定服务器的套接信息,比如ip和端口号
        // 在绑定套接信息之前,需要先将对应的结构体对象填充完毕sock_addr
        struct sockaddr_in local;                       // 网络通信类型
        bzero(&local, sizeof(local));                   // 将内容置为0
        local.sin_family = AF_INET;                     // 网络通信类型
        local.sin_port = htons(_port);                  // 网络通信中,端口号需要不断发送,所以需要符合网络字节序,主机--->网络字节序
        local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 需要将string类型的ip转换成int类型,并且还需要满足网络字节序的要求
        socklen_t len = sizeof(local);
        // 以上只是将要绑定的信息填充完毕,套接字(网络文件)而还没有绑定套接信息

        if (bind(_sockfd, (const struct sockaddr *)&local, len) < 0) // 绑定失败
        {
            lg(Fatal, "bind sockfd error,errno:%d,err string:%s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "bind sockfd success,errno:%d,err string:%s", errno, strerror(errno)); // 绑定成功
    }
    void Run(func_t func) // 服务器是一旦启动不会退出,服务器接收消息,并发送答应
    {
        // 1.接收信息
        char buffer[SIZE];

        while (true)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            // 服务器接收到消息,它还需要知道谁给它发送的,为了后续将应答返回过去
            // 利用一个输出型参数,将对方的网络信息填充到里面
            ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr *)&client, &len);
            if (n < 0)
            {
                lg(Warning, "recvfrom sockfd err,errno: %d, err string %s", errno, strerror(errno));
                continue;
            }
            // 读取成功,将网络文件里的消息读取到buffer里
            buffer[n] = 0; // 字符串形式
            
            // 2.加工处理
            
            // std::string info = buffer;
            // std::string echo_string  = "server echo# " + info;
            std::string info=buffer;
            std::string echo_string=func(info);
            //将接收的信息由外层函数进行处理
           
            

            // 3.将应答发送回去
            // 发送给谁呢?服务器知道吗?服务器知道!因为在接收消息时,服务器就用一个输出型参数,将客户端的网络消息保存下来了
            sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, (const struct sockaddr *)&client, len);
        }
    }
    ~Udpserver()
    {
        if (_sockfd > 0)
            close(_sockfd);
    }

private:
    int _sockfd;     // 套接字文件描述符
    std::string _ip; // 我们习惯用string类型的ip地址
    uint16_t _port;  // 服务器进程的端口号
};

应用场景三:简单聊天

我们还可以制作一个简单的聊天软件,平常我们往群里输入一个消息,qq群里上就会显示我发送了一条消息。并且还标明了是谁发送的。比如李四往群里发送:“hello world”。群里的人都能看到这条消息:李四:“hello world”。

当客户端给服务器发送消息时,服务器不仅能接收到客户端发送的内容,还可以知道客户端的网络消息(客户端的ip和端口号等),也就是知道是谁发送它。所以这里我们可以利用ip+端口号来表示用户。当用户往服务器发送消息时,服务器就将该用户的ip地址+端口号来表示该用户,然后将以[ip+port]:消息再发送回去。显示在屏幕上。
在这里插入图片描述

注意:客户端发送消息给服务器,服务器可以获取到客户端的ip地址和端口号等网络信息,但这些信息都是网络字节序的,如果服务器想使用,需要先转换成用户字节序的。
1.可以使用ntohs()接口将端口号从网络字节序转用户字节序
2.可以使用inet_ntoa()将int类型的ip地址转string类型的ip地址,并转换成用户字节序。

还有就是我往群里发送的消息,qq群里的人是不是都能看到呀。所以我们应该让所有连接服务器的客户端用户都能看到我发送的消息。而他们往群里发送的消息,我也可以看到。

所以我们需要将所有在线的客户端都能看到消息,我们需要制作一个在线用户列表。
我们用一个哈希表来存储在线用户。当客户端用户发送消息时,服务器端就会接收消息,根据用户的ip地址来到哈希表里检测,哈希表里是否有该用户,如果没有,就添加进去,如果有则什么都不做。这样就将用户添加到哈希表里了,所有发送过消息的客户端用户都会被添加进去,但是同一个ip的只能添加一个客户端。
在这里插入图片描述

服务器接收消息,并加工处理后,就可以发送给所有在线的客户端用户了,广播发送给所有用户,那么这些用户在哪呢?在哈希表里!(只要有新客户端用户发送消息了,就会将该客户端ip添加到哈希表里,哈希表kv结果,k表示ip地址,v表示客户端的网络信息)

在这里插入图片描述

#pragma once

#include "Log.hpp"
#include <iostream>
#include <string>
#include <strings.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include <unordered_map>
std::string defaultip = "0.0.0.0";
uint16_t defaultport = 8080;
Log lg;                                                                                                   // 日志,默认往显示屏打印
typedef std::function<std::string(const std::string &info, uint16_t &port, const std::string ip)> func_t; // 相当于定义了一个函数指针
// 返回值是string类型,函数参数也是string类型,利用函数回调的方法,将服务器端对数据的处理操作进行分离,由上层传递的函数来决定如何处理
enum
{
    SOCKET_ERR = 1,
    BIND_ERR
};
class Udpserver
{
public:
    Udpserver(const uint16_t &port = defaultport, std::string &ip = defaultip) : _sockfd(0), _port(port), _ip(ip)
    {
    }
    void Init()
    {
        // 1.创建udp套接字,本质就是打开网络套接字文件
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0) // 表示创建失败
        {
            lg(Fatal, "socket create error,socket: %d", _sockfd);
            exit(SOCKET_ERR); // 创建失败之间退出
        }
        // 创建成功
        lg(Info, "socket create success,socket: %d", _sockfd);
        // 2.绑定服务器的套接信息,比如ip和端口号
        // 在绑定套接信息之前,需要先将对应的结构体对象填充完毕sock_addr
        struct sockaddr_in local;                       // 网络通信类型
        bzero(&local, sizeof(local));                   // 将内容置为0
        local.sin_family = AF_INET;                     // 网络通信类型
        local.sin_port = htons(_port);                  // 网络通信中,端口号需要不断发送,所以需要符合网络字节序,主机--->网络字节序
        local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 需要将string类型的ip转换成int类型,并且还需要满足网络字节序的要求
        socklen_t len = sizeof(local);
        // 以上只是将要绑定的信息填充完毕,套接字(网络文件)而还没有绑定套接信息

        if (bind(_sockfd, (const struct sockaddr *)&local, len) < 0) // 绑定失败
        {
            lg(Fatal, "bind sockfd error,errno:%d,err string:%s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "bind sockfd success,errno:%d,err string:%s", errno, strerror(errno)); // 绑定成功
    }
    void Checkuser(struct sockaddr_in &client,uint16_t &clientport,const std::string &clientip)
    {
       
         //用该ip检测哈希表里是否存在该用户
         auto iter=online_user.find(clientip);
         if(iter==online_user.end())//说明没有找到, 是新用户
         {
              online_user.insert({clientip,client});
            std::cout<<"add a user"<<":["<<clientip<<":"<<clientport<<"]"<<std::endl; 
         }
         //如果不是新用户,那么什么都不干
        
    }
    void Broadcast(const std::string info,uint16_t &clientport,const std::string &clientip)
    {
          //将消息加工处理广播发送给所有在线的用户,而这些用户都在哈希表里
          for(auto& user:online_user)
          {
            std::string message="[处理客户端数据 ";
            message+=clientip;
            message+=":";
            message+=std::to_string(clientport);
            message+="]";
            message+=info;
            
            sendto(_sockfd, message.c_str(), message.size(), 0, (const struct sockaddr *)&(user.second), sizeof(user.second));
          }
    }
    void Run(/*func_t func*/) // 服务器是一旦启动不会退出,服务器接收消息,并发送答应
    {
        // 1.接收信息
        char buffer[SIZE];

        while (true)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            // 服务器接收到消息,它还需要知道谁给它发送的,为了后续将应答返回过去
            // 利用一个输出型参数,将对方的网络信息填充到里面
            ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&client, &len);
            if (n < 0)
            {
                lg(Warning, "recvfrom sockfd err,errno: %d, err string %s", errno, strerror(errno));
                continue;
            }
            // 读取成功,将网络文件里的消息读取到buffer里
            buffer[n] = 0; // 字符串形式


              
            // 服务器想知道是谁给它发送消息的//①获取到发送者的消息②也获取到发送者的套接字信息,所以我们怎么知道是谁发送过来的呢?
            uint16_t clientport = ntohs(client.sin_port);      // 注意port是网络字节序,需要转成用户字节序
            std::string clientip = inet_ntoa(client.sin_addr); // ip是网络字节序的int类型,需要转换成string类型
            Checkuser(client,clientport,clientip);//在线用户列表 
            std::string info = buffer;

            
            //接收消息后,就广播发送给所有在线的人,并告诉是谁发送的
            Broadcast(info,clientport,clientip);
              



            // std::string info = buffer;
            // std::string echo_string  = "server echo# " + info;

            // std::string info=buffer;
            // std::string echo_string=func(info,clientport,clientip);
            // 将接收的信息由外层函数进行处理

            // 3.将应答发送回去
            // 发送给谁呢?服务器知道吗?服务器知道!因为在接收消息时,服务器就用一个输出型参数,将客户端的网络消息保存下来了
            //sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, (const struct sockaddr *)&client, len);
        }
    }
    ~Udpserver()
    {
        if (_sockfd > 0)
            close(_sockfd);
    }

private:
    int _sockfd;     // 套接字文件描述符
    std::string _ip; // 我们习惯用string类型的ip地址
    uint16_t _port;  // 服务器进程的端口号

    std::unordered_map<std::string, struct sockaddr_in> online_user; // 网上在线列表
    // 服务器收到一个客户信息,就要检测这个客户是不是新用户,如果是就添加进去
};

1.多线程化

不过客户端是存在问题的,什么问题呢?用户是不是也能看到别人发送的消息?
是的,但是目前的客户端要求用户必须先输入,才能获取服务器发送的消息,也就是我不输入,也就看不到别人的消息。只有我输入了。而正常聊天应该是,我不输入,我也能看到对方发送的消息应该。
这就要求,输入和输出两个动作要同时运行,我们可以使用多线程,让两个线程各自执行,一个线程执行发送,一个线程执行读取,这样,就算我输入,也能接收到别人发送的消息。

在这里插入图片描述

【理论依据】:在这里插入图片描述

在这里插入图片描述
发送线程需要往套接字里发送,并且需要知道发送给谁,所以需要构建一个结构体对象封装套接字,和服务器网络信息。
接收线程需要从套接字里读取。通过结构体对象里的套接字。
所以我们可以利用该结构来作为线程函数的参数。让线程拿到。在之前先将内容初始填充。

在这里插入图片描述


#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace std;

#include <iostream>
#include <strings.h>
#include <sys/types.h>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

using namespace std;
// 客户端
void Usage(std::string proc)
{
    std::cout << "\n\r./Usage: " << proc << " serverip serverport\n"
              << endl;
}

struct PthreadData
{
    int sockfd;
    struct sockaddr_in server;
};
void *Sender(void *args)
{
    while (true)
    {
        PthreadData *pd = static_cast<PthreadData *>(args);
        socklen_t len = sizeof(pd->server);
        string message;
        cout << "Please enter@ ";
        getline(cin, message);
        // 1.发送给服务器
        sendto(pd->sockfd, message.c_str(), message.size(), 0, (const struct sockaddr *)&(pd->server), len);
    }
}
void *Revcer(void *args)
{
    while (true)
    {
        PthreadData *pd = static_cast<PthreadData *>(args);
        char outbuffer[1024];
        struct sockaddr_in temp;
        socklen_t l = sizeof(temp);
        // 2.接收服务器的应答

        ssize_t s = recvfrom(pd->sockfd, outbuffer, 1023, 0, (struct sockaddr *)&temp, &l);
        // 共用一个套接字,但不影响,是线程安全的
        if (s > 0)
        {
            // 接收成功
            outbuffer[s] = 0;
            cerr << outbuffer << endl;
        }
    }
}
// 启动客户端时要求是: ./Client 服务器ip 服务器port
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(0);
    }
    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);
    PthreadData pd;
    bzero(&(pd.server), sizeof(pd.server));
    pd.server.sin_family = AF_INET;
    pd.server.sin_addr.s_addr = inet_addr(serverip.c_str()); // 将string类型转换成int类型,并且是网络字节序
    pd.server.sin_port = htons(serverport);

    // 1.创建套接字---本质就是打开网络文件
    pd.sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (pd.sockfd < 0)
    {
        cout << "socket create err" << endl;
        return 1;
    }
    // 创建成功
    // 2.需要绑定吗?系统会给我自动绑定,首次发送的时候就会绑定

    // 3.往服务器的套接字里发送消息--需要知道服务器的ip和端口号,目的ip和目的port,将ip和port填入结构体对象里

    pthread_t sender, revcer;
    pthread_create(&sender, nullptr, Sender, &pd);
    pthread_create(&revcer, nullptr, Revcer, &pd);

    pthread_join(sender, nullptr);
    pthread_join(revcer, nullptr);

    close(pd.sockfd);
    return 0;
}

这样一个线程一直在读取,只要有人往套接字里发送消息了,服务器就能直接返回回来,我就可以获取到,不需要输入就可以获取到。因为另一个线程在输入。两个线程是并发的。
在这里插入图片描述

2.输入输出分开

上面还存在一个问题:输入和输出混乱,在同一个显示屏里混乱输出。体验感不好。
所以我们想让输入和输出分开显示。怎么做呢?通过终端!通过打开多个终端,让输入输出显示在不同的终端上。
在这里插入图片描述

首先就是让服务器端加工处理后的数据,利用错误输出流输出。而客户端发送消息默认输出在当前显示屏上。
然后再二号错误输出流重定向到一个新打开的终端显示器上。这样最后服务器发送回来的消息就会显示在新打开的终端上。而客户端输出,就默认输入在旧的终端。在这里插入图片描述

在这里插入图片描述

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

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

相关文章

前端小案例——动态导航栏文字(HTML + CSS, 附源码)

一、前言 实现功能: 这案例是一个具有动态效果的导航栏。导航栏的样式设置了一个灰色的背景&#xff0c;并使用flex布局在水平方向上平均分配了四个选项。每个选项都是一个li元素&#xff0c;包含一个文本和一个横向的下划线。 当鼠标悬停在选项上时&#xff0c;选项的文本颜色…

flask+pyinstaller实现mock接口,并打包到exe运行使用postman验证

flask代码 from flask import Flask, request, jsonifyapp Flask(__name__)app.route("/login", methods[POST]) def login():username request.json.get("username").strip() # 用户名password request.json.get("password").strip() # 密…

FastAdmin青动CRM-E售后

应用介绍 一款基于FastAdminThinkPHP和uniapp开发的CRM售后管理系统&#xff0c;旨在助力企业销售售后全流程精细化、数字化管理&#xff0c;主要功能&#xff1a;客户、合同、工单、任务、报价、产品、库存、出纳、收费&#xff0c;适用于&#xff1a;服装鞋帽、化妆品、机械机…

随机森林超参数的网格优化(机器学习的精华--调参)

随机森林超参数的网格优化&#xff08;机器学习的精华–调参&#xff09; 随机森林各个参数对算法的影响 影响力参数⭐⭐⭐⭐⭐几乎总是具有巨大影响力n_estimators&#xff08;整体学习能力&#xff09;max_depth&#xff08;粗剪枝&#xff09;max_features&#xff08;随机…

STM32--SPI通信协议(3)SPI通信外设

前言 硬件SPI&#xff1a;通过硬件电路实现&#xff0c;所以硬件SPI速度更快&#xff0c;有专门的寄存器和 库函数 &#xff0c;使用起来更方便。 软件SPI&#xff1a;也称模拟SPI&#xff0c;通过程序控制IO口电平模拟SPI时序实现&#xff0c;需要程序不断控制IO电平翻转&am…

网工每日一练(2月4日)

试题1 通过HFC网络实现宽带接入&#xff0c;用户端需要的设备是&#xff08;A&#xff09;&#xff0c;局端用于控制和管理用户的设备是&#xff08;D&#xff09;。 &#xff08;1&#xff09;A.Cable Modem B.ADSL Modem C.OLT D.CMTS &#xff08;2&#xff09;A. Cable Mo…

代码编辑器1.9.0

多线程&#xff01;&#xff01;&#xff01; #include <winsock2.h> #include <windows.h> #include <iostream> #include <stdlib.h> #include <string.h> #include <fstream> #include <conio.h> #include <stdio.h> #incl…

实现屏蔽 Ctrl + Alt + Del 、Ctrl + Shift + Esc 等热键(二)

目录 前言 一、概述 Winlogon 的 RPC 例程 二、Handler 函数的消息处理机制 三、讨论如何安全执行 HOOK 代码 3.1 挂钩例程解决方案 3.2 脱钩例程解决方案 3.3 钩子例程解决方案 3.4 地址信息查询函数 3.5 简单保护加载的模块 四、模块如何安全地注入&#xff1f; 4…

泡泡清新文艺的微社区系统PHP源码

泡泡微社区&#xff0c;小巧而强大&#xff0c;为您带来卓越的社区交流体验。 凭借GoZinc的先进架构&#xff0c;泡泡在保持轻盈身姿的同时&#xff0c;功能一应俱全。前端采用Vue3匠心打造&#xff0c;界面清新简约&#xff0c;三栏式布局仿若Twitter&#xff0c;让您一见倾心…

前端开发中不同语言【react-i18next】

目录 查看并设置语言 单页面&#xff1a;html lang ​编辑 浏览器 自定义翻译&#xff1a;react-i18next 设置 模块&#xff1a;staticData.ts 散(重复利用)&#xff1a;命名空间.json 应用 准备 html标签 查看并设置语言 单页面&#xff1a;html lang 英语: <…

Fink CDC数据同步(五)Kafka数据同步Hive

6、Kafka同步到Hive 6.1 建映射表 通过flink sql client 建Kafka topic的映射表 CREATE TABLE kafka_user_topic(id int,name string,birth string,gender string ) WITH (connector kafka,topic flink-cdc-user,properties.bootstrap.servers 192.168.0.4:6668…

合体积木

欢迎来到程序小院 合体积木 玩法&#xff1a;点击积木移动&#xff0c;将积木合并一起&#xff0c;移动步数越少获得⭐️⭐️越多&#xff0c; 共52关卡&#xff0c;每关卡都有不同的积木摆放&#xff0c;快去闯关吧^^。开始游戏 html <canvas id"gameCanvas" w…

多播路由选择

目录 1 多播路由选择 1.1 转发多播数据报时使用三种方法 (1) 洪泛与剪除 RPB 的要点&#xff1a; 1.检查&#xff0c;转发 2.形成以源为根节点的多播转发树 3.剪枝与嫁接 (2) 隧道技术 (tunneling) (3) 基于核心的发现技术 1.2 几种多播路由选择协议 1 多播路由选择 …

C++实战Opencv第二天——色彩空间转换函数和opencv中图像对象创建与赋值(从零开始,保姆教学)

OpenCV是一个强大的计算机视觉库&#xff0c;使用C作为主要编程语言&#xff0c;对于图像处理和计算机视觉领域具有重要意义。其提供了丰富的功能和算法&#xff0c;使得开发者能够快速实现各种图像处理和计算机视觉应用。OpenCV C为图像处理和计算机视觉领域的开发者提供了一个…

前端JavaScript篇之JavaScript 类数组对象的定义?如何将类数组对象转换为真正的数组

目录 JavaScript 类数组对象的定义&#xff1f;如何将类数组对象转换为真正的数组如何将类数组对象转换为真正的数组 JavaScript 类数组对象的定义&#xff1f;如何将类数组对象转换为真正的数组 类数组对象指的是具有类似数组结构&#xff08;类似于数组的属性或方法&#xf…

西瓜书学习笔记——流形学习(公式推导+举例应用)

文章目录 等度量映射&#xff08;仅保留点与其邻近点的距离&#xff09;算法介绍实验分析 局部线性嵌入&#xff08;不仅保留点与其邻近点的距离还要保留邻近关系&#xff09;算法介绍实验分析 等度量映射&#xff08;仅保留点与其邻近点的距离&#xff09; 算法介绍 等度量映…

vue中 日期选择--本日、本周、本月、本年选择器实现(基于elementui)

效果图&#xff1a; 由于项目需要图标统计展示&#xff0c;需要日期美观化选择如上图所示&#xff0c;代码如下&#xff1a; <template><div class"el-page body"><el-row><el-col class"statistic-analysis-report-style" :span&qu…

Elastic Search 6.x 版本 rollover 配置

背景 业务里有发送消息的请求&#xff0c;如短信、邮件、企信等&#xff0c;这些数据都会存储到 ES 中&#xff0c;用于数据的查询和问题排查等。每天都有几十万至几百万的数据&#xff0c;手动删除数据也比较繁琐&#xff0c;可以通过 ES 的 rollover 机制来实现根据条件自动…

PHP框架详解 - symfony框架

首先说一下为什么要写symfony框架&#xff0c;这个框架也属于PHP的一个框架&#xff0c;小编接触也是3年前&#xff0c;原因是小编接触Golang&#xff0c;发现symfony框架有PHP框架的东西也有Golang的东西&#xff0c;所以决定总结一下&#xff0c;有需要的同学可以参看小编的G…

【数据结构与算法】(7)基础数据结构之双端队列的链表实现、环形数组实现示例讲解

目录 2.6 双端队列1) 概述2) 链表实现3) 数组实现习题E01. 二叉树 Z 字层序遍历-Leetcode 103 2.6 双端队列 1) 概述 双端队列、队列、栈对比 定义特点队列一端删除&#xff08;头&#xff09;另一端添加&#xff08;尾&#xff09;First In First Out栈一端删除和添加&…