基于tcp协议及数据库sqlite3的云词典项目
数据库创建及导入单词表
#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char const *argv[])
{// 1.打开或创建数据库
sqlite3 *db = NULL;int rc;if (sqlite3_open("./word.db", &db) != SQLITE_OK)//打开或创建库{printf("sqlite3_open err:%s\n", sqlite3_errmsg(db));return -1;}printf("sqlite3_open success\n");// 2.创建表char *errmsg = NULL;//返回创建数据库表的错误//创建一个两列的单词表,用于存储单词及注释if (sqlite3_exec(db, "create table if not exists wd1 (word char, annotation char);", NULL, NULL, &errmsg) != SQLITE_OK){printf("create err: %sn", errmsg);sqlite3_close(db); return -1;}//创建一个两列的账户表,用于存储账户名及对应密码if (sqlite3_exec(db, "create table if not exists user (name char, password char);", NULL, NULL, &errmsg) != SQLITE_OK){printf("create err: %sn", errmsg);sqlite3_close(db);return -1;}printf("create success\n");// 3.向表中插入数据
FILE *fp = fopen(argv[1], "r");//打开要插入的文件流if (fp == NULL){printf("failed to open file\n");sqlite3_close(db);return -1;}char buf[1024]; //读取的一行char word[32]; //单词char ant[1024]; //保存注释while (fgets(buf, sizeof(buf), fp) != NULL) //读一行{sscanf(buf, "%99[^ ] %256[^\n]", word, ant); //将第一个单词放到单词数组中,后面的内容放到注释数组中char sql[1024];//存放命令内容sprintf(sql, "insert into wd1 values(\"%s\", \"%s\");", word, ant); // 构造插入语句,将单词及注释插入到单词表中
rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);if (rc != SQLITE_OK){printf("insert err: %s\n", errmsg);return -1;}}fclose(fp);//关闭文件描述符// 5.关闭数据库连接sqlite3_close(db);return 0;
} 头函数及传输协议
#ifndef __HEAD_H__
#define __HEAD_H__//防止重包含
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define N 32
enum type_t //运行命令
{
R=4, //register注册
L, //login登录
Q, //query搜索
H, //history历史
};
typedef struct //数据包结构体
{
int type;//执行命令类型
char name[N]; //用户名
char data[1024]; //密码或要查询的单词
} MSG_t;
typedef struct node_t
{
struct sockaddr_in addr; //ip地址
struct node_t *next; //链表下一个地址
} list_t;
#endif 云词典服务器端
/*服务器创建代码 */
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include <signal.h>
#include <sys/select.h>
#include <time.h>
#include <sys/time.h>
#include "head.h"
MSG_t msg;
int n;
sqlite3 *db = NULL; //命令输入
char *errmsg = NULL; //错误码
int hang, lie; //数据库行和列
int k = 0;
int Register(sqlite3 *db, int sockfd) //注册函数
{
char **result = NULL; //数据库返回内容
//3.向表中插入数据
//(1)执行函数
char sq1[128]; //保存命令
sprintf(sq1, "select * from user where name = \"%s\";", msg.name);
sqlite3_get_table(db, sq1, &result, &hang, &lie, &errmsg);//判断数据库中是否已经存在该账户
if (hang != 0)
{
sprintf(msg.data, "账户已存在;\n");
send(sockfd, &msg, sizeof(msg), 0);
return -1;
}
else //成功注册
{
sprintf(sq1, "insert into user values(\"%s\",\"%s\");", msg.name, msg.data);
if (sqlite3_exec(db, sq1, NULL, NULL, &errmsg) == SQLITE_OK) //""需要用\转意,注册成功插入用户表内
{
sprintf(sq1, "create table if not exists \"%s\" (word char, time char);", msg.name); //每注册一个用户创建一个新表
if (sqlite3_exec(db, sq1, NULL, NULL, &errmsg) != SQLITE_OK) //创建新表
{
printf("create err: %s", errmsg);
sqlite3_close(db);
return -1;
}
else
{
printf("creat %s success\n", msg.name);
}
sprintf(msg.data, "OK");
send(sockfd, &msg, sizeof(msg), 0); //注册成功发送消息
memset(msg.data, 0, sizeof(msg.data));
return 0;
}
else //否则插入失败
{
printf("insert value err;%s\n", errmsg);
return -1;
}
}
}
//用户登录
int loginclient(sqlite3 *db, int sockfd)
{
char **result = NULL; //数据库返回内容
char sq1[128]; //保存命令
sprintf(sq1, "select * from user where name = \"%s\";", msg.name);
sqlite3_get_table(db, sq1, &result, &hang, &lie, &errmsg); //判断数据库中是否已经存在该账户
if (hang != 0) //如果能读出内容则行数不为0
{
if (strcmp(result[3], msg.data) == 0) //判断密码是否正确
{
sprintf(msg.data, "OK");
send(sockfd, &msg, sizeof(msg), 0);
return 0;
}
else //密码错误
{
sprintf(msg.data, "password err\n");
send(sockfd, &msg, sizeof(msg), 0);
return -1;
}
}
else //反之未注册
{
sprintf(msg.data, "no register\n"); //未注册
send(sockfd, &msg, sizeof(msg), 0);
return -1;
}
}
//查询单词注释
int chatclient(sqlite3 *db, int sockfd) //查询单词函数
{
char **result = NULL; //数据库返回内容
char sq1[128]; //保存命令
sprintf(sq1, "select * from wd1 where word = \"%s\";", msg.data);
sqlite3_get_table(db, sq1, &result, &hang, &lie, &errmsg); //判断是否查到该单词
if (hang != 0)
{
sprintf(msg.data, "%s", result[3]); //将注释内容发送到客户端
send(sockfd, &msg, sizeof(msg), 0); //发送该单词注释
time_t th;
time(&th); //获取当前时间
char times[128];
struct tm *ts;
ts = localtime(&th); //将当时间转化为标准时间
sprintf(times, "%4d-%2d-%2d %2d:%2d:%2d", ts->tm_year + 1900, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec);
//先将时间放到一个字符串中,再放到命令语句中
sprintf(sq1, "insert into \"%s\" values(\"%s\", \"%s\");", msg.name, result[2], times); // 构造插入语句
int rc = sqlite3_exec(db, sq1, NULL, NULL, &errmsg); //将查询时间保存到数据库中
if (rc != SQLITE_OK)
{
printf("insert err: %s\n", errmsg);
return -1;
}
return 0;
}
else //未找到该单词
{
sprintf(msg.data, "word unfund\n");
send(sockfd, &msg, sizeof(msg), 0);
return -1;
}
}
int history(sqlite3 *db, int sockfd) //查询历史记录
{
char **result = NULL; //数据库返回内容
char sq1[128]; //保存命令
sprintf(sq1, "select * from \"%s\";", msg.name); //查询单词查询历史
sqlite3_get_table(db, sq1, &result, &hang, &lie, &errmsg);
if (hang != 0)
{
for (int j = 0; j < hang; j++) //拼接表内内容到字符数组中
{
strcat(msg.data, result[j * lie + 2]);
strcat(msg.data, " "); //两个表内内容间添加空格间隔
strcat(msg.data, result[j * lie + 3]);
strcat(msg.data, "\n"); //两行间换行
}
send(sockfd, &msg, sizeof(msg), 0); //发送该单词查询结果
return 0;
}
else if (hang == 0) //历史记录为空
{
sprintf(msg.data, "history is void");
send(sockfd, &msg, sizeof(msg), 0); //发送该单词查询结果
return 0;
}
}
int main(int argc, char const *argv[])
{
// 1.打开或创建数据库
int rc;
if (sqlite3_open("./word.db", &db) != SQLITE_OK)
{
printf("sqlite3_open err:%s\n", sqlite3_errmsg(db));
return -1;
}
printf("sqlite3_open success\n"); //打开数据库成功
if (argc < 2) //行传参正确
{
printf("plase input <file><port>\n");
return -1;
}
//1.创建套接字,用于链接
int sockfd;
int acceptfd; //接收套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) //容错
{
perror("socket err");
return -1;
}
//2.绑定 ip+port 填充结构体
struct sockaddr_in saddr;
saddr.sin_family = AF_INET; //协议族ipv4
saddr.sin_port = htons(atoi(argv[1])); //端口号,htons将无符号短整数hostshort从主机字节顺序到网络字节顺序。
saddr.sin_addr.s_addr = inet_addr("0.0.0.0"); //ip地址,转化为16进制表示
socklen_t len = sizeof(saddr); //结构体大小
//bind绑定ip和端口
if (bind(sockfd, (struct sockaddr *)&saddr, len) < 0)
{
perror("bind err");
return -1;
}
//3.启动监听,把主动套接子变为被动套接字
if (listen(sockfd, 6) < 0)
{
perror("listen err");
return -1;
}
//4.创建表
fd_set readfds; //原表
fd_set tempfds; //创建一个临时表,用来保存新表
FD_ZERO(&readfds); //原表置空
//5.填表
FD_SET(sockfd, &readfds); //将要监测的文件描述符插入到表中
int maxfd = sockfd; //表内最大描述符
int ret;
//6.循环监听 select
while (1)
{
tempfds = readfds; //每次循环前重新赋值一次
int ret = select(maxfd + 1, &tempfds, NULL, NULL, NULL); //监测
if (ret < 0)
{
perror("select err");
return -1;
}
if (FD_ISSET(sockfd, &tempfds)) //监听是否有客户端链接
{
//阻塞等待客户端的链接请求
acceptfd = accept(sockfd, (struct sockaddr *)&saddr, &len);
//获取客户端的ip和端口,(struct sockaddr *)&saddr:用来存放返回的ip,和端口
if (acceptfd < 0)
{
perror("accept err");
return -1;
}
printf("client ip:%s ,port:%d:connect success\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
//打印已经接入的客户端IP
FD_SET(acceptfd, &readfds); //将新接入的客户端文件描述符插入到原表中
if (acceptfd > maxfd) //如果新插入的文件描述符大于已知最大文件描述符,则更新表内最大文件描述符
{
maxfd = acceptfd;
}
}
for (int i = 5; i <= maxfd; i++) //遍历判断是否有信号传输
{
if (FD_ISSET(i, &tempfds)) //监测客户端文件描述符
{
int ret = recv(i, &msg, sizeof(msg), 0); //接收的信号
if (ret < 0) //接收错误
{
perror("recv err.");
return -1;
}
else if (ret == 0)
{
printf("%d client exit\n", i); //客户端退出
close(i); //关闭描述符
FD_CLR(i, &readfds); //删除文件描述符
}
else
{
switch (msg.type)
{
case R: //注册
Register(db, i);
break;
case L: //登录
loginclient(db, i);
break;
case Q: //搜索
chatclient(db, i);
break;
case H: //历史
history(db, i);
break;
default:
break;
}
}
}
}
}
close(sockfd);
close(acceptfd);
return 0;
} 云词典客户端
/*客户端创建代码 */
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "head.h"
#define N 32
MSG_t msg;
int n; //命令输入
//注册操作
void do_register(int sockfd)
{
while (1)
{
msg.type = R; //注册状态
printf("请输入您的用户名:");
scanf("%s", msg.name);
getchar(); //回收一个垃圾字符
if (memcmp(msg.name, "#", 1) == 0) //注册过程中输入#退出注册页面
{
printf("退出注册\n");
break;
}
printf("请输入您的密码:");
scanf("%s", msg.data);
getchar();
send(sockfd, &msg, sizeof(msg), 0);
recv(sockfd, &msg, sizeof(msg), 0); //接收客户端消息,判断是否注册成功
printf("register:%s\n", msg.data);
if (memcmp(msg.data, "OK", 2) == 0) //服务器返回的msg.data == OK注册成功
{
break;
}
}
}
//登录操作
int do_login(int sockfd)
{
while (1)
{
msg.type = L; //登录状态
printf("请输入您的用户名:");
scanf("%s", msg.name);
getchar();
if (memcmp(msg.data, "#", 1) == 0) //退出查询页面,先判断退出后发送内容
{
printf("退出查询\n");
msg.type = 0;//当发送给服务器为结束内容,让服务器端读出且无法识别type,继续等待事件
memset(msg.data,0,sizeof(msg.data));//将msg.data中的#清空
send(sockfd, &msg, sizeof(msg), 0);
break;
}
printf("请输入您的密码:");
scanf("%s", msg.data);
getchar();
send(sockfd, &msg, sizeof(msg), 0);
recv(sockfd, &msg, sizeof(msg), 0);
printf("login:%s\n", msg.data);
if (memcmp(msg.data, "OK", 2) == 0) //服务器返回的msg.data=OK登录成功
{
return 1;
}
}
}
//查询操作
void do_query(int sockfd)
{
msg.type = Q;
while (1)
{
printf("请输入你要查询的单词内容:");
scanf("%s", msg.data);
getchar();
if (memcmp(msg.data, "#", 1) == 0) //退出查询页面,先判断退出后发送内容
{
printf("退出查询\n");
msg.type = 0;//当发送给服务器为结束内容,让服务器端读出且无法识别type,继续等待事件
memset(msg.data,0,sizeof(msg.data));
send(sockfd, &msg, sizeof(msg), 0);
break;
}
send(sockfd, &msg, sizeof(msg), 0);
recv(sockfd, &msg, sizeof(msg), 0);
printf("annotation:%s\n", msg.data); //打印接收的信息/注释
}
}
//查询历史记录
void do_history(int sockfd)
{
// memset(msg.data, 0, sizeof(msg.data));
msg.type = H;
send(sockfd, &msg, sizeof(msg), 0);
recv(sockfd, &msg, sizeof(msg), 0); //接收信息,接一次打一次.
printf("%s\n", msg.data);
}
//主函数
int main(int argc, char const *argv[])
{
if (argc < 3)
{
printf("plase input <ip><port>\n");
return -1;
}
//1.创建套接字,用于链接
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket err");
return -1;
}
//文件描述符 0 -> 标准输入 1->标准输出 2->标准出错 3->socket
printf("sockfd:%d\n", sockfd);
//2.绑定 ip+port 填充结构体
struct sockaddr_in saddr;
saddr.sin_family = AF_INET; //协议族ipv4
saddr.sin_port = htons(atoi(argv[2])); //端口号,htons将无符号短整数hostshort从主机字节顺序到网络字节顺序。
saddr.sin_addr.s_addr = inet_addr(argv[1]); //ip地址,转化为16进制表示
socklen_t len = sizeof(saddr); //结构体大小
//3用于连接服务器;
if (connect(sockfd, (struct sockaddr *)&saddr, len) < 0)
{
perror("connect err");
return -1;
}
int flag = 0;
while (1)
{
printf("*******************************************************\n");
printf("* <BUG词典> *\n");
printf("* 1: 注册 2: 登录 3: 退出 *\n");
printf("*******************************************************\n");
printf("请输入命令:");
scanf("%d", &n);
getchar();
switch (n)
{
case 1:
do_register(sockfd);
break;
case 2:
if (do_login(sockfd) == 1)
{
while (1)
{
if (flag == 1)
{
flag = 0;
break;
}
printf("*******************************************************\n");
printf("* <BUG词典> *\n");
printf("* 1: 查询单词 2: 历史记录 3: 退出 *\n");
printf("*******************************************************\n");
printf("请输入命令:");
scanf("%d", &n);
getchar();
switch (n)
{
case 1:
do_query(sockfd);
break;
case 2:
printf("search history\n");
do_history(sockfd);
break;
case 3:
flag = 1;
break;
default:
break;
}
}
}
break;
case 3:
return 0;
default:
break;
}
}
close(sockfd);
return 0;
} 相关文章:
基于tcp协议及数据库sqlite3的云词典项目
这个小项目是一个网络编程学习过程中一个阶段性检测项目,过程中可以有效检测我们对于服务器客户端搭建的能力,以及一些bug查找能力。项目的一个简单讲解我发在了b站上,没啥心得,多练就好。 https://t.bilibili.com/86524470252640…...
C/C++内存管理(1):C/C++内存分布,C++内存管理方式
一、C/C内存分布 1.1 1.2 二、C内存管理方式 C可以通过操作符new和delete进行动态内存管理。 2.1 new和delete操作内置类型 int main() {int* p1 new int;// 注意区分p2和p3int* p2 new int(10);// 对*p2进行初始化 10int* p3 new int[10];// p3 指向一块40个字节的int类…...
11 redis中分布式锁的实现
单机锁代码 import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.con…...
循环链表3
插入函数——插入数据,在链表plsit的pos位置插入val数据元素 位置pos(在无特别说明的情况下)是从0开始计数的 要改变链表结构,就要依赖前驱,每个前驱的next存储着下一个数据结点的地址,也就是依靠前驱的ne…...
如何修改百科内容?百度百科内容怎么修改?
百科词条创建上去是相当不易的,同时修改也是如此,一般情况下,百科词条是不需要修改的,但是很多时候企业或是人物在近期收获了更多成就或是有更多的变动,这个时候就需要补充维护词条了,如何修改百科内容&…...
mysql8.0英文OCP考试第131-140题
Q131.You have upgraded the MySQL binaries from 5.7.28 to 8.0.18 by using an in-place upgrade. Examine the message sequence generated during the first start of MySQL 8.0.18: 。。。[System]。。。/usx/sbin/mysqld (mysqld 8.0.18-commercial) starting as proces…...
MySQL数据库——存储过程-条件处理程序(通过SQLSTATE指定具体的状态码,通过SQLSTATE的代码简写方式 NOT FOUND)
目录 介绍 案例 通过SQLSTATE指定具体的状态码 通过SQLSTATE的代码简写方式 NOT FOUND 介绍 条件处理程序(Handler)可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤。具体语法为: DECLARE handler_action HANDLER FOR c…...
信号的处理时机(内核态,用户态,如何/为什么相互转换,内核空间,cpu寄存器),信号的处理流程详细介绍+抽象图解
目录 信号的处理时机 引入 思考 -- 什么时候才能算合适的时候呢? 用户态转为内核态 引入 内核地址空间 引入 思考 -- 进程为什么能切换成内核态呢? 虚拟地址空间 注意点 原理 (总结一下) 为什么如何进入内核态 引入 介绍 底层原理(int 80) cpu的寄存器 用…...
【JavaEE】Spring的创建和使用(保姆级手把手图解)
一、创建一个Spring项目 1.1 创建一个Maven项目 1.2 添加 Spring 框架支持 在pom.xml中添加 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE&…...
MyBatis:关联查询
MyBatis 前言关联查询附懒加载对象为集合时的关联查询 前言 在 MyBatis:配置文件 文章中,最后介绍了可以使用 select 标签的 resultMap 属性实现关联查询,下面简单示例 关联查询 首先,先创建 association_role 和 association_…...
第十二章 控制值的转换
文章目录 第十二章 控制值的转换介绍处理特殊 XML 字符文字和 SOAP 编码格式的转义形式 示例防止泄漏的另一种方法 第十二章 控制值的转换 类和属性参数 ESCAPE CONTENT XMLTIMEZONE DISPLAYLIST VALUELIST XMLDEFAULTVALUE XMLLISTPARAMETER XMLSTREAMMODE 介绍 支…...
SQL并集、交集、差集使用
一、概述 SQL语句实现数据的并集(union)、交集(intersect)、差集(except)。 二、案例 1、stu表 idname1张三2李四3王二 2、并集 union union 运算:表示取并集,例如:…...
【双指针】盛水最多的容器
盛水最多的容器 文章目录 盛水最多的容器题目描述算法原理思路一思路二 代码实现Java代码实现C代码实现 题目描述 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与…...
win11,引导项管理
1,打开cmd,输入msconfig 2,进入引导选项卡 3,删除不需要的引导项...
YoloV8改进策略:WaveletPool解决小目标的混叠问题,提高小目标的检测精度
文章目录 摘要论文:《抗混叠在微小目标检测中的重要性》1、简介2、相关研究2.1、微小物体检测2.2. 抗锯齿过滤器3、方法3.1. Wavelet Pooling3.2 一致顺序的Wavelet Pooling的WaveCNet3.3、Bottom-Heavy Backbone4、实验4.1、预训练数据集4.2、微小目标检测数据集4.3、抗混叠方…...
JavaScript中的假值对象是什么?
JavaScript是一种非常灵活且强大的编程语言,但有时候它的一些特性可能会让人感到困惑。其中一个常见的问题就是假值对象。在本文中,我们将探讨什么是假值对象,并通过代码示例来解释这个概念。 什么是假值对象? 在JavaScript中&am…...
求二叉树的最大密度(可运行)
最大密度:二叉树节点数值的最大值 如果没有输出结果,一定是建树错误!!!!!!! 我设置输入的是字符型数据,比较的ASCII值。 输入:FBE###CE### 输…...
V100 GPU服务器安装CUDNN教程
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
RT-Thread Hoist_Motor PID
本节介绍的是一个举升电机,顾名思义,通过转轴控制物体升降,为双通道磁性译码器,利用电调进行操控,具体驱动类似于大学期间最大众的SG180舵机,在一定的频率下,通过调制脉宽进行控制。 设备介绍…...
css 实现文字流光效果
经过调研发现大多滑块验证码中,有一些文字流光效果,因此在这里简单实现一下。 实现主要利用background 渐变背景以及backgorund-clip:text实现。具体代码如下 css部分 .slide {width: 300px;height: 40px;border: 1px solid #ccc;border-radius: 8px;…...
GTNH中文汉化终极指南:3步解锁百万字专业翻译体验
GTNH中文汉化终极指南:3步解锁百万字专业翻译体验 【免费下载链接】Translation-of-GTNH GTNH整合包的汉化 项目地址: https://gitcode.com/gh_mirrors/tr/Translation-of-GTNH 还在为GregTech: New Horizons(GTNH)整合包复杂的英文界…...
告别手动收集!用cvemap+Python脚本,5分钟自动化构建你的专属CVE漏洞知识库
告别手动收集!用cvemapPython脚本,5分钟自动化构建你的专属CVE漏洞知识库 每天打开电脑的第一件事,就是检查最新的CVE漏洞公告——这可能是许多安全工程师的日常。但当你面对NVD、Exploit-DB、HackerOne等多个平台的海量数据时,手…...
创业团队如何利用统一 API 网关优化 AI 开发成本与效率
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 创业团队如何利用统一 API 网关优化 AI 开发成本与效率 对于资源有限的创业团队而言,在探索和集成人工智能能力时&…...
如何为Nintendo Switch解锁自定义功能?大气层系统完整指南
如何为Nintendo Switch解锁自定义功能?大气层系统完整指南 【免费下载链接】Atmosphere-stable 大气层整合包系统稳定版 项目地址: https://gitcode.com/gh_mirrors/at/Atmosphere-stable 你是否希望为你的Nintendo Switch解锁更多可能性?大气层系…...
手把手教你用Alist搭建私人影视库:聚合阿里云盘、百度网盘资源,用Kodi/Plex直接播放
家庭影音中心革命:用Alist打造跨平台云端影视库 坐在沙发上用电视直接播放阿里云盘里的4K电影,或者在卧室用iPad流畅观看百度网盘收藏的美剧——这些曾经需要反复下载转存的繁琐操作,现在通过Alist可以轻松实现。作为一款开源的网盘聚合工具&…...
如何快速成为全栈Web开发者:免费资源与游戏化学习的终极指南
如何快速成为全栈Web开发者:免费资源与游戏化学习的终极指南 【免费下载链接】Become-A-Full-Stack-Web-Developer Free resources for learning Full Stack Web Development 项目地址: https://gitcode.com/gh_mirrors/be/Become-A-Full-Stack-Web-Developer …...
从状态机到可配置IP核:手把手教你用parameter玩转Verilog模块复用(附代码)
从状态机到可配置IP核:手把手教你用parameter玩转Verilog模块复用(附代码) 在数字电路设计中,模块复用是提升开发效率的关键策略。想象一下:当你完成一个精心设计的计数器模块后,下一个项目需要相同功能但不…...
如何高效使用ComfyUI Manager:AI绘画工作流的智能管理指南
如何高效使用ComfyUI Manager:AI绘画工作流的智能管理指南 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various c…...
GJB/Z 299D-2024 电子设备可靠性预计软件高效实操教程
传统手工查表法进行复杂电子设备可靠性预计,存在效率低下、流程繁琐、工作量大、无法快速二次编辑等问题,已难以适配当前军工领域合规化、高效化的报告出具需求。 元器件计数法可靠性预计软件【工作状态】 元器件应力分析法可靠性预计软件【工作状态】 …...
哔哩下载姬DownKyi完整指南:三步掌握免费高效的B站视频下载
哔哩下载姬DownKyi完整指南:三步掌握免费高效的B站视频下载 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、去水印等&…...
