【linux网络编程】| socket套接字 | 实现UDP协议聊天室

news2024/11/27 16:36:28

        前言:本节内容将带友友们实现一个UDP协议的聊天室。 主要原理是客户端发送数据给服务端。 服务端将数据再转发给所有链接服务端的客户端。 所以, 我们主要就是要实现客户端以及服务端的逻辑代码。 那么, 接下来开始我们的学习吧。

        ps:本节内容建议了解socket套接字的接口的友友们进行观看哦,本节内容中涉及到的接口都不会讲解, 直接就用了。

目录

 整体代码

Udpclient

UdpServer

main(配合UdpServer, UdpServer的入口) 

准备文件

实现步骤

实现服务端客户端的收发消息

Udpserver

Init函数

run函数 

 UdpServer析构

Udpclient

实现客户端之间的聊天功能

Udpserver

Udpclient

运行结果


 整体代码

        先上整体代码:

Udpclient


#include<iostream>
using namespace std;
#include<string>
#include<sys/types.h>
#include"Log.hpp"
#include<sys/socket.h>
#include<pthread.h>
#include<arpa/inet.h>
#include<string.h>
#include<netinet/in.h>
Log lg;


class ThreadData
{
public:
    sockaddr_in server;
    int sockfd;
};

void* recv_message(void* args)
{
    char buffer[1024];
    ThreadData* td = static_cast<ThreadData*>(args);    
    while (true)
    {
        //接收数据
        sockaddr_in temp;
        socklen_t len;
        string info;
        ssize_t s = recvfrom(td->sockfd, buffer, sizeof(buffer) - 1, 0, (sockaddr*)&temp, &len);

        if (s < 0)
        {
            lg(Error, "recv error, error: %d, strerror: %s", errno, strerror(errno));
            continue;
        }
        buffer[s] = 0;
        info = buffer;
        cout << info << endl;
    }

}

void* send_message(void* args)
{
    ThreadData* td = static_cast<ThreadData*>(args);
    string message;
    while (true)
    { 
        getline(cin, message);  //获取数据
        //发送数据
        sendto(td->sockfd, message.c_str(), message.size(), 0, (sockaddr*)&td->server, sizeof(td->server));

    }
}

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        cout << "Client server" << endl;
    }

    //先拿到套接字的参数
    string serverip = argv[1];
    uint16_t serverport = stoi(argv[2]);

    ThreadData td;

    //创建套接字与打开网卡
    memset(&td.server, 0, sizeof(td.server));
    td.server.sin_family = AF_INET;
    td.server.sin_port = htons(serverport);
    td.server.sin_addr.s_addr = inet_addr(serverip.c_str());
    td.sockfd = socket(AF_INET, SOCK_DGRAM, 0); //创建文件描述符, 网卡的文件描述符, 网络传输就是使用网络文件描述符找到对应的文件内的数据
    if (td.sockfd < 0)
    {
        lg(Error, "client create sockfd error, errno: %d, strerror: %s", errno, strerror(errno));
        exit(1);
    }

    //创建线程, 然后运行线程, 等待线程
    pthread_t recv, send;
    pthread_create(&recv, nullptr, recv_message, &td);
    pthread_create(&send, nullptr, send_message, &td);

    pthread_join(recv, nullptr);
    pthread_join(send, nullptr);

    close(td.sockfd);
    return 0;
}

UdpServer

#include<iostream>
using namespace std;
#include<sys/types.h>
#include<string>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<strings.h>
#include"Log.hpp"
#include<functional>
#include<netinet/in.h>
#include<unordered_map>


int defaultport = 8080;
string defaultip = "0.0.0.0";

using func_t = function<string(string, sockaddr_in&, unordered_map<string, sockaddr_in>&)>; 
Log lg;

enum
{
    SockError = 2,
    BindError = 3,
    RecvError = 4,
};

class UdpServer
{
public:
    UdpServer(uint16_t port = defaultport) 
        : port_(port), ip_(defaultip), isrunning_(false)
    {}

    void Init()
    {
        //先创建套接字变量并且完成初始化。 然后就创建网卡文件
        sockaddr_in local;
        
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = inet_addr(ip_.c_str());
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            lg(Fatal, "create sock error, errno: %d, strerror: %s", errno, strerror(errno));
            exit(SockError);
        }
        lg(Info, "create sock success");
        
        //绑定
        if (bind(sockfd_, (sockaddr*)&local, sizeof(local)) < 0) 
        {
            lg(Fatal, "bind error, errno: %d, strerror: %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "bind success");
    }

    void BroadCast(string message, unordered_map<string, sockaddr_in>& clients)
    {
        cout << "1 "<< endl;
        for (auto& e : clients)
        {
            sendto(sockfd_, message.c_str(), message.size(), 0, (sockaddr*)&e.second, sizeof(e.second));
        }
        cout << "2 " << endl;
    }

    
    void run(func_t func)
    {
        isrunning_ = true;
        char inbuffer[1024];


        while (isrunning_)
        {
            memset(inbuffer, 0, sizeof(inbuffer));
            sockaddr_in client;
            socklen_t client_len;
            memset(&client, 0, sizeof(client));
            //接收数据的同时监听到客户端的来源
            ssize_t s = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (sockaddr*)&client, &client_len);
            if (s < 0) 
            {
                lg(Waring, "recvfrom error, errno: %d, strerror: %s", errno, strerror(errno));
                continue;
            }
            inbuffer[s] = 0;

            //处理数据
            //创建套接字, 用来监听是哪一个客户端

            string message = inbuffer;
            message = func(message, client, clients);

            //处理完成后, 返回发送给客户端
            BroadCast(message, clients);
            // sendto(sockfd_, message.c_str(), message.size(), 0, (sockaddr*)&client, sizeof(client));


        }
    }

    ~UdpServer()
    {
        if (sockfd_ > 0) close(sockfd_);    
    }
private:
    int sockfd_;
    uint16_t port_;
    string ip_;
    bool isrunning_;
    unordered_map<string, sockaddr_in> clients;

};

main(配合UdpServer, UdpServer的入口) 


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

string Handler(string message, sockaddr_in& client, unordered_map<string, sockaddr_in>& clients)
{
    string tmp = inet_ntoa(client.sin_addr) + to_string(client.sin_port);
    if (!clients.count(tmp))
    {
        clients[tmp] = client; 
        cout << "ip " << inet_ntoa(client.sin_addr) << " : port " << client.sin_port << " has add in talk room" << endl;
    }
    message = "[" + string(inet_ntoa(client.sin_addr)) + ":" + to_string(client.sin_port) + "]#: " + message; 
    return message;
}

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        cout << "has return" << endl;
        return 1;
    }
    //
    uint16_t serverport = stoi(argv[1]);  

    unique_ptr<UdpServer> svr(new UdpServer(serverport));
    //
    svr->Init();
    svr->run(Handler);


    return 0;
}

准备文件

        我们要准备三个文件

  •         Udpclient.cc——用来运行起来客户端
  •         UdpServer.hpp——用来实现服务端的各种接口
  •         main.cc——用来运行起来服务端

        除了这三个主要的文件。 其实博主还准备了两个可以忽略的文件(为了方便)。 一个是博主自己写的日志程序, 用来打印日志。 一个是makefile, 方便编译。 

        如果没有日志程序的话,打印错误信息时直接cout, printf打印即可。 makefile建议带上, 方便编译养成好习惯。

实现步骤

注意, 一步到位是很难的。 所以我们先实现简单的功能, 再实现困难的功能。

        这里简单的功能就是,先让客户端能够将数据发给服务端了, 然后服务端接收到消息后再将数据返回给客户端。

        这里困难的功能就是当多个客户端如何看到互相的信息。然后如何能够一遍发信息,一边收信息。 

实现服务端客户端的收发消息

Udpserver

        实现逻辑:Udpserver.hpp中封装一个类。这个类里面封装一些接口, 然后我们在main函数中创建类对象, 在执行接口操作。

        所以, 先封装一个类, 将要实现的接口以及要用到的变量写上, 实现一个框架:

#include<iostream>
using namespace std;
#include<string>

int defaultport = 8080;       //默认的端口号,我们要创建一个默认的端口号
string defaultip = "0.0.0.0"; //在服务器中使用套接字的时候, bind函数不能绑定公网IP, 因为
//服务器的公网IP可能是虚拟的, 注意,IP地址是和网卡挂钩的, 一个网卡只能有一个IP地址。 
//绑定ip地址就是说在绑定网卡,也就是说绑定某个IP地址后就只能监听这一个网卡的消息了。 但是
//有些机器是有很多张网卡的, 所以就有一个默认IP:0.0.0.0, 绑定这个IP就能监听在本机器下面
//所有的网卡的信息。 


Log lg;

class UdpServer
{
public:
    UdpServer(uint16_t port = defaultport) 
        : port_(port), ip_(defaultip), isrunning_(false)
    {}

    void Init()
    {

    }


    void run(func_t func)
    {

    }

    ~UdpServer()
    {

    }
private:
    int sockfd_;     //服务端的网卡文件的编号
    uint16_t port_;  //服务器起来后的端口号
    string ip_;      //服务器起来的时候所在的ip地址
    bool isrunning_; //服务器是否正在运行


};

        下面是main.cpp里面的内容, 直接启动服务端。 

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



int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        cout << "has return" << endl;
        return 1;
    }
    //
    uint16_t serverport = stoi(argv[1]);  

    unique_ptr<UdpServer> svr(new UdpServer(serverport));
    //
    svr->Init();
    svr->run();


    return 0;
}

Init函数

        Udpserver里面的Init函数, 这个函数用来绑定服务端的套接字的。 什么是绑定? 博主目前的理解就是将我们运行的服务端这个程序能够和网卡建立起关系。         

        这个关系中, 关系的两端是我们运行的服务端程序和socket网卡文件(网卡文件就代表了网卡)。关系的纽带是ip地址和端口号。 利用ip地址和端口号来将我们的服务端程序绑定给网卡, 这个时候因为网卡的工作性质, 其他的进程都不能再绑定网卡了, 直到我们的服务端退出。 

    void Init()
    {
        //先创建套接字变量并且完成初始化。 然后就创建网卡文件
        sockaddr_in local;
        
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = inet_addr(ip_.c_str());
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            lg(Fatal, "create sock error, errno: %d, strerror: %s", errno, strerror(errno));
            exit(SockError);
        }
        lg(Info, "create sock success");
        
        //绑定
        if (bind(sockfd_, (sockaddr*)&local, sizeof(local)) < 0) 
        {
            lg(Fatal, "bind error, errno: %d, strerror: %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "bind success");
    }

run函数 

        我们这里思考一个问题, 我们要实现的其实是服务端与客户端之间收发消息。 所以, 我们就要客户端先发, 然后服务端收消息。 

        然后! 服务端收到消息将消息 处理一下 再将消息发回客户端。

        所以,这个过程中服务端有三个主要的动作, 一个是收,一个是处理, 一个是发。         

        然后我们的处理怎么处理, 我们可以将处理动作暴露出去,  交给main.cpp来决定。 ——利用回调函数, main.cpp中将要执行的动作作为函数传给run函数。 

如下为接口:

    //这里的func_t是一个回调函数的类型。 什么类型, 使用包装器包装的!注意
    //包含头文件functional
    using func_t = function<string(string)>; 


    void run(func_t func)
    {
        isrunning_ = true;
        char inbuffer[1024];


        while (isrunning_)
        {
            memset(inbuffer, 0, sizeof(inbuffer));
            sockaddr_in client;
            socklen_t client_len;
            memset(&client, 0, sizeof(client));
            //接收数据的同时监听到客户端的来源
            ssize_t s = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (sockaddr*)&client, &client_len);
            if (s < 0) 
            {
                lg(Waring, "recvfrom error, errno: %d, strerror: %s", errno, strerror(errno));
                continue;
            }
            inbuffer[s] = 0;

            //处理数据
            //创建套接字, 用来监听是哪一个客户端

            string message = inbuffer;
            message = func(message);//这里的处理使用一个外部的接口

            //处理完成后, 返回发送给客户端

            sendto(sockfd_, message.c_str(), message.size(), 0, (sockaddr*)&client, sizeof(client));


        }
    }

 UdpServer析构

析构函数不解释

    ~UdpServer()
    {
        if (sockfd_ > 0) close(sockfd_);    
    }

Udpclient

        客户端就是给对应的服务端发送数据。 数据被服务端处理后接收即可:

#include<iostream>
#include<cstdlib>
#include<unistd.h>
using namespace std;
#include<sys/types.h>
#include<strings.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<cstring>
#include<string>



//./udpclient serverip serverport 
int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        cout << "has return" << endl;
        return 1;
    }
    //
    string serverip = argv[1];
    uint16_t serverprot = stoi(argv[2]);
    
    //创建套接字
    struct sockaddr_in server;
    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(serverprot);
    server.sin_addr.s_addr = inet_addr(serverip.c_str());
    socklen_t serlen = sizeof(server);

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        cout << "socker error" << endl; 
        return 1;
    }


    string message;
    char buffer[1024];
    while(true)
    {   

        cout << "please Enter@:" << endl;
        getline(cin, message);  
        
        //发送数据
        sendto(sockfd, message.c_str(), message.size(), 0,  (struct sockaddr*)&server, serlen);
        cout << "yes" << endl;

        //接收数据
        sockaddr_in temp;
        socklen_t socklen;
        ssize_t sz = recvfrom(sockfd, (void*)buffer, sizeof(buffer) - 1, 0, (sockaddr*)&temp, &socklen); //sockfd其实就是网卡的pid
        
        if(sz > 0)
        {
            buffer[sz] = 0;
            cout << buffer << endl;
        }
    }
    

    close(sockfd);
    return 0;
}

实现客户端之间的聊天功能

Udpserver

        实现客户端之间的聊天可是说是在上面的代码中改两个地方。 一个是创建一个哈希表存储有多少客户端连接了服务端。 然后以后发消息就直接便利整个哈希表, 然后将数据发给每一个客户端。 如下:

#include<iostream>
using namespace std;
#include<sys/types.h>
#include<string>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<strings.h>
#include"Log.hpp"
#include<functional>
#include<netinet/in.h>
#include<unordered_map>


int defaultport = 8080;
string defaultip = "0.0.0.0";

//包装类要进行修改一下
using func_t = function<string(string, sockaddr_in&, unordered_map<string, sockaddr_in>&)>; 

Log lg;

enum
{
    SockError = 2,
    BindError = 3,
    RecvError = 4,
};

class UdpServer
{
public:
    UdpServer(uint16_t port = defaultport) 
        : port_(port), ip_(defaultip), isrunning_(false)
    {}
    
    //Init不变
    void Init()
    {
        //先创建套接字变量并且完成初始化。 然后就创建网卡文件
        sockaddr_in local;
        
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        local.sin_addr.s_addr = inet_addr(ip_.c_str());
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            lg(Fatal, "create sock error, errno: %d, strerror: %s", errno, strerror(errno));
            exit(SockError);
        }
        lg(Info, "create sock success");
        
        //绑定
        if (bind(sockfd_, (sockaddr*)&local, sizeof(local)) < 0) 
        {
            lg(Fatal, "bind error, errno: %d, strerror: %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "bind success");
    }
    

    //遍历哈希表,将数据分发给所有的客户端
    void BroadCast(string message, unordered_map<string, sockaddr_in>& clients)
    {
        cout << "1 "<< endl;
        for (auto& e : clients)
        {
            sendto(sockfd_, message.c_str(), message.size(), 0, (sockaddr*)&e.second, sizeof(e.second));
        }
        cout << "2 " << endl;
    }

    
    void run(func_t func)
    {
        isrunning_ = true;
        char inbuffer[1024];


        while (isrunning_)
        {
            memset(inbuffer, 0, sizeof(inbuffer));
            sockaddr_in client;
            socklen_t client_len;
            memset(&client, 0, sizeof(client));
            //接收数据的同时监听到客户端的来源
            ssize_t s = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (sockaddr*)&client, &client_len);
            if (s < 0) 
            {
                lg(Waring, "recvfrom error, errno: %d, strerror: %s", errno, strerror(errno));
                continue;
            }
            inbuffer[s] = 0;

            //处理数据
            //创建套接字, 用来监听是哪一个客户端

            string message = inbuffer;
            message = func(message, client, clients);//这里的处理使用一个外部的接口

            //处理完成后, 返回发送给客户端
            BroadCast(message, clients);

        }
    }

    ~UdpServer()
    {
        if (sockfd_ > 0) close(sockfd_);    
    }
private:
    int sockfd_;
    uint16_t port_;
    string ip_;
    bool isrunning_;
    unordered_map<string, sockaddr_in> clients; //添加哈希表

};

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

//main.cc主要修改就是Handler函数, 我们要通过client里面的ip地址和端口号作为key,client作为value,然后放入哈希表。 同时将message处理一下,方便我们观看结果。 
string Handler(string message, sockaddr_in& client, unordered_map<string, sockaddr_in>& clients)
{
    string tmp = inet_ntoa(client.sin_addr) + to_string(client.sin_port);
    if (!clients.count(tmp))
    {
        clients[tmp] = client; 
        cout << "ip " << inet_ntoa(client.sin_addr) << " : port " << client.sin_port << " has add in talk room" << endl;
    }
    message = "[" + string(inet_ntoa(client.sin_addr)) + ":" + to_string(client.sin_port) + "]#: " + message; 
    return message;
}

// 

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        cout << "has return" << endl;
        return 1;
    }
    //
    uint16_t serverport = stoi(argv[1]);  

    unique_ptr<UdpServer> svr(new UdpServer(serverport));
    //
    svr->Init();
    svr->run(Handler);


    return 0;
}

Udpclient

#include<iostream>
using namespace std;
#include<string>
#include<sys/types.h>
#include"Log.hpp"
#include<sys/socket.h>
#include<pthread.h>
#include<arpa/inet.h>
#include<string.h>
#include<netinet/in.h>
Log lg;


class ThreadData
{
public:
    sockaddr_in server;
    int sockfd;
};

//数据接收函数
void* recv_message(void* args)
{
    char buffer[1024];
    ThreadData* td = static_cast<ThreadData*>(args);    
    while (true)
    {
        //接收数据
        sockaddr_in temp;
        socklen_t len;
        string info;
        ssize_t s = recvfrom(td->sockfd, buffer, sizeof(buffer) - 1, 0, (sockaddr*)&temp, &len);

        if (s < 0)
        {
            lg(Error, "recv error, error: %d, strerror: %s", errno, strerror(errno));
            continue;
        }
        buffer[s] = 0;
        info = buffer;
        cout << info << endl;
    }

}

//数据发送函数
void* send_message(void* args)
{
    ThreadData* td = static_cast<ThreadData*>(args);
    string message;
    while (true)
    {  
        getline(cin, message);  //获取数据
        //发送数据
        sendto(td->sockfd, message.c_str(), message.size(), 0, (sockaddr*)&td->server, sizeof(td->server));

    }
}

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        cout << "Client server" << endl;
    }

    //先拿到套接字的参数
    string serverip = argv[1];
    uint16_t serverport = stoi(argv[2]);

    ThreadData td;

    //创建套接字与打开网卡
    memset(&td.server, 0, sizeof(td.server));
    td.server.sin_family = AF_INET;
    td.server.sin_port = htons(serverport);
    td.server.sin_addr.s_addr = inet_addr(serverip.c_str());
    td.sockfd = socket(AF_INET, SOCK_DGRAM, 0); //创建文件描述符, 网卡的文件描述符, 网络传输就是使用网络文件描述符找到对应的文件内的数据
    if (td.sockfd < 0)
    {
        lg(Error, "client create sockfd error, errno: %d, strerror: %s", errno, strerror(errno));
        exit(1);
    }

    

    //创建线程, 然后运行线程, 等待线程
    pthread_t recv, send;
    pthread_create(&recv, nullptr, recv_message, &td);
    pthread_create(&send, nullptr, send_message, &td);

    pthread_join(recv, nullptr);
    pthread_join(send, nullptr);

    close(td.sockfd);
    return 0;
}

运行结果

最后就是运行结果, 运行结果就是下图了, 我们已经能够成功的进行两个客户端之间的远程交流

 ——————以上就是本节全部内容哦, 如果对友友们有帮助的话可以关注博主, 方便学习更多知识哦!!! 

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

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

相关文章

Windows 下实验视频降噪算法 MeshFlow 详细教程

MeshFlow视频降噪算法 Meshflow 视频降噪算法来自于 2017 年电子科技大学一篇高质量论文。 该论文提出了一个新的运动模型MeshFlow&#xff0c;它是一个空间平滑的稀疏运动场 (spatially smooth sparse motion field)&#xff0c;其运动矢量 (motion vectors) 仅在网格顶点 (m…

随机采样方法之逆变换采样

抽样或采样是指从目标总体中抽取出部分个体也就是样本&#xff0c;通过对样本的属性或特征进行分析&#xff0c;以此对总体进行评估。采样作为一种重要的数据分析方法&#xff0c;在深度学习、渲染等诸多方面具有广泛的应用。本文将回顾一种基本的采样方法即逆变换采样。 一、…

国自然地学部立项名单(2021-2023年)和标书范本(2007-2017年33份)-最新出炉 附下载链接

国自然地学部立项名单&#xff08;2021-2023年&#xff09;和标书范本&#xff08;2007-2017年33份&#xff09; 下载链接-点它&#x1f449;&#x1f449;&#x1f449;&#xff1a; 国自然地学部立项名单&#xff08;2021-2023年&#xff09;和标书范本&#xff08;2007-201…

C++之多态的深度剖析

目录 前言 1.多态的概念 2.多态的定义及实现 2.1多态的构成条件 2.1.1重要条件 2.1.2 虚函数 2.1.3 虚函数的重写/覆盖 2.1.4 选择题 2.1.5 虚函数其他知识 协变&#xff08;了解&#xff09; 析构函数的重写 override 和 final关键字 3. 重载&#xff0c;重写&…

信息安全数学基础(34)正规子群和商群

正规子群详述 定义&#xff1a; 设G是一个群&#xff0c;H是G的子群。若H的左陪集与右陪集总是相等&#xff08;即对任何的a∈G&#xff0c;都有aHHa&#xff09;&#xff0c;则称H是G的正规子群或不变子群&#xff0c;记为H⊴G。 性质&#xff1a; 平凡性&#xff1a;任何群G…

日期选择简化版今日、本周、本月、本季度、本年

function 未来之窗_时间_现在() {let date new Date(),year date.getFullYear(), //获取完整的年份(4位)month date.getMonth() 1, //获取当前月份(0-11,0代表1月)strDate date.getDate() // 获取当前日(1-31),小时 date.getHours(),分钟 date.getMinutes();if (month &…

C语言笔记(指针题目)例题+图解

本文分为两部分 &#xff0c;第一部分为数组、字符串、字符指针在sizeof和strlen中的辨析&#xff0c;第二部分是一些笔试题目。若有错误&#xff0c;请批评指正。 目录 1.第一部分 1.1.数组名的使用 1.1.1一维整型数组在sizeof中的使用 1.1.2一维字符数组在sizeof中的使用…

Android Input的流程和原理

Android Input事件机制 Android系统是由事件驱动的&#xff0c;而Input是最常见的事件之一&#xff0c;用户的点击、滑动、长按等操作&#xff0c;都属于Input事件驱动&#xff0c;其中的核心就是InputReader和InputDispatcher。InputReader和InputDispatcher是跑在system_serv…

Manus在虚拟现实仿真模拟中的应用案例分享

Manus虚拟现实手套作为一种高精度的人机交互设备&#xff0c;在仿真模拟领域展现出了巨大的应用潜力。通过提供实时、准确的手指动作捕捉数据&#xff0c;Manus手套为多个行业带来了前所未有的仿真体验&#xff0c;推动了技术发展和应用创新。 技术特点 1. 高精度手指跟踪 Manu…

windows 驱动实例分析系列: NDIS 6.0的Filter 驱动改造(四)

驱动的测试代码解读 1. 打开设备对象: // 1. 打开底层设备对象HANDLE hDevice CreateFile(L"\\\\.\\NDISFilter", // 设备名称GENERIC_READ | GENERIC_WRITE, // 访问权限0, // 不共享NULL, // 默认安全属性OPEN_EXISTING, // 打开现有设备0, // 无特殊标志NULL /…

加强版 第四节联通组件分析与演示

得到二值图像的目的是为了后面的分析 基本概念解释 -图像联通组件 -四邻域与八邻域联通 ccl联通组件标记 通过四邻域和八邻域来对图像进行边缘寻找与噪声处理的功能 常见算法来寻找联通组件 -基于像素扫描方法 -基于块扫描的方法 -两步法扫描 API: OpenCV中支持连通组件…

闯关leetcode——232. Implement Queue using Stacks

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/implement-queue-using-stacks/description/ 内容 Implement a first in first out (FIFO) queue using only two stacks. The implemented queue should support all the functions of a normal …

【Unity基础】初识UI Toolkit - 编辑器UI

&#xff08;本文所需图片在文章上面的资源中&#xff0c;点击“立即下载”。&#xff09; 本文介绍了如何通过UI工具包&#xff08;UI Toolkit&#xff09;来创建一个编辑器UI。 一、创建项目 1. 打开Unity创建一个空项目&#xff08;任意模板&#xff09;&#xff0c;这里我…

什么?Flutter 又要凉了? Flock 是什么东西?

今天突然看到这个消息&#xff0c;突然又有一种熟悉的味道&#xff0c;看来这个月 Flutter “又要凉一次了”&#xff1a; 起因 flutter foundation 决定 fork Flutter 并推出 Flock 分支用于自建维护&#xff0c;理由是&#xff1a; foundation 推测 Flutter 团队的劳动力短缺…

windows文件实时同步

在现今这个高效运转的工作时代&#xff0c;数据同步与备份的重要性愈发凸显。特别是对于Windows用户&#xff0c;实现文件在不同设备间的实时流转&#xff0c;不仅能够显著提升工作效率&#xff0c;更是数据安全的一道重要防线。接下来&#xff0c;我们将深入剖析Windows文件实…

全桥PFC电路及MATLAB仿真

一、PFC电路原理概述 PFC全称“Power Factor Correction”&#xff08;功率因数校正&#xff09;&#xff0c;PFC电路即能对功率因数进行校正&#xff0c;或者说是能提高功率因数的电路。是开关电源中很常见的电路。功率因数是用来描述电力系统中有功功率&#xff08;实际使用…

rom定制系列------红米note8_miui14安卓13定制修改固件 带面具root权限 刷写以及界面预览

&#x1f49d;&#x1f49d;&#x1f49d;红米note8机型代码&#xff1a;ginkgo。高通芯片。此固件官方最终版为稳定版12.5.5安卓11的版本。目前很多工作室需要高安卓版本的固件来适应他们的软件。并且需要root权限。根据客户要求。修改固件为完全root。并且修改为可批量刷写的…

【传知代码】图像处理解决种子计数方法

文章目录 一、背景及意义介绍研究背景农业考种需求传统计数方法的局限性人工计数仪器设备计数 研究意义提高育种效率提高计数准确性广泛的适用性数据存档与分析便利 二、概述三、材料与数据准备以及方法介绍整体流程图像采集图像预处理形态学操作腐蚀运算开运算 图像二值化种子…

【鸿蒙HarmonyOS实战:通过华为应用市场上架测试版App实现HBuilder X打包的UniApp项目的app转hap教程(邀请码)方式教程详解】

鸿蒙HarmonyOS实战&#xff1a;通过华为应用市场上架测试版App实现HBuilder X打包的UniApp项目的app转hap教程&#xff08;邀请码&#xff09;方式详解 在使用uniapp打包的鸿蒙项目的过程中&#xff0c;由于生成的是app文件&#xff0c;而hdc传给鸿蒙HarmonyOS系统需要的是hap文…

2025选题|基于协同推荐的黔醉酒业白酒销售系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参…