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

        前言:本节内容将带友友们实现一个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;
}

运行结果

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

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

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

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

相关文章

【PTA】4-2 树的同构【数据结构】

给定两棵树 T1​ 和 T2​。如果 T1​ 可以通过若干次左右孩子互换就变成 T2​&#xff0c;则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的&#xff0c;因为我们把其中一棵树的结点A、B、G的左右孩子互换后&#xff0c;就得到另外一棵树。而图2就不是同构的。 图一…

「Mac畅玩鸿蒙与硬件13」鸿蒙UI组件篇3 - TextInput 组件获取用户输入

在鸿蒙应用开发中,TextInput 组件用于接收用户输入,适用于文本、密码等多种输入类型。本文详细介绍鸿蒙 TextInput 组件的使用方法,包括输入限制、样式设置、事件监听及搜索框应用,帮助你灵活处理鸿蒙应用中的用户输入。 关键词 TextInput 组件用户输入输入限制事件监听搜索…

单元测试详解

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 为什么需要单元测试&#xff1f; 从产品角度而言&#xff0c;常规的功能测试、系统测试都是站在产品局部或全局功能进行测试&#xff0c;能够很好地与用户的需…

如何从PPT中导出600dpi的高清图

Step1. 修改PPT注册表 具体过程&#xff0c;参见如下链接&#xff1a;修改ppt注册表&#xff0c;导出高分辨率图片 Step2. 打开PPT&#xff0c;找到自己想要保存的图&#xff0c;选中图像&#xff0c;查看图像尺寸并记录 Step3. 重新新建一个PPT&#xff0c;并根据记录的图片…

「Mac畅玩鸿蒙与硬件7」鸿蒙开发环境配置篇7 - 使用命令行工具和本地模拟器管理项目

本篇将讲解在 macOS 上配置 HarmonyOS 开发环境的流程&#xff0c;聚焦 hvigorw 命令行工具的使用。我们将以创建 HelloWorld 项目为例&#xff0c;演示使用 hvigorw 进行项目构建、清理操作&#xff0c;并通过 DevEco Studio 的本地模拟器进行预览&#xff0c;帮助提升项目开发…

Linux基础—基础命令及相关知识5(ubuntu网络配置)

网络的配置方法 centos网络配置 centos的网卡位置 /etc/sysconfig/network-scripts/ifcfg-ens33(centos网卡文件) bootproto表示获得IP地址的方式是静态的还是动态 onboot表示启动系统时是否激活该网络接口 设置IP地址&#xff0c;子网掩码&#xff0c;网关&#xff0c;dns…

LabVIEW开发的控制阀监控与维护系统

LabVIEW开发一套自动测试软件&#xff0c;用于控制阀的实时监控、数据采集、维护管理以及报警通知。此系统的目标是通过便捷的操作界面、可靠的通信接口和高效的数据管理&#xff0c;为工厂设备管理提供全面的支持。 1. 项目需求 目标是实现一个控制阀管理系统&#xff0c;能够…

第7章 利用CSS和多媒体美化页面作业

2.用表格布局页面&#xff0c;利用CSS技术&#xff0c;及添加多媒体&#xff0c;制作并美化“心灵之音”页面。 浏览效果如下&#xff1a; 实例代码如下&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>心灵…

Python中的数据可视化:Matplotlib基础与高级技巧

Python中的数据可视化&#xff1a;Matplotlib基础与高级技巧 数据可视化是数据分析和数据科学中不可或缺的一部分。通过图表&#xff0c;我们可以更直观地观察数据的分布和趋势。Matplotlib作为Python最基础、也是最广泛使用的绘图库之一&#xff0c;不仅支持多种常用图表&…

‘cmd‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

报错描述&#xff1a; 我在使用python执行一个spark任务时&#xff0c;一直报如下错误&#xff0c;检查电脑上所有的环境变量后发现都配置正确&#xff0c;但还是一直报cmd 不是内部或外部命令&#xff0c;也不是可运行的程序这个错误&#xff0c;如果你也有这样的情况&#x…

【网络】传输层协议TCP

目录 四位首部长度 序号 捎带应答 标记位 超时重传机制 连接管理机制&#xff08;RST标记位&#xff09; 三次握手及四次挥手的原因 TCP的全称是传输控制协议&#xff08;Transmission Control Protocol&#xff09;&#xff0c;也就是说&#xff0c;对于放到TCP发送缓冲…

【优选算法篇】前缀之序,后缀之章:于数列深处邂逅算法的光与影

文章目录 C 前缀和详解&#xff1a;基础题解与思维分析前言第一章&#xff1a;前缀和基础应用1.1 一维前缀和模板题解法&#xff08;前缀和&#xff09;图解分析C代码实现易错点提示代码解读题目解析总结 1.2 二维前缀和模板题解法&#xff08;二维前缀和&#xff09;图解分析C…

采用STM32CubeMX和HAL库的定时器应用实例

目录 STM32的通用定时器配置流程 定时器应用的硬件设计 定时器应用的软件设计 1. 通过STM32CubeMX新建工程 通过STM32CubeMX新建工程的步骤如下&#xff1a; 2. 通过Keil MDK实现工程 通过Keil MDK实现工程的步骤如下&#xff1a; STM32的通用定时器配置流程 通用定时器…

开源一套基于若依的wms仓库管理系统,支持lodop和网页打印入库单、出库单的源码

大家好&#xff0c;我是一颗甜苞谷&#xff0c;今天分享一款基于若依的wms仓库管理系统&#xff0c;支持lodop和网页打印入库单、出库单的源码。 前言 在当今快速发展的商业环境中&#xff0c;库存管理对于企业来说至关重要。然而&#xff0c;许多企业仍然依赖于传统的、手动…

算法实现 - 快速排序(Quick Sort) - 理解版

文章目录 算法介绍算法分析核心思想三个版本运行过程挖坑法Hoare 原版前后指针法 算法稳定性和复杂度稳定性时间复杂度平均情况O(nlogn)最差情况O( n 2 n^2 n2) 空间复杂度 算法介绍 快速排序是一种高效的排序算法&#xff0c;由英国计算机科学家C. A. R. Hoare在1960年提出&a…

C语言指针的介绍

零.导言 在日常生活中&#xff0c;我们常常在外出时居住酒店&#xff0c;细心的你一定能发现酒店不同的房间上有着不同的门牌号&#xff0c;上面写着像308&#xff0c;512之类的数字。当你定了酒店之后&#xff0c;你就会拿到一个写有门牌号的钥匙&#xff0c;凭着钥匙就能进入…

聊聊解构的那些事

#我们都知道es6出了个新特性&#xff0c;支持解构&#xff0c;使用过的人可能都觉得挺简单的&#xff0c;但有一些小点&#xff0c;只有使用中留意了或者踩坑了才发现我们认识的还很浅# 解构定义 允许按照一定模式&#xff0c;从数组和对象中提取值&#xff0c;对变量进行赋值…

Qt Designer客户端安装和插件集(pyqt5和pyside2)

GitHub - PyQt5/QtDesignerPlugins: Qt Designer PluginsQt Designer Plugins. Contribute to PyQt5/QtDesignerPlugins development by creating an account on GitHub.https://github.com/PyQt5/QtDesignerPlugins 一、下载客户端 https://github.com/PyQt5/QtDesigner/rel…

Idea常见插件(超级实用)

文章目录 Idea好用的插件推荐Idea插件安装Chinese(中文版)Alibaba Java Coding Guidelines&#xff08;代码规范&#xff09;Auto Filling Java Arguments&#xff08;自动补全参数&#xff09;CamelCase&#xff08;变量名称格式转换&#xff09;CodeGeeX&#xff08;智能&…

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

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