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

【Linux网络】epoll实现的echo服务器{nocopy类/智能指针/echo服务器}

文章目录

  • 1.代码基础
    • 1.1某类唯一存在
    • 1.2C++智能指针
  • 2.epoll实现的echo服务器
    • 日志
    • 套接字
    • CMake
    • epoll封装
    • 主函数
    • 服务器

1.代码基础

1.1某类唯一存在

这段代码定义了一个名为 nocopy 的类,它旨在防止该类的实例被复制或赋值。这是通过在类中显式删除拷贝构造函数(nocopy(const nocopy &))和赋值操作符(const nocopy &operator=(const nocopy &))来实现的。

拷贝构造函数(Copy Constructor)
拷贝构造函数是一种特殊的构造函数,用于创建一个新对象作为另一个同类型对象的副本。在 nocopy 类中,拷贝构造函数被声明为 = delete,这意味着如果尝试使用拷贝构造函数来创建 nocopy 类的实例的副本,编译器将报错。这确保了 nocopy 类的实例不能通过拷贝构造函数进行复制。

赋值操作符(Assignment Operator)
赋值操作符用于将一个对象的状态(即其成员变量的值)复制到另一个同类型的对象。同样地,在 nocopy 类中,赋值操作符也被声明为 = delete,这意味着如果尝试将一个 nocopy 类的实例赋值给另一个同类型的实例,编译器将报错。这确保了 nocopy 类的实例不能通过赋值操作符进行赋值。

使用场景
资源管理:当类的实例管理着重要的资源(如文件句柄、网络连接、动态分配的内存等)时,可能需要防止这些资源被无意中复制或赋值,以避免资源泄露或不可预测的行为。
唯一性保证:在需要确保某个类的实例在程序中唯一存在的场景中,禁用拷贝和赋值操作可以强制实现这一点。

示例
cpp
#include <iostream>  class nocopy  
{  
public:  nocopy() { std::cout << "nocopy constructed\n"; }  nocopy(const nocopy &) = delete;  const nocopy &operator=(const nocopy &) = delete;  
};  int main() {  nocopy obj1; // 正确:调用构造函数  // nocopy obj2 = obj1; // 错误:拷贝构造函数被删除  // obj1 = obj2; // 错误:赋值操作符被删除  return 0;  
}

在这个示例中,尝试使用拷贝构造函数或赋值操作符会导致编译错误,因为它们都已被删除。

当一个类(如你提供的nocopy类)被设计成不允许被拷贝(通过拷贝构造函数)或赋值(通过赋值运算符),这通常是为了确保该类的实例在程序中的唯一性或特定的生命周期管理策略。当其他类继承这个nocopy类时,它们也继承了这些不允许拷贝和赋值的特性,这带来了几个重要的意义和目的:

  1. 防止浅拷贝问题:对于包含动态分配资源(如指针指向的内存、文件句柄等)的类,如果允许拷贝,可能会导致多个对象实例共享相同的资源,从而引发数据竞争、资源泄露等问题。通过禁止拷贝,可以确保每个对象都管理自己独立的资源,从而避免这些问题。
  2. 实现单例模式:单例模式是一种确保类只有一个实例,并提供一个全局访问点的设计模式。通过继承nocopy类,可以很容易地实现一个单例类,因为它自然就不允许通过拷贝来创建额外的实例。
  3. 确保对象唯一性:在某些情况下,可能希望确保某个类的所有实例在逻辑上都是唯一的,或者至少在某些方面(如标识符、配置等)是唯一的。通过禁止拷贝和赋值,可以强制要求使用其他机制(如工厂方法、依赖注入等)来创建和管理这些对象的实例,从而有助于维护这种唯一性。
  4. 强化不可变性和线程安全:对于设计为不可变(immutable)的类,禁止拷贝和赋值可以进一步强调其不可变性,因为任何尝试修改实例(通过赋值)或创建其副本(通过拷贝)的行为都将被编译器阻止。此外,不可变对象通常更容易实现线程安全,因为它们不需要在并发访问时进行同步。
  5. 简化资源管理和生命周期:通过控制对象的拷贝和赋值行为,可以更精确地控制资源的分配和释放时机,以及对象的生命周期。这对于管理复杂资源(如网络连接、数据库连接等)的类尤为重要。
  6. 表达设计意图:通过明确禁止拷贝和赋值,类的设计者可以向使用该类的其他开发者传达关于对象如何被预期使用和管理的明确信息。这有助于减少误解和错误使用,提高代码的可维护性和可读性。
    总之,通过让其他类继承nocopy类并继承其不允许拷贝和赋值的特性,可以在多个方面提高代码的健壮性、安全性和可维护性。

1.2C++智能指针

C++标准库提供的一种用于自动管理动态分配内存的指针类型。它们的主要目的是解决传统裸指针(raw pointers)在动态内存管理时容易出现的内存泄漏、重复释放等问题。智能指针通过封装裸指针并提供自动的析构函数来确保动态分配的内存被适时释放,从而简化了内存管理。

C++标准库中主要有以下几种智能指针:

std::unique_ptr:

独享所有权的智能指针。 std::unique_ptr不允许拷贝构造和拷贝赋值,但支持移动构造和移动赋值。 这意味着一个std::unique_ptr对象在任意时刻只能被一个std::unique_ptr拥有。当std::unique_ptr被销毁时(例如,离开作用域),它所指向的对象也会被自动删除。

std::shared_ptr:

共享所有权的智能指针。 多个std::shared_ptr实例可以指向同一个对象,并通过内部的控制块(通常是一个计数器)来跟踪有多少std::shared_ptr指向该对象。当最后一个指向该对象的std::shared_ptr被销毁时,对象才会被删除。std::shared_ptr支持拷贝构造和拷贝赋值,这使得它们非常适合在复杂的数据结构或算法中共享所有权。

std::weak_ptr:

std::weak_ptr是一种不拥有其所指对象的智能指针。它主要用于解决std::shared_ptr之间的循环引用问题。std::weak_ptr可以指向一个由std::shared_ptr管理的对象,但它不增加对象的共享计数。因此,当所有的std::shared_ptr都被销毁时,即使还有std::weak_ptr指向该对象,对象也会被销毁。std::weak_ptr提供了一个lock成员函数,用于尝试获取一个指向对象的std::shared_ptr,如果对象还存在,则返回一个有效的std::shared_ptr;否则,返回一个空的std::shared_ptr。

智能指针的使用使得C++中的动态内存管理更加安全和方便,减少了内存泄漏和野指针的风险。然而,开发者仍然需要谨慎使用它们,特别是在复杂的所有权关系和生命周期管理中。
复习好文!

2.epoll实现的echo服务器

日志

#pragma once#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>#define SIZE 1024#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4#define Screen 1
#define Onefile 2
#define Classfile 3#define LogFile "log.txt"class Log
{
private:int printMethod;std::string path;public:Log(){printMethod = Screen;path = "./";}void Enable(int method){printMethod = method;}std::string levelToString(int level){switch (level){case Info:return "Info";case Debug:return "Debug";case Warning:return "Warning";case Error:return "Error";case Fatal:return "Fatal";default:return "None";}}/*void logmessage(int level, const char *format, ...){time_t t = time(nullptr);struct tm *ctime = localtime(&t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式:默认部分+自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);// printf("%s", logtxt);printLog(level, logtxt);}*/// lg(Warning, "accept error, %s: %d", strerror(errno), errno);void operator()(int level, const char *msg_format, ...){time_t timestamp = time(nullptr);struct tm *ctime = localtime(&timestamp);//level 年月日char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,ctime->tm_hour, ctime->tm_min, ctime->tm_sec);//自定义msgva_list arg_list;//存储可变参数列表信息va_start(arg_list, msg_format);//初始化 使其指向函数参数列表中format参数之后的第一个可变参数char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), msg_format, arg_list);va_end(arg_list);//清理va_list变量// 格式:默认部分+自定义部分char log_content[SIZE * 2];snprintf(log_content, sizeof(log_content), "%s %s", leftbuffer, rightbuffer);// printf("%s", logtxt); // 暂时打印printLog(level, log_content);}void printLog(int level, const std::string &log_content){switch (printMethod){case Screen:std::cout << log_content << std::endl;break;case Onefile:printOneFile(LogFile, log_content);break;case Classfile:printClassFile(level, log_content);break;default:break;}}void printOneFile(const std::string &log_filename, const std::string &log_content){//path = "./"; #define LogFile "log.txt"std::string _logFilename = path + log_filename;int fd = open(_logFilename.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // "log.txt"if (fd < 0)return;write(fd, log_content.c_str(), log_content.size());close(fd);}void printClassFile(int level, const std::string &log_content){//#define LogFile "log.txt"std::string filename = LogFile;filename += ".";filename += levelToString(level); // "log.txt.Debug"printOneFile(filename, log_content);}~Log(){}
};Log lg;/*
int sum(int n, ...)
{va_list s; // char*va_start(s, n);int sum = 0;while(n){sum += va_arg(s, int); // printf("hello %d, hello %s, hello %c, hello %d,", 1, "hello", 'c', 123);n--;}va_end(s); //s = NULLreturn sum;
}
*/

套接字

#pragma once#include <iostream>
#include <string>
#include <unistd.h>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "Log.hpp"enum
{SocketErr = 2,BindErr,ListenErr,
};const int g_backlog = 10;class Sock
{
private:int _sockfd;public:Sock(){}~Sock(){}public:void Socket(){_sockfd = socket(AF_INET, SOCK_STREAM, 0);if (_sockfd < 0){lg(Fatal, "socker error, %s: %d", strerror(errno), errno);exit(SocketErr);}}void Bind(uint16_t port){struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port);local.sin_addr.s_addr = INADDR_ANY;if (bind(_sockfd, (struct sockaddr *)&local, sizeof(local)) < 0){lg(Fatal, "bind error, %s: %d", strerror(errno), errno);exit(BindErr);}}void Listen(){if (listen(_sockfd, g_backlog) < 0){lg(Fatal, "listen error, %s: %d", strerror(errno), errno);exit(ListenErr);}}int Accept(std::string *clientip, uint16_t *clientport){struct sockaddr_in peer;socklen_t len = sizeof(peer);int newfd = accept(_sockfd, (struct sockaddr *)&peer, &len);if (newfd < 0){lg(Warning, "accept error, %s: %d", strerror(errno), errno);return -1;}char ipstr[64];inet_ntop(AF_INET, &peer.sin_addr, ipstr, sizeof(ipstr));*clientip = ipstr;*clientport = ntohs(peer.sin_port);return newfd;}bool Connect(const std::string &ip, const uint16_t &port){struct sockaddr_in peer;memset(&peer, 0, sizeof(peer));peer.sin_family = AF_INET;peer.sin_port = htons(port);inet_pton(AF_INET, ip.c_str(), &(peer.sin_addr));int n = connect(_sockfd, (struct sockaddr *)&peer, sizeof(peer));if (n == -1){std::cerr << "connect to " << ip << ":" << port << " error" << std::endl;return false;}return true;}void CloseFd(){close(_sockfd);}int getSocketFd(){return _sockfd;}
};

CMake

cmake_minimum_required(VERSION 3.29)
set(CMAKE_CXX_STANDARD 11)  
set(CMAKE_CXX_STANDARD_REQUIRED True)project(EpollServer)add_executable(epoll_server Main.cc)

epoll封装

#pragma once#include "nocopy.hpp"
#include "Log.hpp"
#include <cerrno>
#include <cstring>
#include <sys/epoll.h>class Epoller : public nocopy
{static const int size = 128;private:int _epollFd;int _timeout{3000};public:Epoller(){_epollFd = epoll_create(size);if (_epollFd == -1)lg(Error, "epoll_create error: %s", strerror(errno));elselg(Info, "epoll_create success: %d", _epollFd);}int EpllerUpdate(int oper, int sock, uint32_t event){// int epoll_ctl(int __epfd, int __op, int __fd, epoll_event *)int n = 0;if (oper == EPOLL_CTL_DEL){n = epoll_ctl(_epollFd, oper, sock, nullptr);if (n != 0)lg(Error, "epoll_ctl delete error!");}else // EPOLL_CTL_MOD || EPOLL_CTL_ADD{/*typedef union epoll_data{void *ptr;int fd;uint32_t u32;uint64_t u64;} epoll_data_t;struct epoll_event{uint32_t events;   // Epoll eventsepoll_data_t data; // User data variable} __EPOLL_PACKED;*/struct epoll_event ev;ev.events = event;ev.data.fd = sock; // 方便后期得知 是哪一个fd就绪了n = epoll_ctl(_epollFd, oper, sock, &ev);if (n != 0)lg(Error, "epoll_ctl error!");}return n;}int EpollerWait(struct epoll_event revents[], int num){// int epoll_wait(int __epfd, epoll_event *__events, int __maxevents, int __timeout)int n = epoll_wait(_epollFd, revents, num, /*_timeout 0*/ -1);return n;}~Epoller(){if (_epollFd >= 0)close(_epollFd);}
};

主函数

#include <iostream>
#include <memory>
#include "EpollServer.hpp"int main()
{std::unique_ptr<EpollServer> epoll_svr(new EpollServer(8888));epoll_svr->Init();epoll_svr->Start();/*//无法引用 函数 "Epoller::Epoller(const Epoller &)" (已隐式声明) -- 它是已删除的函数Epoller ep;Epoller ep1 = ep;*/return 0;
}

服务器

#pragma once#include <iostream>
#include <memory>
#include <sys/epoll.h>
#include "Socket.hpp"
#include "Epoller.hpp"
#include "Log.hpp"
#include "nocopy.hpp"uint32_t EVENT_IN = (EPOLLIN);
uint32_t EVENT_OUT = (EPOLLOUT);// 此程序的read/write仍忽略了网络读取报文完整性问题 主要考虑epoll逻辑
class EpollServer : public nocopy
{static const int num = 64;private:std::shared_ptr<Epoller> _epollerPtr;std::shared_ptr<Sock> _listenSocketPtr;uint16_t _port;public:EpollServer(uint16_t port): _port(port),_listenSocketPtr(new Sock()),_epollerPtr(new Epoller()){}void Init(){_listenSocketPtr->Socket();_listenSocketPtr->Bind(_port);_listenSocketPtr->Listen();lg(Info, "create listen socket success: %d\n", _listenSocketPtr->getSocketFd());}void Accepter() // 获取了一个新连接{std::string clientip;uint16_t clientport;int sock = _listenSocketPtr->Accept(&clientip, &clientport);if (sock > 0){// 不能直接读取 原因select/poll已讲_epollerPtr->EpllerUpdate(EPOLL_CTL_ADD, sock, EVENT_IN);lg(Info, "get a new link, client info@ %s:%d", clientip.c_str(), clientport);}}void Recver(int fd){char buffer[1024];// 1.不一定是完整的报文// 2.读到部分报文 下次的Recver()函数中buffer是局部变量 // A报文如果发两次过来 也无法拼接成完整报文ssize_t n = read(fd, buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = 0;std::cout << "get a messge: " << buffer << std::endl;std::string echo_str = "server echo $ ";echo_str += buffer;write(fd, echo_str.c_str(), echo_str.size());}else if (n == 0){lg(Info, "client quit, me too, close fd is : %d", fd);_epollerPtr->EpllerUpdate(EPOLL_CTL_DEL, fd, 0);close(fd);}else{lg(Warning, "recv error: fd is : %d", fd);_epollerPtr->EpllerUpdate(EPOLL_CTL_DEL, fd, 0);close(fd);}}void Dispatcher(struct epoll_event revs[], int num){for (int i = 0; i < num; i++){uint32_t events = revs[i].events;int fd = revs[i].data.fd;if (events & EVENT_IN) // 客户联连接读取事件就绪{if (fd == _listenSocketPtr->getSocketFd())Accepter();else // 普通读取事件就绪Recver(fd);}// else if (events & EVENT_OUT){}// else{}}}void Start(){// 将listensock添加到epoll中 -> listensock和他关心的事件 添加到内核epoll模型中rb_tree_epollerPtr->EpllerUpdate(EPOLL_CTL_ADD, _listenSocketPtr->getSocketFd(), EVENT_IN);struct epoll_event revs[num];for (;;){int n = _epollerPtr->EpollerWait(revs, num);if (n > 0) // 有事件就绪{lg(Debug, "event happened, first event fd is : %d", revs[0].data.fd);Dispatcher(revs, n);}else if (n == 0)lg(Info, "time out ...");elselg(Error, "epll wait error");}}~EpollServer(){_listenSocketPtr->CloseFd();}
};

相关文章:

【Linux网络】epoll实现的echo服务器{nocopy类/智能指针/echo服务器}

文章目录 1.代码基础1.1某类唯一存在1.2C智能指针 2.epoll实现的echo服务器日志套接字CMakeepoll封装主函数服务器 1.代码基础 1.1某类唯一存在 这段代码定义了一个名为 nocopy 的类&#xff0c;它旨在防止该类的实例被复制或赋值。这是通过在类中显式删除拷贝构造函数&#…...

[数据集][目标检测]拐杖检测数据集VOC+YOLO格式2778张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2778 标注数量(xml文件个数)&#xff1a;2778 标注数量(txt文件个数)&#xff1a;2778 标注…...

长按加速- 解决react - setInterval下无法更新问题

最开始直接setInterval里&#xff0c;useState硬写&#xff0c;发现更新不&#xff0c;固定值 换let&#xff0c;发现dom更新不了 正确做法是用ref 并且pc端可以长按的&#xff0c;只是要用onTouchStart&#xff0c;不要用onMouseDown onTouchStart{handleMouseDown} onTou…...

路网双线合并单线——ArcGIS 解决方法

路网双线合并成单线是一个在地图制作、交通规划以及GIS分析中常见的需求。双线路网定义&#xff1a;具有不同流向、不同平面结构的道路。此外&#xff0c;车道数较多的道路&#xff08;例如&#xff0c;双黄实线车道数大于4的道路&#xff09;也可以视为双线路网&#xff0c;本…...

【.NET全栈】ASP.NET开发Web应用——ADO.NET数据访问技术

文章目录 前言一、ADO.NET基础1、ADO.NET架构2、ADO.NET数据提供者 二、连接数据库1、SqlConnection数据库连接类2、使用SqlConnectionStringBuilder连接字符串3、关闭和释放连接4、在web.config配置文件中保存连接字符串5、连接池技术 三、与数据库交互1、使用SqlCommand操作数…...

【机器学习】无监督学习和自监督学习

1. 什么是机器学习 机器学习是一种使计算机系统能够从数据中学习并做出预测或决策的技术和科学领域。它不需要显式地编程来执行特定任务&#xff0c;而是通过使用算法来分析数据和识别模式&#xff0c;以此“学习”如何做出准确的预测或决策。 以下是机器学习的几个关键点&…...

蓝牙新篇章:WebKit的Web Bluetooth API深度解析

蓝牙新篇章&#xff1a;WebKit的Web Bluetooth API深度解析 在物联网(IoT)时代&#xff0c;Web应用与物理设备的交互变得越来越重要。WebKit的Web Bluetooth API开启了一个新时代&#xff0c;允许Web页面直接与蓝牙设备通信。这一API不仅提高了用户体验&#xff0c;还为创新的…...

2024可信数据库发展大会:TDengine CEO 陶建辉谈“做难而正确的事情”

在当前数字经济快速发展的背景下&#xff0c;可信数据库技术日益成为各行业信息化建设的关键支撑点。金融、电信、能源和政务等领域对数据处理和管理的需求不断增加&#xff0c;推动了数据库技术的创新与进步。与此同时&#xff0c;人工智能与数据库的深度融合、搜索与分析型数…...

Guns v7.3.0:基于 Vue3、Antdv 和 TypeScript 打造的开箱即用型前端框架

摘要 本文深入探讨了Guns v7.3.0前端项目&#xff0c;该项目是基于Vue3、Antdv和TypeScript的前端框架&#xff0c;以Vben Admin的脚手架为基础进行了改造。文章分析了Guns 7.3.0的技术特点&#xff0c;包括其使用Vue3、vite2和TypeScript等最新前端技术栈&#xff0c;以及提供…...

掌握构建艺术:在Gradle中配置自定义的源代码管理(SCM)

掌握构建艺术&#xff1a;在Gradle中配置自定义的源代码管理&#xff08;SCM&#xff09; 在软件开发过程中&#xff0c;源代码管理&#xff08;Source Code Management&#xff0c;简称SCM&#xff09;是不可或缺的一部分。它帮助开发者管理代码的变更历史&#xff0c;支持团…...

如何在 Mac 上下载安装植物大战僵尸杂交版? 最新版本 2.2 详细安装运行教程问题详解

植物大战僵尸杂交版已经更新至2.2了&#xff0c;但作者只支持 Windows、手机等版本并没有支持 MAC 版本&#xff0c;最近搞到了一个最新的杂交 2.2 版本的可以在 Macbook 上安装运行的移植安装包&#xff0c;试了一下非常完美能够正常在 MAC 上安装运行&#xff0c;看图&#x…...

​前端Vue组件技术实践:打造自定义精美悬浮菜单按钮组件

随着前端技术的迅猛发展&#xff0c;复杂的应用场景和不断迭代的产品需求使得开发的复杂度日益提升。传统的整体式开发方式已经难以满足现代前端应用的灵活性和可维护性需求。在这样的背景下&#xff0c;组件化开发逐渐崭露头角&#xff0c;成为解决复杂前端应用问题的有效手段…...

数据仓库的一致性维度

一致性维度的定义&#xff1a; 一致性维度是指在数据仓库中&#xff0c;具有相同属性和含义的维度在不同的事实表中保持一致。它确保了通过不同事实表进行查询和分析时&#xff0c;维度数据的一致性和准确性。 一致性维度的作用&#xff1a; 数据一致性&#xff1a;一致性维度…...

【ffmpeg命令】RTMP推流

文章目录 前言推流是什么RTMP协议简介RTMP的基本概念RTMP的工作原理RTMP的优缺点 ffmpeg RTMP推流推流命令综合解释ffplay播放RTMP流 总结 前言 在现代的视频直播中&#xff0c;RTMP&#xff08;Real-Time Messaging Protocol&#xff09;是一种广泛使用的流媒体传输协议。它允…...

人工智能大模型发展的新形势及其省思

作者简介 肖仰华&#xff0c;复旦大学计算机科学技术学院教授、博导&#xff0c;上海市数据科学重点实验室主任。研究方向为知识图谱、知识工程、大数据管理与挖掘。主要著作有《图对称性理论及其在数据管理中的应用》、《知识图谱&#xff1a;概念与技术》&#xff08;合著&a…...

Linux云计算 |【第一阶段】SERVICES-DAY4

主要内容&#xff1a; DHCP概述、PXE批量装机、配置PXE引导、Kickstart自动应答、Cobbler装机平台 一、DHCP服务概述及原理 DHCP动态主机配置协议&#xff08;Dynamic Host Configuration Protocol&#xff09;&#xff0c;由IETF&#xff08;Internet网络工程师任务小组&…...

微信小程序 button样式设置为图片的方法

微信小程序 button样式设置为图片的方法 background-image background-size与background-repeat与border:none;是button必须的 <view style" position: relative;"><button class"customer-service-btn" style"background-image: url(./st…...

2024 HNCTF PWN(hide_flag Rand_file_dockerfile Appetizers TTOCrv_)

文章目录 参考hide_flag思路exp Rand_file_dockerfile libc 2.31思路exp Appetizers glibc 2.35绕过关闭标准输出实例客户端 关闭标准输出服务端结果exp TTOCrv_&#x1f3b2; glibc 2.35逆向DT_DEBUG获得各个库地址随机数思路exp 参考 https://docs.qq.com/doc/p/641e8742c39…...

《昇思25天学习打卡营第25天|第14天》

今天是打卡的第十四天&#xff0c;今天学习的是应用实践中的热门LLM及其他AI应用的K近邻算法实现红酒分类篇。这一片主要介绍使用MindSpore在部分wine数据集上进行KNN实验&#xff0c;对实验的步骤的介绍&#xff1a;K近邻算法原理介绍&#xff08;分类问题、回归问题和距离的定…...

Easysearch、Elasticsearch、Amazon OpenSearch 快照兼容对比

在当今的数据驱动时代&#xff0c;搜索引擎的快照功能在数据保护和灾难恢复中至关重要。本文将对 EasySearch、Elasticsearch 和 Amazon OpenSearch 的快照兼容性进行比较&#xff0c;分析它们在快照创建、恢复、存储格式和跨平台兼容性等方面的特点&#xff0c;帮助大家更好地…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成

一个面向 Java 开发者的 Sring-Ai 示例工程项目&#xff0c;该项目是一个 Spring AI 快速入门的样例工程项目&#xff0c;旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计&#xff0c;每个模块都专注于特定的功能领域&#xff0c;便于学习和…...