Linux:epoll模式web服务器代码,代码debug
源码:
https://blog.csdn.net/weixin_44718794/article/details/107206136
修改的地方:
修改后代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
//#include “epoll_server.h”
#ifndef _EPOLL_SERVER_H
#define _EPOLL_SERVER_H
int init_listen_fd(int port, int epfd);
void epoll_run(int port);
void do_accept(int lfd, int epfd);
void do_read(int cfd, int epfd);
int get_line(int sock, char buf, int size);
void disconnect(int cfd, int epfd);
void http_request(const char request, int cfd);
void send_respond_head(int cfd, int no, const char* desp, const char* type, long len);
void send_file(int cfd, const char* filename);
void send_dir(int cfd, const char* dirname);
void encode_str(char* to, int tosize, const char* from);
void decode_str(char *to, char *from);
const char *get_file_type(const char *name);
#endif
int main(int argc, const char* argv[]){
if(argc < 3){
printf(“eg: ./a.out port path\n”);
exit(1);
}
// 端口 字符串转整数
int port = atoi(argv[1]);// 修改进程的工作目录, 方便后续操作
int ret = chdir(argv[2]);
if(ret == -1){perror("chdir error");exit(1);
}
// 启动epoll模型
epoll_run(port);
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/stat.h>
#include <ctype.h>
//#include “epoll_server.h”
#define MAXSIZE 2000
void epoll_run(int port) {
// 创建一个epoll树的根节点
int epfd = epoll_create(MAXSIZE);
if (epfd == -1) {perror("epoll_create error");exit(1);
}// 添加要监听的节点
// 先添加监听lfd
int lfd = init_listen_fd(port, epfd);// 委托内核检测添加到树上的节点
struct epoll_event all[MAXSIZE];
while (1) {//epfd是epoll树的根节点,如果有树上某个文件描述符对应的缓冲区发生了变换//则会被拷贝到结构体数组all中// MAXSIZE是数组的大小, -1是一直阻塞,直到有节点发生变化的时候再发生返回//返回值ret是发生变化的文件描述符个数int ret = epoll_wait(epfd, all, MAXSIZE, -1);if (ret == -1) {perror("epoll_wait error");exit(1);}// 遍历发生变化的节点int i = 0;for (i = 0; i < ret; ++i) {// 只处理读事件, 其他事件默认不处理struct epoll_event *pev = &all[i];if (!(pev->events & EPOLLIN)) {// 不是读事件continue;}if (pev->data.fd == lfd) {// 接受连接请求do_accept(lfd, epfd);}else {// 读数据do_read(pev->data.fd, epfd);}}
}
}
// 读数据
void do_read(int cfd, int epfd) {
// 将浏览器发过来的数据, 读到buf中
char line[1024] = { 0 };
// 读请求行
int len = get_line(cfd, line, sizeof(line));//get_line调用的是recv,recv返回值为0则说明客户端断开了链接
if (len == 0) {printf("客户端cfd(%d)断开了连接...\n",cfd);// 关闭套接字, cfd从epoll上删除disconnect(cfd, epfd);
}
//recv失败了
else if (len == -1) {// perror("recv error"); // delete michael // exit(1); // delete michael
}
else {printf("cfd(%d)请求行数据: %s",cfd, line);printf("cfd(%d)============= 请求头 ============\n",cfd);// 还有数据没读完,继续读while (len > 0) { // michael change for (len) to (len > 0)char buf[1024] = { 0 };len = get_line(cfd, buf, sizeof(buf));printf("cfd:%d-----: %s", cfd,buf);sleep(0.2);//michael add}printf("cfd: %d============= The End ============\n",cfd);
}// 请求行: get /xxx http/1.1
// 判断是不是get请求 strncasecmp函数用于比较两个字符串,不区分大小写的比较前n个字符
if (strncasecmp("get", line, 3) == 0) {// 处理http请求http_request(line, cfd);// 关闭套接字, cfd从epoll上deldisconnect(cfd, epfd);
}
}
// 断开连接的函数
void disconnect(int cfd, int epfd) {
int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, cfd, NULL);
if (ret == -1) {
perror(“epoll_ctl del cfd error”);
exit(1);
}
close(cfd);
}
// http请求处理,传入request和
void http_request(const char* request, int cfd) {
// 拆分http请求行
// get /xxx http/1.1
char method[12], path[1024], protocol[12];
//%[^ ]匹配遇到空格为止
sscanf(request, "%[^ ] %[^ ] %[^ ]", method, path, protocol);printf("method = %s, path = %s, protocol = %s\n", method, path, protocol);// 转码 将不能识别的中文乱码 - > 中文
// 解码 %23 %34 %5f
decode_str(path, path);
// 处理path /xx(有可能是目录,也有可能是文件)
// 去掉path中的/
char* file = path + 1;
// 如果没有指定访问的资源, 默认显示资源目录中的内容
if (strcmp(path, "/") == 0) {// file的值, 资源目录的当前位置file = "./";
}// 获取文件属性
struct stat st;
int ret = stat(file, &st);
if (ret == -1) { //michael delete// show 404send_respond_head(cfd, 404, "File Not Found", ".html", -1);send_file(cfd, "404.html");
}// 判断是目录还是文件
// 如果是目录
if (S_ISDIR(st.st_mode)) {// 发送头信息send_respond_head(cfd, 200, "OK", get_file_type(".html"), -1);// 发送目录信息send_dir(cfd, file);
}
else if (S_ISREG(st.st_mode))
{// 文件// 发送消息报头send_respond_head(cfd, 200, "OK", get_file_type(file), st.st_size);// 发送文件内容send_file(cfd, file);
}
}
// 发送目录内容,拼写一个html表格
void send_dir(int cfd, const char* dirname) {
// 拼一个html页面<table></table> table可以显示多行多列,便于显示文件信息
char buf[4096] = { 0 };//目录名
sprintf(buf, "<html><head><title>目录名: %s</title></head>", dirname);
//当前目录
sprintf(buf + strlen(buf), "<body><h1>当前目录: %s</h1><table>", dirname);/*-------------------------------获取当前目录中的所有内容---------------------------*/
char enstr[1024] = { 0 };
char path[1024] = { 0 };// 目录项二级指针
struct dirent** ptr;
int num = scandir(dirname, &ptr, NULL, alphasort);// 遍历
int i = 0;
for (i = 0; i < num; ++i){//获取文件名char* name = ptr[i]->d_name;// 拼接文件的完整路径sprintf(path, "%s/%s", dirname, name);printf("michael add path = %s ===================\n", path);struct stat st;stat(path, &st);encode_str(enstr, sizeof(enstr), name);// 如果是文件if (S_ISREG(st.st_mode)){sprintf(buf + strlen(buf),"<tr><td><a href=\"%s\">%s</a></td><td>%ld</td></tr>",enstr, name, (long)st.st_size);}// 如果是目录else if (S_ISDIR(st.st_mode)){sprintf(buf + strlen(buf),"<tr><td><a href=\"%s/\">%s/</a></td><td>%ld</td></tr>",enstr, name, (long)st.st_size);}//每循环一次就发送异常,清空buf,防止buf溢出send(cfd, buf, strlen(buf), 0);memset(buf, 0, sizeof(buf));// 字符串拼接
}sprintf(buf + strlen(buf), "</table></body></html>");
send(cfd, buf, strlen(buf), 0);printf("dir message send OK!!!!\n");
#if 0
// 打开目录
DIR* dir = opendir(dirname);
if (dir == NULL){
perror(“opendir error”);
exit(1);
}
// 读目录
struct dirent* ptr = NULL;
while ((ptr = readdir(dir)) != NULL){char* name = ptr->d_name;
}
closedir(dir);
#endif
}
// 发送响应头 cfd(服务器和浏览器通讯的文件描述符),no(状态码)
//desp(对状态码的描述),type(Content-Type),len(发送的数据长度)
void send_respond_head(int cfd, int no, const char* desp, const char* type, long len) {
char buf[1024] = { 0 };
// 状态行 http不区分大小写
sprintf(buf, "http/1.1 %d %s\r\n", no, desp);
//防止buf溢出,先把里面的数据发送出去
send(cfd, buf, strlen(buf), 0);// 消息报头
sprintf(buf, "Content-Type:%s\r\n", type);
sprintf(buf + strlen(buf), "Content-Length:%ld\r\n", len);
send(cfd, buf, strlen(buf), 0);// 空行
send(cfd, "\r\n", 2, 0);
}
// 发送文件
void send_file(int cfd, const char* filename){
// 打开文件
int fd = open(filename, O_RDONLY);
if (fd == -1){
// show 404
return;
}
// 循环读文件
char buf[4096] = { 0 };
int len = 0;
while ((len = read(fd, buf, sizeof(buf))) > 0){// 发送读出的数据send(cfd, buf, len, 0);
}
if (len == -1){// perror("read file error"); // delete michael // exit(1); // delete michael
}close(fd);
}
// 解析http请求消息的每一行内容
int get_line(int sock, char *buf, int size) {
int i = 0;
char c = ‘\0’;
int n;
//每次读一个字节,判断合理就放入缓冲区中
while ((i < size - 1) && (c != ‘\n’)) {
n = recv(sock, &c, 1, 0);
if (n > 0) {
if (c == ‘\r’) {
//MSG_PEEK 使得recv以拷贝的方式从缓冲区中读取数据(否则读取之后,缓冲区中的数据就没了)
//试探性的获取缓冲区中的数据量
n = recv(sock, &c, 1, MSG_PEEK);
//缓冲区中有数据并且结尾是 \n ,则读取数据
if ((n > 0) && (c == ‘\n’)) {
recv(sock, &c, 1, 0);
}
else {
c = ‘\n’;
}
}
buf[i] = c;
i++;
}
else {
c = ‘\n’;
}
}
buf[i] = ‘\0’;
//recv失败
if (n == -1) {i = -1;
}return i;
}
// 接受新连接处理
void do_accept(int lfd, int epfd) {
struct sockaddr_in client;
socklen_t len = sizeof(client);
int cfd = accept(lfd, (struct sockaddr*)&client, &len);
if (cfd == -1) {
perror(“accept error”);
exit(1);
}
// 打印客户端信息
char ip[64] = { 0 };
//inet_ntop大端整型转淀粉十进制ip地址
printf("New Client IP: %s, Port: %d, cfd = %d\n",inet_ntop(AF_INET, &client.sin_addr.s_addr, ip, sizeof(ip)),ntohs(client.sin_port), cfd);// 设置cfd为非阻塞(默认是阻塞的)
int flag = fcntl(cfd, F_GETFL);
flag |= O_NONBLOCK; //非阻塞
fcntl(cfd, F_SETFL, flag);// 得到的新节点挂到epoll树上
struct epoll_event ev;
ev.data.fd = cfd;
// 边沿非阻塞模式
ev.events = EPOLLIN | EPOLLET;
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
if (ret == -1) {perror("epoll_ctl add cfd error");exit(1);
}
}
//初始化监听,传入端口号和epoll书的根节点
int init_listen_fd(int port, int epfd) {
// 创建监听的套接字
int lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd == -1) {perror("socket error");exit(1);
}// lfd绑定本地IP和port
struct sockaddr_in serv;
memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(port);
serv.sin_addr.s_addr = htonl(INADDR_ANY);// 端口复用
int flag = 1;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv)); //绑定
if (ret == -1) {perror("bind error");exit(1);
}// 设置监听,最大是128,这里写个64是随意写的
ret = listen(lfd, 64);
if (ret == -1) {perror("listen error");exit(1);
}// lfd添加到epoll树上
struct epoll_event ev; //创建节点
ev.events = EPOLLIN;
ev.data.fd = lfd;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev); //把节点挂上
if (ret == -1) {perror("epoll_ctl add lfd error");exit(1);
}return lfd;
}
// 16进制数转化为10进制
int hexit(char c) {
if (c >= ‘0’ && c <= ‘9’)
return c - ‘0’;
if (c >= ‘a’ && c <= ‘f’)
return c - ‘a’ + 10;
if (c >= ‘A’ && c <= ‘F’)
return c - ‘A’ + 10;
return 0;
}
//字符转成16进制数
void encode_str(char* to, int tosize, const char* from) {
int tolen;
for (tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from) {//isalnum判断字符是不是数字(判断字符是否需要解码)//http协议中, /_.~这四个不需要转if (isalnum(*from) || strchr("/_.-~", *from) != (char*)0) {//不需要转,则原封不动的拷贝一份*to = *from;++to;++tolen;}else {//字符转成十六进制数—— *from取字符值,然后与十六进制数字做按位与sprintf(to, "%%%02x", (int)*from & 0xff);//to永远指向字符从末尾to += 3;tolen += 3;}
}
*to = '\0';
}
//编码,用作回写浏览器的时候,将除字母、数字以及 /_.~以外的字符转义后回写
//将16进制数转换成字符
void decode_str(char *to, char *from) {
for (; *from != ‘\0’; ++to, ++from) {
//十六进制转十进制
if (from[0] == ‘%’ && isxdigit(from[1]) && isxdigit(from[2])) {
//依次判断from中 %20 三个字符
*to = hexit(from[1]) * 16 + hexit(from[2]);
//移除已经处理的两个字符
from += 2;
}else {
*to = *from;
}
}
*to = ‘\0’;
}
// 通过文件名获取文件的类型
const char *get_file_type(const char name){
char dot;
// 自右向左查找‘.’字符, 如不存在返回NULL
dot = strrchr(name, '.');
if (dot == NULL)return "text/plain; charset=utf-8";
if (strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0)return "text/html; charset=utf-8";
if (strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0)return "image/jpeg";
if (strcmp(dot, ".gif") == 0)return "image/gif";
if (strcmp(dot, ".png") == 0)return "image/png";
if (strcmp(dot, ".css") == 0)return "text/css";
if (strcmp(dot, ".au") == 0)return "audio/basic";
if (strcmp(dot, ".wav") == 0)return "audio/wav";
if (strcmp(dot, ".avi") == 0)return "video/x-msvideo";
if (strcmp(dot, ".mov") == 0 || strcmp(dot, ".qt") == 0)return "video/quicktime";
if (strcmp(dot, ".mpeg") == 0 || strcmp(dot, ".mpe") == 0)return "video/mpeg";
if (strcmp(dot, ".vrml") == 0 || strcmp(dot, ".wrl") == 0)return "model/vrml";
if (strcmp(dot, ".midi") == 0 || strcmp(dot, ".mid") == 0)return "audio/midi";
if (strcmp(dot, ".mp3") == 0)return "audio/mpeg";
if (strcmp(dot, ".ogg") == 0)return "application/ogg";
if (strcmp(dot, ".pac") == 0)return "application/x-ns-proxy-autoconfig";return "text/plain; charset=utf-8";
}
结果:
相关文章:

Linux:epoll模式web服务器代码,代码debug
源码: https://blog.csdn.net/weixin_44718794/article/details/107206136 修改的地方: 修改后代码: #include <stdio.h> #include <unistd.h> #include <stdlib.h> //#include “epoll_server.h” #ifndef _EPOLL_SER…...

SpringSecurity学习(四)密码加密、RememberMe记住我
文章目录密码加密一、简介密码为什么要加密常见的加密解决方案PasswordEncoder详解DelegatingPasswordEncoder二、自定义加密方式1. 使用灵活的密码加密方案(BCryptPasswordEncoder)加密验证(推荐)需要在密码前指定加密类型{bcryp…...

vue专项练习
一、循环实现一个列表的展示及删除功能 1.1 列表展示 1、背景: 完成一个这样的列表展示。使用v-for 循环功能 id接口名称测试人员项目名项目ID描述信息创建时间用例数1首页喵酱发财项目a1case的描述信息2019/11/6 14:50:30102个人中心张三发财项目a1case的描述信…...
【笔试题】百度+美团
发工资 链接:https://www.nowcoder.com/questionTerminal/e47cffeef25d43e3b16c11c9b28ac7e8 来源:牛客网 小度新聘请了一名员工牛牛, 每个月小度需要给牛牛至少发放m元工资(给牛牛发放的工资可以等于m元或者大于m元, 不能低于m)。 小度有一些钞票资金…...

【8.索引篇】
索引分类 索引和数据就是位于存储引擎中: 按「数据结构」分类:Btree索引、Hash索引、Full-text索引。按「物理存储」分类:聚簇索引(主键索引)、二级索引(辅助索引)。按「字段特性」分类&#…...

MySQL InnoDB存储引擎锁与事务实现原理解析(未完成)
InnoDB MySQL存储引擎是基于表的,也就是说每张表可以选择不同的存储引擎。 InnoDB存储引擎的表是索引组织的,也就是数据即索引。 存储引擎文件 InnoDB引擎会包含RedoLog重做日志文件和TableSpace表空间文件。 表空间文件 默认表空间文件(…...
P1683 入门(洛谷)JAVA
题目描述: 不是任何人都可以进入桃花岛的,黄药师最讨厌像郭靖一样呆头呆脑的人。所以,他在桃花岛的唯一入口处修了一条小路,这条小路全部用正方形瓷砖铺设而成。有的瓷砖可以踩,我们认为是安全的,而有的瓷砖…...

yocto编译烧录和脚本解析
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、初始化构建目录二、imx-setup-release.sh脚本解析三、编译单独编译内核四、烧录总结前言 本篇文章主要讲解如何在下载好源码之后进行编译和yocto的脚本解析…...
Proteus 8.15安装包安装教程
Proteus介绍Proteus的介绍Proteus8.15安装包Proteus8.15安装教程Proteus的介绍 Proteus是英国著名的EDA工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。是世界上唯…...

Spring——AOP工作流程
AOP就是代理模式的开发简化 1.Spring容器启动 因为AOP是要将通知类作为一个bean对象交给spring进行管理的,还有经过通知类被增强的类。 此时还没有创建bean对象 2.读取所有切面配置中的切入点 在下面这段代码中,定义了两个切入点,但是只…...
c++11多线程之condition_variable、wait()、notify_one()、notify_all()的使用。
系列文章目录 文章目录系列文章目录前言一、基本概念1.1 std::condition_variable1.2 wait()函数1.2.1 wait()带第二个参数1.2.2 wait()不带第二个参数1.2.3 当其他线程用notify_one()或notify_all()1.3 notify函数二、代码实例总结前言 C11多线程&…...
skywalking扩展实现 —— 监控数据的动态上报
把标题名整高大上一些,来掩盖需求的奇葩。 0. 目录1. 需求背景2. 需求描述3. 优势4. 实现4.1 扩展点4.2 配置项5. 优化6. 提醒7. 补充 - 关于微服务8. 参考1. 需求背景 过去一段时间,接手了一个迭代了数年的"基于微服务架构"搭建的产品。 自…...
【GoF 23】23种设计模式与OOP七大原则概述
1. 什么是GoF 23? GoF 23也就是23种设计模式。1995年GoF(Gang of Four,四人组/四人帮)合作出版了《设计模式:可复用面向对象软件的基础》一书,一共收录了23种设计模式,从此梳理了软件设计模式领…...
Java 日期时间
Java 日期时间是 Java 标准库中一个非常重要的部分,它提供了丰富的 API 来处理日期、时间以及日期时间。在 Java 应用程序中,我们经常需要处理日期时间相关的操作,例如计算两个日期之间的差、将日期时间转换为不同的时区等。在本篇文章中&…...

Face Forgery Suvery
文章目录Face ForgeryFace Forgery classAttribute ManipulationExpression SwapIdentity SwapEntire Face SynthesisFace Forgery DetectionLow-levelOn the Detection of Digital Face Manipulation(CVPR2020)High-levelProtecting World Leaders Against Deep FakesDetectin…...

案例学习--016 消息队列作用和意义
简介MQ全称为Message Queue, 是一种分布式应用程序的的通信方法,它是消费-生产者模型的一个典型的代表,producer往消息队列中不断写入消息,而另一端consumer则可以读取或者订阅队列中的消息。主要产品有:ActiveMQ、RocketMQ、Rabb…...

【MySQL】MySQL的锁机制
目录 概述 MyISAM 表锁 InnoDB行锁 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制(避免争抢)。 在数据库中,除传统的 计算资源(如 CPU、RAM、I/O 等)的争用以外,数据也是一种供许多用户共…...
HTML 背景
一个富有美感的背景会让站点看上去更加高级、更有吸引力。本篇为大家来的是 HTML 背景相关内容。 背景(Backgrounds) <body> 拥有两个配置背景的标签。背景可以是颜色或者图像。 背景颜色(Bgcolor) 背景颜色属性将背景设…...
Lombok
文章目录简介原理安装常用Getter、SetterToStringEqualsAndHashCodeNonNullNoArgsConstructor、RequiredArgsConstructor、AllArgsConstructorDATABuilderLogvalCleanup简介 Project Lombok is a java library that automatically plugs into your editor and build tools, spi…...

Koa源码学习
前言 koa是一个非常流行的Node.js http框架。本文我们来学习下它的使用和相关源码 来自官网的介绍: Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...

企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...

6.9-QT模拟计算器
源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...