Linux网络编程--Udp套接字+实战 (万字详解,超详细!!)

目录

套接字协议:

        协议(protocol):

创建套接字(Create Socket):

绑定服务器地址

开始通信

Udp服务器设计--V1

Udp服务器设计--V2 引入进程池 待更新


套接字协议:

        协议(protocol):

        如果2个距离很远的人想要进行交流,首先要决定的就是"我们该用什么工具来进行通话?" :写信?手机?还是电脑?首先明确一点:能成功通信的双方一定是达成了某种共识的!如:2个人都是用网络进行通信,或者都是用书信交流,不可能存在一方使用书信,另一方使用手机这种“荒谬”的事情发生;换句话说,协议就是为了完成数据交换而定好的约定!

创建套接字(Create Socket):

        在Linux中一切皆文件,使用系统调用socket函数创建返回一个套接字文件描述符(如果成功)

创建失败返回-1,错误码被设置。

函数原型:

使用socket函数需要包含对应头文件;

参数详解:

  •   domian:套接字中使用的协议族,什么是协议族?说人话就是:番茄炒蛋和番茄炒米(参考卢老爷名言)都是属于用番茄做的菜一类,在套接字中,番茄就是协议族,番茄炒蛋就是协议族的一种类型,在套接字中,协议族常用的就2种:AF_INET和AF_INET6,分别对应ipv4和ipv6
  • type:套接字遵守的协议:udp还是tcp,设置为SOCK_DGRAM对应遵守UDP协议,设置为SOCK_STREAM对应遵守TCP协议
  • protocol:设置套接字的类型,非阻塞还是阻塞,是否能被子进程继承,设置为SOCK_NONBLOCK表示设置描述符非阻塞,设置SOCK_CLOEXEC表示不能被子进程继承

绑定服务器地址

        套接字创建成功后,需要绑定自己的地址信息,使用系统调用的bind函数

函数原型:

参数详解:

  • sockfd:之前使用的创建套接字返回的描述符fd
  • addr: 需要手动填充的服务器的地址信息,sockaddr本质上c语言的“拟基类”,我们要填充的其实不是sockaddr,而是它的"子类":struct sockaddr_in,结构体原型:sin_addr中还有一个成员:s_addr,用于填充要绑定的ip,注意!在云服务器上只能绑定所有地址,即"0.0.0.0"; sin_family:地址族;sin_port:端口号,注意要从本地序列(uint16_t)转换成网络序列,可以使用函数::htons进行转换;sin_zero一般都填充为0即可,所以可以在刚创建出sockaddr_in时使用memset将结构体清零
  • addrlen:第二个参数的大小,使用sizeof计算即可

开始通信

UDP套接字较为简单,不需要其他操作,只要bind成功就可以直接进行通信

使用recvfron接收信息,sendto发送信息

Udp服务器设计--V1

        目标:实现一个简单的Echo服务器,客户端发送什么info就返回什么样的info

先引入日志Log.hpp:

/*Log.hpp*/#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fstream>
#include <mutex>
#include <pthread.h>
#define _SCREEN_TYPE_ 1
#define _FILE_TYPE 2
namespace ns_log
{const std::string DEFAULTSTR = "Log.txt";enum{DEBUG = 1,INFO,WARNING,ERROR,FATAL};struct Logmessage{std::string _level; // 等级pid_t _pid;std::string _filename;   // 文件名int _filenumber;         // 行号std::string _curr_time;  // 获取日志信息出现的时间std::string _logmessage; // 信息};std::string LevelToString(int level){switch (level){case DEBUG:return "DEBUG";break;case INFO:return "INFO";break;case WARNING:return "WARNING";break;case ERROR:return "ERROR";break;case FATAL:return "FATAL";break;default:return "UNKNOW";break;}}std::string GetCurrTime(){time_t now_time = time(nullptr);struct tm *curr_time = localtime(&now_time);// 转换为string格式char buf[128];snprintf(buf, sizeof(buf), "%d-%02d-%02d %02d:%02d:%02d",curr_time->tm_year + 1900, curr_time->tm_mon + 1, curr_time->tm_mday, curr_time->tm_hour, curr_time->tm_min, curr_time->tm_sec);return buf;}class Log{void LogMsgToScreen(const Logmessage &logmsg){printf("[%s][%d][%s][%d][%s] %s",logmsg._level.c_str(), logmsg._pid, logmsg._filename.c_str(), logmsg._filenumber, logmsg._curr_time.c_str(), logmsg._logmessage.c_str());}void LogMsgToFile(const Logmessage &logmsg){char buf_info[2048] = "\0";snprintf(buf_info, sizeof(buf_info), "[%s][%d][%s][%d][%s] %s",logmsg._level.c_str(), logmsg._pid, logmsg._filename.c_str(), logmsg._filenumber, logmsg._curr_time.c_str(), logmsg._logmessage.c_str());/*--系统调用版本--*/// int fd = open(_logfile.c_str(),O_CREAT | O_WRONLY | O_APPEND,0666);// if(fd < 0)// {//     perror("open");//     return;// }// write(fd,buf_info,sizeof(buf_info));/*--c++提供的fstream--*/std::ofstream out;out.open(_logfile, std::ios::out | std::ios::app | std::ios::binary);if (!out.is_open())return;out.write(buf_info, sizeof(buf_info));out.close();}void FlushLogMsg(int level, const Logmessage &logmsg){// c++11的锁//  _mutex.lock();// RAII类型的锁std::unique_lock<std::mutex> lock(_mtx);if (_isopen && level == DEBUG)return;switch (_type){case _SCREEN_TYPE_:LogMsgToScreen(logmsg);break;case _FILE_TYPE:LogMsgToFile(logmsg);break;}}public:Log(const std::string &logfile = DEFAULTSTR) : _logfile(logfile), _type(_SCREEN_TYPE_){}void ModPrintFormat(int type){std::unique_lock<std::mutex> lock(_mtx);_type = type;}void LogMessage(int level, std::string filename, int filenumber, const char *format, ...) // 注意-->可变函数参数{Logmessage msg;msg._level = LevelToString(level);msg._filename = filename;msg._pid = getpid();msg._filenumber = filenumber;msg._curr_time = GetCurrTime();// 注意:取出可变参数的固定写法va_list _ap;           // 创建变量,本质是一个指针va_start(_ap, format); // 将参数列表中离...最近的确定的参数传入char log_info[512];vsnprintf(log_info, sizeof(log_info), format, _ap);va_end(_ap); // 销毁_apmsg._logmessage = log_info;FlushLogMsg(level, msg);}~Log(){}void EnableFiltration(bool flag){_isopen = flag;}private:int _type;std::string _logfile;std::mutex _mtx;bool _isopen = false;};Log lg;
// 打开过滤器
#define EnabelFILTRATION()         \do                             \{                              \lg.EnableFiltration(true); \} while (0)
// 关闭过滤器
#define ClOSEFILTRATION             \do                              \{                               \lg.EnableFiltration(false); \} while (0)
#define LOG(level, format, ...)                                          \do                                                                   \{                                                                    \lg.LogMessage(level, __FILE__, __LINE__, format, ##__VA_ARGS__); \} while (0)#define LOGTOSCREEN(level, format, ...)                                  \do                                                                   \{                                                                    \lg.ModPrintFormat(_SCREEN_TYPE_);                                \lg.LogMessage(level, __FILE__, __LINE__, format, ##__VA_ARGS__); \} while (0)#define LOGTOFILE(level)               \do                                 \{                                  \lg.ModPrintFormat(_FILE_TYPE); \} while (0)}

  引入日志后,正式开始编写V1版本echo服务器:

 V1--Udp_Server:

根据上文的udp套接字接口介绍,下面就直接上代码:

#pragma once
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
using namespace ns_log;
#define MAX_BUFFER_SIZE 4096
// Udp--无连接|不可靠|高性能|广播
// 云服务器bind--->0.0.0.0
/*这是一个echo服务器*/
class UdpServer
{
private:int _sockfd;uint16_t _port;bool _isrunning;
public:UdpServer(uint16_t port) : _port(port), _isrunning(false){_sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(FATAL, "create socketfd failed!\n");abort();}LOG(DEBUG, "---create sockfd succsee,sockfd = %d---\n", _sockfd);// bindstruct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = ::htons(_port); // 本地序列转网络序列// bind任意ipaddr.sin_addr.s_addr = INADDR_ANY;//INADDR_ANY--表示bind任意地址"0.0.0.0"int res = ::bind(_sockfd, (struct sockaddr *)&addr, sizeof(addr));if (res < 0){LOG(FATAL, "server bind error!\n");abort();}LOG(DEBUG, "server bind success!\n");}void Start(){_isrunning = true;while (_isrunning){char buff[MAX_BUFFER_SIZE];// 接收信息struct sockaddr_in peer;memset(&peer, 0, sizeof(peer));socklen_t len = sizeof(peer);ssize_t n = ::recvfrom(_sockfd, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&peer, &len);if (n > 0){buff[n] = 0;LOG(INFO, "client info#: %s\n", buff);// 发送std::string info = "[server][info]# ";info += buff;ssize_t n = ::sendto(_sockfd, info.c_str(), info.size(), 0,(struct sockaddr *)&peer, len);}else {if(n == 0) continue;if(n < 0){LOG(ERROR,"recv error!\n");break;}}}}void Close(){if(_sockfd > 0) ::close(_sockfd);}void Stop(){_isrunning = false;}~UdpServer(){}
};

编写客户端代码:client.cc

对于客户端来说,需要bind要连接的服务器的ip地址和端口号,不能bind任意地址了

实现:

#include "Udp_Server.hpp"bool Usage(int argc, char *argv[])
{if (argc != 3){LOG(ERROR, "Usage:<./exe> <ip> <port>\n");return false;}return true;
}
int main(int argc, char *argv[])
{if (!Usage(argc, argv))return -1;std::string ip = argv[1];uint16_t port = atoi(argv[2]);int sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){LOG(FATAL, "Create socket error!\n");return -2;}struct sockaddr_in server;// 将结构体清零memset(&server, 0, sizeof(server));server.sin_family = AF_INET;::inet_pton(AF_INET, ip.c_str(), &server.sin_addr.s_addr);server.sin_port = ::htons(port);while(true){std::string buffer;std::getline(std::cin,buffer);ssize_t n = ::sendto(sockfd,buffer.c_str(),buffer.size(),0,(struct sockaddr*)&server,sizeof(server));//接收信息char recvbuff[1024];struct sockaddr_in client;memset(&client,0,sizeof(client));socklen_t len = sizeof(client);n = ::recvfrom(sockfd,recvbuff,sizeof(recvbuff)-1,0,(struct sockaddr*)&client,&len);if(n > 0){recvbuff[n] = 0;LOG(INFO,"%s\n",recvbuff);continue;}else{if(n == 0) continue;if(n < 0){LOG(ERROR,"client recv error!\n");break;}}}return 0;
}

编写serevr.cc

#include"Udp_Server.hpp"
#include<memory>
bool Usage(int argc, char *argv[])
{if (argc != 2){LOG(ERROR, "Usage:<./exe> <port>\n");return false;}return true;
}
int main(int argc, char *argv[])
{if (!Usage(argc, argv))return -1;uint16_t port = atoi(argv[1]);std::unique_ptr<UdpServer> server = std::make_unique<UdpServer>(port);server->Start();server->Stop();server->Close();
}

编写Makefile:

.PHONY:ALL
ALL:server client
server:server.ccg++ -o $@ $^ -std=c++14 
client:client.ccg++ -o $@ $^ -std=c++14	.PHONY:clean
clean:rm -f server client

make编译即可;

Udp服务器设计--V2 引入线程池 --在线群聊服务器实现

设计图:

Udp_Server模块只负责进行IO!

Udp_Server.hpp:

#pragma once
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include "Inetaddr.hpp"
#include "Route.hpp"
using namespace ns_log;
#define MAX_BUFFER_SIZE 4096class nocopy
{
public:nocopy(){}~nocopy(){}nocopy(const nocopy&) = delete;const nocopy& operator=(const nocopy&) = delete;
};
using server_t = std::function<void(int sockfd, const std::string &info, InetAddr& addr)>;
class UdpServer : public nocopy
{
private:int _sockfd;uint16_t _port;bool _isrunning;server_t _route_call_back;
public:UdpServer(uint16_t port,const server_t& task) : _port(port), _isrunning(false),_route_call_back(task){_sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(FATAL, "---create socketfd failed !----\n");abort();}LOG(DEBUG, "---create sockfd succsee,sockfd = %d---\n", _sockfd);// bindstruct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = ::htons(_port); // 本地序列转网络序列// bind任意ipaddr.sin_addr.s_addr = INADDR_ANY;//INADDR_ANY--表示bind任意地址"0.0.0.0"int res = ::bind(_sockfd, (struct sockaddr *)&addr, sizeof(addr));if (res < 0){LOG(FATAL, "server bind error!\n");abort();}LOG(DEBUG, "server bind success!\n");}void Start(){_isrunning = true;while (_isrunning){char buff[MAX_BUFFER_SIZE];// 接收信息struct sockaddr_in peer;socklen_t len = sizeof(peer);ssize_t n = ::recvfrom(_sockfd, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&peer, &len);if (n > 0){buff[n] = 0;InetAddr addr(peer);std::cout<<addr.GetInetAddrStr()<<"#: "<<buff<<std::endl;//回调进行处理_route_call_back(_sockfd,buff,addr);}else {LOG(ERROR,"recv error!\n");}}}void Close(){if(_sockfd > 0) ::close(_sockfd);}void Stop(){_isrunning = false;}~UdpServer(){}
};

引入线程池(同步线程池)--并使用双重检查锁定模式构造单例线程池对象

ThreadPool.hpp:

#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <vector>
#include <mutex>
#include <queue>
#include <thread>
#include <memory>
#include <condition_variable>
#include <unistd.h>
#include <pthread.h>
#include "Log.hpp"
const int default_thread_num = 10;
using namespace ns_log;template <class T>
class ThreadPool
{
private:// 任务队列std::queue<T> _task_queue;// 锁std::mutex _mtx;// 条件变量std::condition_variable _con;// 管理线程的结构std::vector<std::thread> _threads;bool _isrunning;// 睡眠的线程数量int _sleep_threads;int _threadsNums;static ThreadPool<T>* _pool; static std::mutex _mutex;
private:void HandlerTask(){while (true){std::unique_lock<std::mutex> lock(_mtx);while (_task_queue.empty() && _isrunning){_con.wait(lock);// _sleep_threads--;break;}if ((!_isrunning) && _task_queue.empty()){lock.unlock();LOG(DEBUG, "thread pool is quit!\n");break;}T task = _task_queue.front();_task_queue.pop();lock.unlock();task();}}public:static ThreadPool<T>* GetThreadPoolInstance(int threadnum = default_thread_num){//双重检查锁定模式if(_pool == nullptr){std::unique_lock<std::mutex> lock(_mutex);if(_pool == nullptr)_pool = new ThreadPool<T>(threadnum);}return _pool;}ThreadPool(int threadnum): _isrunning(true),_sleep_threads(threadnum),_threadsNums(default_thread_num){for (int i = 0; i < _threadsNums; i++){_threads.emplace_back(std::bind(&ThreadPool::HandlerTask,this));}}//向任务队列插入任务void Push(const T &task){std::unique_lock<std::mutex> lock(_mtx);_task_queue.push(task);LOG(DEBUG,"Load once Task!,队列中的任务数量:%d\n",_task_queue.size());// 有任务立即通知消费者_con.notify_one();}//停止线程池void Stop(){std::unique_lock<std::mutex> lock(_mtx);_isrunning = false;_con.notify_all();}~ThreadPool(){for(auto& thread : _threads){LOG(DEBUG,"thread join done!\n");thread.join();}}};//类外初始化
template<class T>
ThreadPool<T>* ThreadPool<T>::_pool = nullptr;
template<class T>
std::mutex ThreadPool<T>::_mutex;

消息转发模块设计:Route.hpp:

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include "InetAddr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
using namespace ns_log;
using task_t = std::function<void()>;
class Route
{
private:// 在线用户std::vector<InetAddr> _online;std::mutex _mtx;public:Route(){}~Route(){}// 添加用户模块void CheckOnlineUser(InetAddr &who){std::unique_lock<std::mutex> lock(_mtx);for (auto &user : _online){if (user == who){return;}}_online.push_back(who);LOG(INFO, "用户[%s][%d]已上线!\n", who.IP().c_str(), who.Port());}// 移除下线用户模块void DeleteOnlineUser(InetAddr &who){std::unique_lock<std::mutex> lock(_mtx);auto iter = _online.begin();while (iter != _online.end()){if (*iter == who){_online.erase(iter);printf("用户[%s][%d]已下线!\n", who.IP().c_str(), who.Port());break;}++iter;}}void ForWard(int sockfd, const std::string info, InetAddr& addr){std::unique_lock<std::mutex> lock(_mtx);// 转发信息--观察者模式std::string message = addr.GetInetAddrStr() + info;for (auto &user : _online){struct sockaddr_in peer = user.GetAddr();// std::cout<<"message = "<<message<<"sockfd = "<<sockfd<<std::endl;ssize_t n = ::sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&(peer), sizeof(peer));if (n < 0)LOG(ERROR, "send error!,address = %s\n", addr.GetInetAddrStr().c_str());std::cout<<strerror(errno)<<std::endl;}}void RouteHandler(int sockfd, const std::string &info, InetAddr &who){CheckOnlineUser(who);task_t task;if (info == "Q" || info == "quit" || info == "q"){DeleteOnlineUser(who);std::string str = who.GetInetAddrStr();str += "已下线!\n";task = std::bind(&Route::ForWard, this, sockfd, str, who);}else{task = std::bind(&Route::ForWard, this, sockfd, info, who);}ThreadPool<task_t>::GetThreadPoolInstance()->Push(task);}
};

server.cc:

#include "ThreadPool.hpp"
#include "udp_server.hpp"
#include "Route.hpp"
#include <memory>
int main(int argc, char *argv[])
{if (argc != 2){LOG(INFO, "Usage: <./exe><port>\n");return -1;}uint16_t port = atoi(argv[1]);Route ro;// 业务todostd::unique_ptr<UdpServer> server = std::make_unique<UdpServer>(port,std::bind(&Route::RouteHandler,&ro,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));server->Start();server->Close();return 0;
}

client.cc:

#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <functional>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "udp_server.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "Route.hpp"int InitClient()
{int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){LOG(FATAL, "create socket errno!\n");exit(-1);}return sockfd;
}
void RecvMessage(int sockfd)
{while (true){struct sockaddr_in peer;char buf[1024];socklen_t len = sizeof(peer);ssize_t n = ::recvfrom(sockfd, buf, sizeof(buf) - 1, 0, (struct sockaddr *)(&peer), &len);if (n > 0){buf[n] = 0;InetAddr who(peer);std::cout <<who.GetInetAddrStr()<<buf << std::endl;}else{std::cerr << "recvfrom error!\n"<< std::endl;break;}}
}
void SendMessage(int sockfd, std::string &ip, uint16_t port)
{struct sockaddr_in src;memset(&src, 0, sizeof(src));src.sin_family = AF_INET;src.sin_addr.s_addr = ::inet_addr(ip.c_str());src.sin_port = ::htons(port);std::string client_prev = "SendThread# ";while (true){std::string line;std::cout << client_prev;std::getline(std::cin, line);// send message;int n = sendto(sockfd, line.c_str(), line.size(), 0, (struct sockaddr *)(&src), sizeof(src));if (n <= 0){std::cerr << "sendthread send error! \n"<< std::endl;break;}}
}
int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "usage 3 nums_command-->[./name ip port]" << std::endl;exit(-1);}int sockfd = InitClient();std::string s_ip = argv[1];uint16_t port = std::stoi(argv[2]);// start threadsstd::thread recever(std::bind(&RecvMessage, sockfd));std::thread Sender(std::bind(&SendMessage, sockfd, s_ip, port));recever.join();Sender.join();::close(sockfd);return 0;
}

Makefile:

.PHONY:ALL
ALL:server client
server:server.ccg++ -o $@ $^ -std=c++14 -lpthread -g
client:Client.ccg++ -o $@ $^ -std=c++14 -lpthread -g
.PHONY:clean
clean:rm -f server client

make编译即可

done

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

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

相关文章

C# 两种方案实现调用 DeepSeek API

目录 序 开发运行环境 访问API的一个通用方法 原生官网实现 申请 API key 调用实现 调用示例 腾讯云知识引擎原子调用 申请 API key 调用示例 小结 序 DeepSeek&#xff08;深度求索&#xff09; 最近可谓火爆的一塌糊涂&#xff0c;具体的介绍这里不再赘述&#x…

中间件-安装Minio-集成使用(ubantu-docker)

目录 1、安装docer 2、运行以下命令拉取MinIO的Docker镜像 3、检查当前所有Docker下载的镜像 4、创建目录 5、创建Minio容器并运行 6、SDK操作 FileUploader.java 1、安装docer 参考这篇&#xff1a;Linux安装Docker 2、运行以下命令拉取MinIO的Docker镜像 docker pull…

LabVIEW用户界面设计原则

在LabVIEW开发中&#xff0c;用户界面&#xff08;UI&#xff09;设计不仅仅是为了美观&#xff0c;它直接关系到用户的操作效率和体验。一个直观、简洁、易于使用的界面能够大大提升软件的可用性&#xff0c;尤其是在复杂的实验或工业应用中。设计良好的UI能够减少操作错误&am…

使用 Docker 安装 Open WebUI 并集成 Ollama 的 DeepSeek 模型

文章目录 使用 Docker 安装 Open WebUI 并集成 Ollama 的 DeepSeek 模型前提条件1. 安装ollama2. 拉取deepseek的模型3. Open-WebUI 说明4. 启动容器文档的方法如下优化命令&#xff08;可选&#xff09;1. 增加了健康检查机制&#xff08;--health-cmd&#xff09;2. 使 WebUI…

19.4.9 数据库方式操作Excel

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 本节所说的操作Excel操作是讲如何把Excel作为数据库来操作。 通过COM来操作Excel操作&#xff0c;请参看第21.2节 在第19.3.4节【…

算法15(力扣347)——前k个高频元素

1、问题 给你一个整数数组 nums 和一个整数 k &#xff0c;请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 2、示例 &#xff08;1&#xff09; 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2] &#xff08;2&#xff09; 输入: nums [1], k 1 输出: [1…

防御保护-----前言

HCIE安全防御 前言 计算机病毒 ​ 蠕虫病毒----->具备蠕虫特性的病毒&#xff1a;1&#xff0c;繁殖性特别强&#xff08;自我繁殖&#xff09;&#xff1b;2&#xff0c;具备破坏性 蠕虫病毒是一种常见的计算机病毒&#xff0c;其名称来源于它的传播方式类似于自然界中…

IntelliJ IDEA 2024.1.4版无Tomcat配置

IntelliJ IDEA 2024.1.4 (Ultimate Edition) 安装完成后&#xff0c;调试项目发现找不到Tomcat服务&#xff1a; 按照常规操作添加&#xff0c;发现服务插件中没有Tomcat。。。 解决方法 1、找到IDE设置窗口 2、点击Plugins按钮&#xff0c;进入插件窗口&#xff0c;搜索T…

docker compose部署flink集群

本次部署2个jobmanager和3个taskmanager 一、部署zookeeper集群 flink使用zookeeper用作高可用 部署集群参考&#xff1a;docker compose部署zookeeper集群-CSDN博客 二、创建目录及配置文件 创建timezone文件&#xff0c;内容填写Asia/Shanghai 手动创建目录&#xff1a…

XSS 常用标签及绕过姿势总结

XSS 常用标签及绕过姿势总结 一、xss 常见标签语句 0x01. 标签 <a href"javascript:alert(1)">test</a> <a href"x" onfocus"alert(xss);" autofocus"">xss</a> <a href"x" onclickeval(&quo…

【Django】 templates模板与static静态文件

1.templates模板 在app01(你创建的app名称)文件夹下&#xff0c;创建templates文件夹&#xff0c;其中存放想要返回的html文件 对应关系如下 除了上面的方式&#xff0c;还可以在项目根目录下创建templates文件夹&#xff0c;这时需要在settings.py文件中增加一行代码&#xf…

解锁电商数据宝藏:淘宝商品详情API实战指南

在电商蓬勃发展的今天&#xff0c;数据已成为驱动业务增长的核心引擎。对于商家、开发者以及数据分析师而言&#xff0c;获取精准、实时的商品数据至关重要。而淘宝&#xff0c;作为国内最大的电商平台&#xff0c;其海量商品数据更是蕴含着巨大的价值。 本文将带你深入探索淘…

YOLO11 【二】 【速通 训练+推理+导出】

一、 vscode 配置 conda 环境 选择默认配置修改配置文件 %windir%\System32\cmd.exe “/K” D:\Software\Anaconda3\Scripts\activate.bat D:\Software\Anaconda3 将该命令加到配置文件后面 ** “/K” D:\Software\Anaconda3\Scripts\activate.bat D:\Software\Anaconda3 **…

UWB功耗大数据插桩调研

一、摘要 UWB功耗点 插桩点 日志关键字 电流 蓝牙持锁 BatteryStats的锁统计 vendor_bluetooth_lock 30~40mA 测距 UwbSessionManager.startRanging UwbSessionManager.stoptRanging 或接入fadiKey Uwb状态广播 "com.fadiui.dkservice.action.uwb.state.change&q…

开发完的小程序如何分包

好几次了&#xff0c;终于想起来写个笔记记一下 我最开始并不会给小程序分包&#xff0c;然后我就各种搜&#xff0c;发现讲的基本上都是开发之前的小程序分包&#xff0c;可是我都开发完要发布了&#xff0c;提示我说主包太大需要分包&#xff0c;所以我就不会了。。。 好了…

前端vue项目打包部署

一、打包 可以在vscode中输入命令打包&#xff0c;也可以通过vscode的图形化界面打包 打包完成后&#xff0c;目录中&#xff0c;会生成dist文件。打包后&#xff0c;数据占用空间更小&#xff0c;比如把换行都去掉了。 完成打包 二、部署 前端主流部署服务器是 Ngix &#x…

PyTorch 中 `torch.cuda.amp` 相关警告的解决方法

在最近的写代码过程中&#xff0c;遇到了两个与 PyTorch 的混合精度训练相关的警告信息。这里随手记录一下。 警告内容 警告 1: torch.cuda.amp.autocast FutureWarning: torch.cuda.amp.autocast(args...) is deprecated. Please use torch.amp.autocast(cuda, args...) i…

C++ STL容器之set使用及复现

cset 1. 关联式容器 vector、list、deque、forward_list(C11) 等STL容器&#xff0c;其底层为线性序列的数据结构&#xff0c;里面存储的是元素本身&#xff0c;这样的容器被统称为序列式容器。而 map、set 是一种关联式容器&#xff0c;关联式容器也是用来存储数据的&#x…

激光工控机在精密制造中的应用与优势

在精密制造中&#xff0c;激光工控机可以用于许多场景例如 激光切割与雕刻&#xff1a;用于金属、塑料、陶瓷等材料的精密切割和雕刻&#xff0c;适用于汽车、航空航天、电子等行业&#xff1b;可实现复杂图案和高精度加工&#xff0c;满足微米级精度要求。 激光焊接&#xf…

第 12 天:行为树(Behavior Tree),让 AI 更智能!

&#x1f3af; 目标&#xff1a; ✅ 理解 Unreal Engine 5 行为树&#xff08;Behavior Tree&#xff09; ✅ 创建行为树&#xff08;BT&#xff09;和黑板&#xff08;Blackboard&#xff09;管理 AI 状态 ✅ 使用任务&#xff08;Task&#xff09;让 AI 巡逻、追踪、攻击玩家…