首页 > 数据库 >云词典——基于TCP和sqlite3实现

云词典——基于TCP和sqlite3实现

时间:2024-09-17 14:22:16浏览次数:3  
标签:int pbuf TCP MSG printf sqlite3 sizeof data 词典

项目需求

  功能描述   

       仿照有道云词典功能,实现一个自己的云词典。自行定义项目名,最终可以体现到简历中。

  效果参考

功能矩阵

功能模块

功能点

功能点描述

优先级

备注

客户端

注册

可实现新用户的注册功能

A

登录

支持用户登录校验,错误给出提示,正确进入操作菜单

A

查词

可以进行单词释义查询操作

A

查词历史

可查看当前用户的查词历史

A

服务器

注册

实现用户的注册功能,并永久保存到数据库中

A

登录

实现用户登录请求的校验

B

查词

实现用户的查词请求并返回释义结果

A

历史

根据当前用户返回查词历史

A

心跳包检测

tcp的keepalive机制,确保客户端是否在线

C

选做

 流程图:

程序框架

通过网盘分享的文件:框架 提取码: pqqnicon-default.png?t=O83Ahttps://pan.baidu.com/s/1fv-svjLrQhSTZKQ2t-Gd5w?pwd=pqqn

参考

server.c

//sever.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define DATABASE "my.db"
#define N 16

enum CMD
{
    R = 1,
    L,
    Q,
    H
};

typedef struct sockaddr SA;

typedef struct
{
    int type;
    char name[N];
    char data[1000]; // password or word
} MSG;

static sqlite3 *db;

/**
 * @brief 服务器处理注册
 * 得到用户输入用户名和密码并拼接sql语句
 * 执行sql语句
 * 封装执行结果并回发客户端
 */
void do_register(int connfd, MSG *pbuf)
{
    char *errmsg;
    char sql[256] = "";
    sprintf(sql, "insert into usr values('%s','%s');", pbuf->name, pbuf->data);
    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
    {
        printf("注册失败:%s\n", errmsg);
        strcpy(pbuf->data, "用户名名重复");
        send(connfd, pbuf, sizeof(MSG), 0);
        return;
    }
    strcpy(pbuf->data, "注册成功!");
    printf("%s\n", pbuf->data);
    send(connfd, pbuf, sizeof(MSG), 0);
    return;
}

/**
 * @brief 服务器处理登录
 * 得到用户输入用户名和密码并拼接sql语句
 * 执行sql语句
 * 封装执行结果并回发客户端
 */
void do_login(int connfd, MSG *pbuf)
{
    char *errmsg;
    char **Result = NULL;
    char **Re = NULL;
    char sql[2000];
    int lie, hang;
    sprintf(sql, "select name from usr;");
    if (sqlite3_get_table(db, sql, &Re, &hang, &lie, &errmsg) != 0)
    {
        printf("get table err:%s\n", errmsg);
        return;
    }
    memset(sql, 0, sizeof(sql));
    for (int i = 0; i < hang + 1; i++)
    {
        if (!strcmp(Re[i], pbuf->name))
        {
            sprintf(sql, "select pass from usr where name = \"%s\";", pbuf->name);
            if (sqlite3_get_table(db, sql, &Result, &hang, &lie, &errmsg) != 0)
            {
                printf("get table err:%s\n", errmsg);
                return;
            }
            if (!strcmp(pbuf->data, Result[1]))
                strcpy(pbuf->data, "登陆成功!");
            else
            {
                strcpy(pbuf->data, "用户名或密码错误");
            }
            send(connfd, pbuf, sizeof(MSG), 0);
            printf("%s\n", pbuf->data);
            memset(pbuf->data, 0, sizeof(pbuf->data));
            memset(pbuf->name, 0, sizeof(pbuf->name));
            memset(sql, 0, sizeof(sql));
            return;
        }
    }
    strcpy(pbuf->data, "用户名不存在");
    send(connfd, pbuf, sizeof(MSG), 0);
    printf("%s\n", pbuf->data);
    memset(pbuf->data, 0, sizeof(pbuf->data));
    memset(pbuf->name, 0, sizeof(pbuf->name));
    memset(sql, 0, sizeof(sql));
    return;
}

/**
 * @brief 返回当前的时间,存到date中
 * @return 
 */
void get_date(char *date)
{
    time_t t;
    struct tm *tp;

    time(&t);

    tp = localtime(&t);

    sprintf(date, "%d-%02d-%02d %02d:%02d:%02d", tp->tm_year + 1900,
            tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);

    strftime(date, 64, "%Y-%m-%d %H:%M:%S", tp);

    return;
}

/**
 * @brief 服务器处理查询
 * 查询单词释义
 * 把本次查询添加到查询历史中
 */
void do_query(int connfd, MSG *pbuf)
{
    char buf[1024] = "";
    char *errmsg;
    char **Result = NULL;   
    char sql[1000];
    int lie,hang;
    sprintf(sql, "select * from dic where word = '%s';", pbuf->data);  
    strcpy(buf, pbuf->data);
    if (sqlite3_get_table(db, sql, &Result, &hang, &lie, &errmsg) != 0)
    {
        printf("get table err:%s\n", errmsg);
        strcpy(pbuf->data, "没有查到该单词\n");
        send(connfd, pbuf, sizeof(MSG), 0);
        return;
    }
    if (hang == 0 || Result == NULL)
    {
        strcpy(pbuf->data, "没有查到该单词\n");
        send(connfd, pbuf, sizeof(MSG), 0);
        return;
    }
    // printf("Result[3]:%s\n",Result[3]);
    // printf("hang: %d lie:%d\n",hang,lie);
    printf("%s", Result[3]);
    strcpy(pbuf->data, Result[3]);
    send(connfd, pbuf, sizeof(MSG), 0);
    memset(pbuf->data, 0, sizeof(pbuf->data));
    get_date(pbuf->data);
    memset(sql, 0, sizeof(sql));
    sprintf(sql, "insert into record values('%s','%s','%s');", pbuf->name, pbuf->data, buf);
    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
    {
        printf("into err:%s\n", errmsg);
        return;
    }
    return;
}

/**
 * @brief 查询历史处理
 * 根据用户名来查找查询历史,并将结果返回给客户端
 * 执行sql语句
 * 封装执行结果并回发客户端
 */
void do_history(int connfd, MSG *pbuf)
{
    char *errmsg;
    char **Result=NULL;
    char sql[1000];
    int lie,hang;
    printf("successs - --");
    printf("%s----",pbuf->data);
    memset(pbuf->data,0,sizeof(pbuf->data));
    sprintf(sql,"select * from record ;");
    if(sqlite3_get_table(db,sql,&Result,&hang,&lie,&errmsg) !=0)
    {
        printf("get table err:%s\n",errmsg);
        strcpy(pbuf->data,"查询错误");
        send(connfd,pbuf,sizeof(MSG),0);
        return;
    }
    else if (hang == 0 || Result == NULL)
    {
        strcpy(pbuf->data,"查询失败\n");
        printf("%s",pbuf->data);
        send(connfd,pbuf,sizeof(MSG),0);
        return;
    }
    int k=3;
    printf("Result[0]:%s\n",Result[0]);
    printf("Result[1]:%s\n",Result[1]);
    printf("Result[2]:%s\n",Result[2]);
    printf("Result[3]:%s\n",Result[3]);
    printf("Result[4]:%s\n",Result[4]);
    for(int i = 1;i<=hang;i++)
    {
        for(int j =0;j< lie;j++)
        {
            strcat(pbuf->data,Result[k++]);
            strcat(pbuf->data," ");
        }
        strcat(pbuf->data,"\n");
    }
    send(connfd,pbuf,sizeof(MSG),0);
    printf("%s",pbuf->data);
    return;
}

/**
 * @brief do_client 处理客户端请求
 * @param connfd 客户端fd
 * @param db 数据库句柄
 */
void do_client(int connfd)
{
    MSG buf;
    while (recv(connfd, &buf, sizeof(buf), 0) > 0)
    {
        switch (buf.type)
        {
        case R:
            printf("will reg\n");
            do_register(connfd, &buf);
            break;
        case L:
            printf("will login\n");
            do_login(connfd, &buf);
            break;
        case Q:
            printf("will query\n");
            do_query(connfd, &buf);
            break;
        case H:
            printf("will history\n");
            do_history(connfd, &buf);
            break;
        default:
            break;
        }
    }

    exit(0);
}

int main(int argc, char *argv[])
{
    int listenfd, connfd;
    struct sockaddr_in myaddr;
    pid_t pid;
    MSG buf;

    if (argc < 2)
    {
        printf("Usage : %s <port>\n", argv[0]);
        exit(-1);
    }

    //打开数据库
    if (sqlite3_open(DATABASE, &db) < 0)
    {
        printf("fail to sqlite3_open : %s\n", sqlite3_errmsg(db));
        return -1;
    }

    //创建服务器socket
    listenfd = socket(PF_INET, SOCK_STREAM, 0);
    if (listenfd < 0)
    {
        perror("fail to socket");
        exit(-1);
    }
    bzero(&myaddr, sizeof(myaddr));
    myaddr.sin_family = PF_INET;
    myaddr.sin_port = htons(atoi(argv[1]));
    myaddr.sin_addr.s_addr = INADDR_ANY;
    if (bind(listenfd, (SA *)&myaddr, sizeof(myaddr)) < 0)
    {
        perror("fail to bind");
        exit(-1);
    }

    if (listen(listenfd, 5) < 0)  
    {
        perror("fail to listen");
        exit(-1);
    }

    //并发服务器
    while (1)
    {
        if ((connfd = accept(listenfd, NULL, NULL)) < 0)
        {
            perror("fail to accept");
            exit(-1);
        }
        pid = fork();
        if (pid == -1)
        {
            perror("fail to fork\n");
            exit(-1);
        }
        else if (pid == 0)
        { //子进程
            printf("a user comming\n");
            do_client(connfd);
        }
        else
        { //父进程
            close(connfd);
        }
    }
}

client.c

//client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define N 16
typedef struct sockaddr SA;

enum CMD
{
    R = 1, //注册
    L,     //登录
    Q,     //查询
    H      //历史
};

typedef struct
{
    int type;
    char name[N];
    char data[1000]; // password or word
} MSG;

/**
 * @brief 客户端注册
 * 用户输入用户名和密码
 * 封装消息
 * 发送
 * 接收并输出结果
 */
void do_register(int sockfd, MSG *pbuf)
{
    pbuf->type = 1;
    printf("input name:");
    //fgets(pbuf->name,N,stdin);
    scanf("%s", pbuf->name);
    getchar();
    // fgets(pbuf->data,256,stdin);
    // send(sockfd,pbuf,sizeof(buf),0);
    printf("input password:");
    scanf("%s", pbuf->data);
    getchar();
    send(sockfd, pbuf, sizeof(MSG), 0);
    memset(pbuf->data, 0, sizeof(pbuf->data));
    int ret = recv(sockfd, pbuf, sizeof(MSG), 0);
    if (ret < 0)
    {
        perror("recv err");
        return;
    }
    printf("%s\n", pbuf->data);
    memset(pbuf->data, 0, sizeof(pbuf->data));
    memset(pbuf->name, 0, sizeof(pbuf->name));
    return;
}

/**
 * @brief 客户端登录
 * 用户输入用户名和密码
 * 封装消息
 * 发送
 * 接收并输出结果
 * @return 成功返回1 失败返回0
 */
int do_login(int sockfd, MSG *pbuf)
{
    memset(pbuf->data, 0, sizeof(pbuf->data));
    memset(pbuf->name, 0, sizeof(pbuf->name));
    pbuf->type = 2;
    printf("请输入用户名:");
    scanf("%s", pbuf->name);
    getchar();
    printf("请输入密码:");
    scanf("%s", pbuf->data);
    getchar();
    send(sockfd, pbuf, sizeof(MSG), 0);
    memset(pbuf->data, 0, sizeof(pbuf->data));
    int ret = recv(sockfd, pbuf, sizeof(MSG), 0);
    if (ret < 0)
    {
        perror("recv err");
        return 0;
    }
    printf("%s\n", pbuf->data);
    if (!strcmp(pbuf->data, "登陆成功!"))
        return 1;
    else
        return 0;
}

/**
 * @brief 客户端查询
 * 查询历史
 */
void do_history(int sockfd, MSG *pbuf)
{
    pbuf->type = H;
    send(sockfd, pbuf, sizeof(MSG), 0);
    int ret = recv(sockfd, pbuf, sizeof(MSG), 0);
    if (ret < 0)
    {
        perror("recv err");
        return;
    }
    printf("%s", pbuf->data);
    return;
}

/**
 * @brief 客户端查询
 * 输入单词或“#”
 * 封装消息
 * 发送
 * 接收并输出结果
 */
void do_query(int sockfd, MSG *pbuf)
{
    while (1)
    {
        memset(pbuf->data, 0, sizeof(pbuf->data));
        pbuf->type = Q;
        printf("请输入单词或#(#为退出):");
        scanf("%s", pbuf->data);
        getchar();
        //printf("getchar success!\n");
        if (!strcmp(pbuf->data, "#"))
            break;
        send(sockfd, pbuf, sizeof(MSG), 0);
        memset(pbuf->data, 0, sizeof(pbuf->data));
        int ret = recv(sockfd, pbuf, sizeof(MSG), 0);
        if (ret < 0)
        {
            perror("recv err");
            return;
        }
        // if(ret>0)
        // {
        //     printf("recv seccuss");
        // }
        printf("%s", pbuf->data);
    }
}

void enter_query(int sockfd, MSG *buf)
{
    int input;
    char cleanbuf[64];

    while (1)
    {
        printf("***********************************************\n");
        printf("* 1: query_word   2: history_record   3: quit *\n");
        printf("***********************************************\n");
        printf("please choose : ");
        //获取用户输入
        if (scanf("%d", &input) == 0)
        {
            fgets(cleanbuf, 64, stdin); //类型错误需要重新清除输入缓冲区
            continue;
        }

        switch (input)
        {
        case 1:
            printf("\n");
            do_query(sockfd, buf);
            printf("\n");
            break;
        case 2:
            printf("\n");
            do_history(sockfd, buf);
            printf("\n");
            break;
        case 3:
            return;
        default:
            break;
        }
    }
}

int main(int argc, char *argv[])
{
    int sockfd, login = 0;
    struct sockaddr_in servaddr;
    MSG buf;
    char clean[64];

    if (argc < 3)
    {
        printf("Usage : %s <serv_ip> <serv_port>\n", argv[0]);
        exit(-1);
    }

    //创建客户端socket
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("fail to socket");
        exit(-1);
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = PF_INET;
    servaddr.sin_port = htons(atoi(argv[2]));
    servaddr.sin_addr.s_addr = inet_addr(argv[1]);

    //连接服务器
    if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("fail to connect");
        exit(-1);
    }

    int input;
    char cleanbuf[64];
    while (1)
    {
        printf("************************************\n");
        printf("* 1: register   2: login   3: quit *\n");
        printf("************************************\n");
        printf("please choose : ");
        //获取用户输入
        if (scanf("%d", &input) == 0)
        {
            fgets(cleanbuf, 64, stdin); //类型错误需要重新清除输入缓冲区
            continue;
        }

        switch (input)
        {
        case 1:
            do_register(sockfd, &buf);
            break;
        case 2:
            if (do_login(sockfd, &buf) == 1)
            { //成功
                enter_query(sockfd, &buf);
            }
            break;
        case 3:
            close(sockfd);
            exit(0);
            break;
        default:
            break;
        }
    }
}

项目文件夹及其单词数据库

通过网盘分享的文件:dictionary.zip 提取码: 5sr9icon-default.png?t=O83Ahttps://pan.baidu.com/s/1DwZnggUNhxK_wgzFI0ytjw?pwd=5sr9

视频演示

标签:int,pbuf,TCP,MSG,printf,sqlite3,sizeof,data,词典
From: https://blog.csdn.net/weixin_63791423/article/details/142314074

相关文章

  • 简单论述TCP,UDP,HTTP,SMTP,DNS,RTP之间的关系(计算机网络408)
            最近有很多同学在刚接触计算机网络概论的时候很容易被提及到IP,TCP,UDP....之类的东西,这里就简单论述一下他们是干什么的。                                                             ......
  • TCP协议分析《实验报告》
    一、实验目的1、理解TCP协议;2、掌握TCP协议三次握手建立连接和四次挥手释放连接的过程;3、理解TELNET协议及工作过程;4、掌握TCP协议分析方法。二、实验设备和环境1、硬件设备:PC机或笔记本电脑;2、软件:H3CCloudLab、Wireshark。三、实验记录1、实验环境搭建按照下图在......
  • TCP三次握手及四次挥手理解
    定义传输控制协议(TCP,TransmissionControlProtocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。三次握手三次握手的过程中是没有业务数据传递的,其目的就是确保服务端和客户端能建立连接,方式也很简单,向对方发送的请求有回应就算连接成功,由于没有业务数据的传递,这......
  • 网络服务性能优化:Wrktcp与Perf工具详解
    wrktcp安装码云地址:https://gitee.com/icesky1stm/wrktcp直接下载,cdwrktcp-master&&make,会生成wrktcp,就ok了,很简单wrktcp使用压测首先需要一个服务,写了一个epoll+边沿触发的服务,业务是判断ip是在国内还是国外,rq:00000015CHECKIP1.0.4.0,rs:000000010,写的有些就简陋兑付看......
  • PbootCMS未检测到您服务器环境的sqlite3数据库扩展
    在使用PBootCMS时,如果系统提示“未检测到您服务器环境的sqlite3数据库扩展”,这意味着服务器上缺少必要的SQLite3扩展。SQLite3是一种轻量级的嵌入式数据库引擎,广泛用于Web应用开发。为了解决这个问题,你需要确保服务器上已安装并启用了SQLite3扩展。解决方法检查PHP环境:确认......
  • 内网穿透技术的思考--反向代理、TCP 隧道、 UDP 打洞--C++代码示例
    概述内网穿透是一种技术,用于在私有局域网(LAN)中的设备与外部网络(如互联网)之间建立通信通道,使得外部设备可以访问内网中的服务。由于内网设备通常位于防火墙或NAT(网络地址转换)设备之后,外部网络无法直接访问它们。因此,内网穿透技术旨在解决这一问题。本文将讨论如何使用C++实现......
  • 网络编程介绍&TCP&UDP协议
    1.网络编程入门1.1网络编程概述计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统网络编程在网络通信协议下,不同计算机上运行的程序......
  • 网站打开提示:”未检测到您服务器环境的sqlite3数据库扩展...“
    当你的网站打开时提示“未检测到您服务器环境的sqlite3数据库扩展”,这意味着你的PHP环境缺少对SQLite3的支持。SQLite3是一个轻量级的数据库引擎,它作为PHP的一个扩展来提供支持。要解决这个问题,你可以按照以下步骤操作:1.检查PHP版本首先确认你的PHP版本支持SQLite3。SQLite3支......
  • 未检测到您服务器环境的sqlite3数据库扩展,请检查php.ini中是否已经开启该扩展
    当你遇到“未检测到您服务器环境的sqlite3数据库扩展,请检查php.ini中是否已经开启该扩展”的提示时,这表明PHP当前的安装环境中没有启用SQLite3支持。SQLite3是一个轻量级的嵌入式数据库引擎,它通常用于不需要完整服务器端数据库解决方案的应用场景。解决方法1.检查 ph......
  • 720. 词典中最长的单词
    题目链接720.词典中最长的单词思路Trie树的经典应用题解链接官方题解关键点构建Trie树时间复杂度\(O(\sum_{i}\#\text{word}_{i})\)空间复杂度\(O(\sum_{i}\#\text{word}_{i})\)代码实现:classTrie:def__init__(self):self.childr......