当前位置: 首页 > news >正文

【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是一个回调函数的类型。 什么类型, 使用包装器包装的!注意//包含头文件functionalusing 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其实就是网卡的pidif(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;
}

运行结果

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

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

相关文章:

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

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

第二届开放原子大赛-开源工业软件算法集成大赛即将启动!

第二届开放原子大赛-开源工业软件算法集成大赛作为开放原子开源基金会组织举办的开源技术领域专业赛事&#xff0c;聚焦开源底座框架平台建设&#xff0c;通过组件化集成的开发模式&#xff0c;丰富平台功能模块&#xff0c;拓展其应用场景&#xff0c;以此促进工业软件生态的繁…...

PXC集群(Percona XtraDB Cluster )

一、简介 基于Galera Cluster技术的开源分布式数据库解决方案,它允许你在多个MySQL服务器之间创建一个同步的多主复制集群。 特点: * 多主复制架构: PXC集群支持多主复制,每个节点都可以同时读写数据,这使得应用程序可以更灵活地进行负载均衡和高可用性设置。* 同步复制:…...

分布式光伏是什么意思?如何高效管理?

分布式光伏系统是指在用户现场或靠近用电现场配置较小的光伏发电供电系统&#xff0c;以满足特定用户的需求。根据通知&#xff0c;分布式光伏系统主要有以下几类定义&#xff1a; 10kV以下电压等级接入&#xff0c;且单个并网点总装机容量不超过6MW的分布式电源&#xff1a;这…...

提问GPT

1 理解GPT AI模型即采用深度学习技术的人工神经网络。 你不会被AI取代&#xff0c;而是会被熟练运用AI的人取代 1.1 问答或对话是普通用户与这一轮新&#xff21;&#xff29;产品的典型交互方式。 GPT生成式预训练转换器 了解当前GPT产品的形式&#xff1a; 通用聊天机器人…...

李飞飞团队新突破:低成本高泛化机器人训练法,零样本迁移成功率90%!

在机器人训练中&#xff0c;如何高效地利用模拟环境一直是研究者们关注的重点问题。 近日&#xff0c;美国斯坦福大学李飞飞教授团队提出了一种突破性的“数字表亲”&#xff08;digital cousins&#xff09;概念。这一创新方法既保留了数字孪生的优势&#xff0c;又大大降低了…...

PHP内存马:不死马

内存马概念 内存马是无文件攻击的一种常用手段&#xff0c;利用中间件的进程执行某些恶意代码。首先要讲的是PHP不死马&#xff0c;实质上就是直接用代码弄一个死循环&#xff0c;强占一个 PHP 进程&#xff0c;并不间断的写一个PHP shell&#xff0c;或者执行一段代码。 不死…...

【python】OpenCV—Connected Components

文章目录 1、任务描述2、代码实现3、完整代码4、结果展示5、涉及到的库函数6、参考 1、任务描述 基于 python opencv 的连通分量标记和分析函数&#xff0c;分割车牌中的数字、号码、分隔符 cv2.connectedComponentscv2.connectedComponentsWithStatscv2.connectedComponents…...

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

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

win10 更新npm 和 node

win10 更新npm 和 node win10 更新 npm winR 输入cmd&#xff0c;打开命令行&#xff0c;并输入如下 # 查看当前npm版本 npm -v # 清缓存 npm cache clean --force # 强制更新npm&#xff0c;试过npm update -g&#xff0c;没起作用&#xff0c;版本没变化 npm install -g …...

搜索引擎算法更新对网站优化的影响与应对策略

内容概要 随着互联网的不断发展&#xff0c;搜索引擎算法也在不断地进行更新和优化。了解这些算法更新的背景与意义&#xff0c;对于网站管理者和优化人员而言&#xff0c;具有重要的指导意义。不仅因为算法更新可能影响到网站的排名&#xff0c;还因为这些变化也可能为网站带…...

使用 Q3D 计算芯片引线的 AC 和 DC R 和 L

摘要: 模具经常用于电子行业。了解其导联的寄生特性对于设计人员来说很重要。Q3D 是计算 RLCG 的完美工具。它可用于高速板或低频电力电子设备。 在下面的视频中,我们展示了如何修改几何结构、设置模型和检查结果。 详细信息: 几何图形可以在 Q3D 中创建,也可以作为不同…...

前端_008_Vite

文章目录 Vite项目结构依赖构建插件 官网&#xff1a;https://vitejs.cn/vite3-cn/guide/ 一句话简介&#xff1a;前端的一个构建工具 Vite项目结构 index.html package.json vite.config.js public目录 src目录 #新建一个vite项目 npm create vitelatest原有项目引入vite需要…...

ssm007亚盛汽车配件销售业绩管理统(论文+源码)_kaic

本科毕业设计论文 题目&#xff1a;亚盛汽车配件销售业绩管理系统设计与实现 系 别&#xff1a; XX系&#xff08;全称&#xff09; 专 业&#xff1a; 软件工程 班 级&#xff1a; 软件工程15201 学生姓名&#xff1a; 学生学号&#xff1a; 指导教师&am…...

如何使用python完成时间序列的数据分析?

引言 时间序列分析是统计学和数据分析中的一个重要领域,广泛应用于经济学、金融、气象学、工程等多个领域。 时间序列数据是按时间顺序排列的一系列数据点,通常用于分析数据随时间的变化趋势。 本文将介绍时间序列分析的基本概念、常用方法以及如何使用Python进行时间序列…...

数字ic设计,Windows/Linux系统,其他相关领域,软件安装包(matlab、vivado、modelsim。。。)

目录 一、总述 二、软件列表 1、modelsim_10.6c 2、notepad 3、matlab 4、Visio-Pro-2016 5、Vivado2018 6、VMware15 7、EndNote X9.3.1 8、Quartus 9、pycharm 10、CentOS7-64bit 一、总述 过往发了很多数字ic设计领域相关的内容&#xff0c;反响也很好。 最近…...

SD-WAN分布式组网:构建高效、灵活的企业网络架构

随着企业数字化转型的深入&#xff0c;分布式组网逐渐成为企业网络架构中的核心需求。无论是跨区域的分支机构互联&#xff0c;还是企业与云服务的连接&#xff0c;如何在不同区域实现高效、低延迟的网络传输&#xff0c;已成为业务成功的关键。SD-WAN&#xff08;软件定义广域…...

Task :prepareKotlinBuildScriptModel UP-TO-DATE,编译卡在这里不动或报错

这里写自定义目录标题 原因方案其他思路 原因 一般来说&#xff0c;当编译到这个task之后&#xff0c;后续是要进行一些资源的下载的&#xff0c;如果你卡在这边不动的话&#xff0c;很有可能就是你的IDE目前没有办法进行下载。 方案 开关一下IDE内部的代理&#xff0c;或者…...

unseping攻防世界

源码分析 <?php highlight_file(__FILE__);//代码高亮 class ease{//声明了两个私有属性&#xff1a;保存要调用的方法的名称和保存该方法的参数。$method&#xff0c;$argsprivate $method;private $args;//构造函数在实例化类的对象时初始化,即为对象成员变量赋初始值。…...

大厂面试真题-简单描述一下SpringBoot的启动过程

SpringBoot的启动流程是一个复杂但有序的过程&#xff0c;它涉及多个步骤和组件的协同工作。以下是SpringBoot启动流程的详细解析&#xff1a; 一、启动main方法 当SpringBoot项目启动时&#xff0c;它会在当前工作目录下寻找有SpringBootApplication注解标识的类&#xff0c…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&&#xff1a;逻辑与 ||&#xff1a;逻辑或 &#xff01;&#xff1a;逻辑非 短路求值 位运算符 按位与&&#xff1a; 按位或 | 按位取反~ …...

Selenium 查找页面元素的方式

Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素&#xff0c;以下是主要的定位方式&#xff1a; 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...