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

基于tcp协议及数据库sqlite3的云词典项目

这个小项目是一个网络编程学习过程中一个阶段性检测项目,过程中可以有效检测我们对于服务器客户端搭建的能力,以及一些bug查找能力。项目的一个简单讲解我发在了b站上,没啥心得,多练就好。
https://t.bilibili.com/865244702526406675?share_source=pc_native

数据库创建及导入单词表

#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的云词典项目

这个小项目是一个网络编程学习过程中一个阶段性检测项目&#xff0c;过程中可以有效检测我们对于服务器客户端搭建的能力&#xff0c;以及一些bug查找能力。项目的一个简单讲解我发在了b站上&#xff0c;没啥心得&#xff0c;多练就好。 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

插入函数——插入数据&#xff0c;在链表plsit的pos位置插入val数据元素 位置pos&#xff08;在无特别说明的情况下&#xff09;是从0开始计数的 要改变链表结构&#xff0c;就要依赖前驱&#xff0c;每个前驱的next存储着下一个数据结点的地址&#xff0c;也就是依靠前驱的ne…...

如何修改百科内容?百度百科内容怎么修改?

百科词条创建上去是相当不易的&#xff0c;同时修改也是如此&#xff0c;一般情况下&#xff0c;百科词条是不需要修改的&#xff0c;但是很多时候企业或是人物在近期收获了更多成就或是有更多的变动&#xff0c;这个时候就需要补充维护词条了&#xff0c;如何修改百科内容&…...

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 介绍 条件处理程序&#xff08;Handler&#xff09;可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤。具体语法为&#xff1a; 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&#xff1a;配置文件 文章中&#xff0c;最后介绍了可以使用 select 标签的 resultMap 属性实现关联查询&#xff0c;下面简单示例 关联查询 首先&#xff0c;先创建 association_role 和 association_…...

第十二章 控制值的转换

文章目录 第十二章 控制值的转换介绍处理特殊 XML 字符文字和 SOAP 编码格式的转义形式 示例防止泄漏的另一种方法 第十二章 控制值的转换 类和属性参数 ESCAPE CONTENT XMLTIMEZONE DISPLAYLIST VALUELIST XMLDEFAULTVALUE XMLLISTPARAMETER XMLSTREAMMODE 介绍 支…...

SQL并集、交集、差集使用

一、概述 SQL语句实现数据的并集&#xff08;union&#xff09;、交集&#xff08;intersect&#xff09;、差集&#xff08;except&#xff09;。 二、案例 1、stu表 idname1张三2李四3王二 2、并集 union union 运算&#xff1a;表示取并集&#xff0c;例如&#xff1a…...

【双指针】盛水最多的容器

盛水最多的容器 文章目录 盛水最多的容器题目描述算法原理思路一思路二 代码实现Java代码实现C代码实现 题目描述 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与…...

win11,引导项管理

1&#xff0c;打开cmd,输入msconfig 2,进入引导选项卡 3&#xff0c;删除不需要的引导项...

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是一种非常灵活且强大的编程语言&#xff0c;但有时候它的一些特性可能会让人感到困惑。其中一个常见的问题就是假值对象。在本文中&#xff0c;我们将探讨什么是假值对象&#xff0c;并通过代码示例来解释这个概念。 什么是假值对象&#xff1f; 在JavaScript中&am…...

求二叉树的最大密度(可运行)

最大密度&#xff1a;二叉树节点数值的最大值 如果没有输出结果&#xff0c;一定是建树错误&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 我设置输入的是字符型数据&#xff0c;比较的ASCII值。 输入&#xff1a;FBE###CE### 输…...

V100 GPU服务器安装CUDNN教程

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

RT-Thread Hoist_Motor PID

本节介绍的是一个举升电机&#xff0c;顾名思义&#xff0c;通过转轴控制物体升降&#xff0c;为双通道磁性译码器&#xff0c;利用电调进行操控&#xff0c;具体驱动类似于大学期间最大众的SG180舵机&#xff0c;在一定的频率下&#xff0c;通过调制脉宽进行控制。 设备介绍…...

css 实现文字流光效果

经过调研发现大多滑块验证码中&#xff0c;有一些文字流光效果&#xff0c;因此在这里简单实现一下。 实现主要利用background 渐变背景以及backgorund-clip:text实现。具体代码如下 css部分 .slide {width: 300px;height: 40px;border: 1px solid #ccc;border-radius: 8px;…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

HTTPS证书一年多少钱?

HTTPS证书作为保障网站数据传输安全的重要工具&#xff0c;成为众多网站运营者的必备选择。然而&#xff0c;面对市场上种类繁多的HTTPS证书&#xff0c;其一年费用究竟是多少&#xff0c;又受哪些因素影响呢&#xff1f; 首先&#xff0c;HTTPS证书通常在PinTrust这样的专业平…...