Linux小项目:在线词典开发

在线词典介绍

  • 流程图如下:
    在这里插入图片描述
  • 项目的功能介绍
    • 在线英英词典
    • 项目功能描述
    • 用户注册和登录验证
    • 服务器端将用户信息和历史记录保存在数据中。客户端输入用户和密码,服务器端在数据库中查找、匹配,返回结果
    • 单词在线翻译
    • 根据客户端输入输入的单词在字典文件中搜索
    • 历史记录查询
    • 项目分析
  • 项目流程
    • 定义数据库中表的结构
    • 定义消息结构体
    • 分析服务端和客户端流程
    • 编码实现
  • 客户端流程图分析
    • 服务器和客户端通信的结构体
      在这里插入图片描述
    • 客户端流程图如下:
      在这里插入图片描述
    • 服务器端流程图如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/64b2312c006e4298a3f382597ff62558.png

在线词典的代码编写

  • 客户端代码的编写:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>#define   N  32#define  R  1   // user - register
    #define  L  2   // user - login
    #define  Q  3   // user - query
    #define  H  4   // user - history// 定义通信双方的信息结构体
    typedef struct {int type;char name[N];char data[256];
    }MSG;int  do_register(int sockfd, MSG *msg)
    {msg->type = R;printf("Input name:");scanf("%s", msg->name);getchar();printf("Input passwd:");scanf("%s", msg->data);if(send(sockfd, msg, sizeof(MSG),0) < 0){printf("fail to send.\n");return -1;}if(recv(sockfd, msg, sizeof(MSG), 0) < 0){printf("Fail to recv.\n");return -1;}// ok !  or  usr alread exist.printf("%s\n", msg->data);return 0;
    }int do_login(int sockfd, MSG *msg)
    {msg->type = L;printf("Input name:");scanf("%s", msg->name);getchar();printf("Input passwd:");scanf("%s", msg->data);if(send(sockfd, msg, sizeof(MSG),0) < 0){printf("fail to send.\n");return -1;}if(recv(sockfd, msg, sizeof(MSG), 0) < 0){printf("Fail to recv.\n");return -1;}if(strncmp(msg->data, "OK", 3) == 0){printf("Login ok!\n");return 1;}else {printf("%s\n", msg->data);}return 0;
    }int do_query(int sockfd, MSG *msg)
    {msg->type = Q;puts("--------------");while(1){printf("Input word:");scanf("%s", msg->data);getchar();//客户端,输入#号,返回到上一级菜单if(strncmp(msg->data, "#", 1) == 0)break;//将要查询的单词发送给服务器if(send(sockfd,msg, sizeof(MSG), 0) < 0){printf("Fail to send.\n");return -1;}// 等待接受服务器,传递回来的单词的注释信息if(recv(sockfd, msg,sizeof(MSG), 0) < 0){printf("Fail to recv.\n");return -1;}printf("%s\n", msg->data);}return 0;
    }int do_history(int sockfd, MSG *msg)
    {msg->type = H;send(sockfd, msg, sizeof(MSG), 0);// 接受服务器,传递回来的历史记录信息while(1){recv(sockfd, msg, sizeof(MSG), 0);if(msg->data[0] == '\0')break;//输出历史记录信息printf("%s\n", msg->data);}return 0;
    }// ./server  192.168.3.196  10000
    int main(int argc, const char *argv[])
    {int sockfd;struct sockaddr_in  serveraddr;int n;MSG  msg;if(argc != 3){printf("Usage:%s serverip  port.\n", argv[0]);return -1;}if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0){perror("fail to socket.\n");return -1;}bzero(&serveraddr, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));if(connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){perror("fail to connect");return -1;}while(1){printf("*****************************************************************\n");printf("* 1.register          2.login              3.quit               *\n");printf("*****************************************************************\n");printf("Please choose:");scanf("%d", &n);getchar();switch(n){case 1:do_register(sockfd, &msg);break;case 2:if(do_login(sockfd, &msg) == 1){goto next;}break;case 3:close(sockfd);exit(0);break;default:printf("Invalid data cmd.\n");}}next:while(1){printf("*****************************************************\n");printf("* 1.query_word   2.history_record   3.quit          *\n");printf("*****************************************************\n");printf("Please choose:");scanf("%d", &n);getchar();switch(n){case 1:do_query(sockfd, &msg);break;case 2:do_history(sockfd, &msg);break;case 3:close(sockfd);exit(0);break;default :printf("Invalid data cmd.\n");}}return 0;
    

}
```

  • 服务器端代码编写如下:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <unistd.h>
    #include <sqlite3.h>
    #include <signal.h>
    #include <time.h>#define   N  32#define  R  1   // user - register
    #define  L  2   // user - login
    #define  Q  3   // user - query
    #define  H  4   // user - history#define  DATABASE  "my.db"// 定义通信双方的信息结构体
    typedef struct {int type;char name[N];char data[256];
    }MSG;int do_client(int acceptfd, sqlite3 *db);
    void do_register(int acceptfd, MSG *msg, sqlite3 *db);
    int do_login(int acceptfd, MSG *msg, sqlite3 *db);
    int do_query(int acceptfd, MSG *msg, sqlite3 *db);
    int do_history(int acceptfd, MSG *msg, sqlite3 *db);
    int history_callback(void* arg,int f_num,char** f_value,char** f_name);
    int do_searchword(int acceptfd, MSG *msg, char word[]);
    int get_date(char *date);// ./server  192.168.3.196  10000
    int main(int argc, const char *argv[])
    {int sockfd;struct sockaddr_in  serveraddr;int n;MSG  msg;sqlite3 *db;int acceptfd;pid_t pid;if(argc != 3){printf("Usage:%s serverip  port.\n", argv[0]);return -1;}//打开数据库if(sqlite3_open(DATABASE, &db) != SQLITE_OK){printf("%s\n", sqlite3_errmsg(db));return -1;}else{printf("open DATABASE success.\n");}if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0){perror("fail to socket.\n");return -1;}bzero(&serveraddr, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){perror("fail to bind.\n");return -1;}// 将套接字设为监听模式if(listen(sockfd, 5) < 0){printf("fail to listen.\n");return -1;}//处理僵尸进程signal(SIGCHLD, SIG_IGN);while(1){if((acceptfd = accept(sockfd, NULL, NULL)) < 0){perror("fail to accept");return -1;}if((pid = fork()) < 0){perror("fail to fork");return -1;}else if(pid == 0)  // 儿子进程{//处理客户端具体的消息close(sockfd);do_client(acceptfd, db);}else  // 父亲进程,用来接受客户端的请求的{close(acceptfd);}}return 0;
    }int do_client(int acceptfd, sqlite3 *db)
    {MSG msg;while(recv(acceptfd, &msg, sizeof(msg), 0) > 0){printf("type:%d\n", msg.type);switch(msg.type){case R:do_register(acceptfd, &msg, db);break;case L:do_login(acceptfd, &msg, db);break;case Q:do_query(acceptfd, &msg, db);break;case H:do_history(acceptfd, &msg, db);break;default:printf("Invalid data msg.\n");}}printf("client exit.\n");close(acceptfd);exit(0);return 0;
    }void do_register(int acceptfd, MSG *msg, sqlite3 *db)
    {char * errmsg;char sql[128];sprintf(sql, "insert into usr values('%s', %s);", msg->name, msg->data);printf("%s\n", sql);if(sqlite3_exec(db,sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("%s\n", errmsg);strcpy(msg->data, "usr name already exist.");}else{printf("client  register ok!\n");strcpy(msg->data, "OK!");}if(send(acceptfd, msg, sizeof(MSG), 0) < 0){perror("fail to send");return ;}return ;
    }int do_login(int acceptfd, MSG *msg , sqlite3 *db)
    {char sql[128] = {};char *errmsg;int nrow;int ncloumn;char **resultp;sprintf(sql, "select * from usr where name = '%s' and pass = '%s';", msg->name, msg->data);printf("%s\n", sql);if(sqlite3_get_table(db, sql, &resultp, &nrow, &ncloumn, &errmsg)!= SQLITE_OK){printf("%s\n", errmsg);return -1;}else{printf("get_table ok!\n");}// 查询成功,数据库中拥有此用户if(nrow == 1){strcpy(msg->data, "OK");send(acceptfd, msg, sizeof(MSG), 0);return 1;}if(nrow == 0) // 密码或者用户名错误{strcpy(msg->data,"usr/passwd wrong.");send(acceptfd, msg, sizeof(MSG), 0);}return 0;
    }int do_searchword(int acceptfd, MSG *msg, char word[])
    {FILE * fp;int len = 0;char temp[512] = {};int result;char *p;//打开文件,读取文件,进行比对if((fp = fopen("dict.txt", "r")) == NULL){perror("fail to fopen.\n");strcpy(msg->data, "Failed to open dict.txt");send(acceptfd, msg, sizeof(MSG), 0);return -1;}//打印出,客户端要查询的单词len = strlen(word);printf("%s , len = %d\n", word, len);//读文件,来查询单词while(fgets(temp, 512, fp) != NULL){//	printf("temp:%s\n", temp);// abandon  abresult = strncmp(temp,word,len);if(result < 0){continue;}if(result > 0 || ((result == 0) && (temp[len]!=' '))){break;}// 表示找到了,查询的单词p = temp + len; //  abandon   v.akdsf dafsjkj //	printf("found word:%s\n", p);while(*p == ' '){p++;}// 找到了注释,跳跃过所有的空格strcpy(msg->data, p);printf("found word:%s\n", msg->data);// 注释拷贝完毕之后,应该关闭文件fclose(fp);return 1;}fclose(fp);return 0;
    }int get_date(char *date)
    {time_t t;struct tm *tp;time(&t);//进行时间格式转换tp = localtime(&t);sprintf(date, "%d-%d-%d %d:%d:%d", tp->tm_year + 1900, tp->tm_mon+1, tp->tm_mday, tp->tm_hour, tp->tm_min , tp->tm_sec);printf("get date:%s\n", date);return 0;
    }int do_query(int acceptfd, MSG *msg , sqlite3 *db)
    {char word[64];int found = 0;char date[128] = {};char sql[128] = {};char *errmsg;//拿出msg结构体中,要查询的单词strcpy(word, msg->data);found = do_searchword(acceptfd, msg, word);printf("查询一个单词完毕.\n");// 表示找到了单词,那么此时应该将 用户名,时间,单词,插入到历史记录表中去。if(found == 1){// 需要获取系统时间get_date(date);sprintf(sql, "insert into record values('%s', '%s', '%s')", msg->name, date, word);if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("%s\n", errmsg);return -1;}else{printf("Insert record done.\n");}}else  //表示没有找到{strcpy(msg->data, "Not found!");}// 将查询的结果,发送给客户端send(acceptfd, msg, sizeof(MSG), 0);return 0;
    }// 得到查询结果,并且需要将历史记录发送给客户端
    int history_callback(void* arg,int f_num,char** f_value,char** f_name)
    {// record  , name  , date  , word int acceptfd;MSG msg;acceptfd = *((int *)arg);sprintf(msg.data, "%s , %s", f_value[1], f_value[2]);send(acceptfd, &msg, sizeof(MSG), 0);return 0;
    }int do_history(int acceptfd, MSG *msg, sqlite3 *db)
    {char sql[128] = {};char *errmsg;sprintf(sql, "select * from record where name = '%s'", msg->name);//查询数据库if(sqlite3_exec(db, sql, history_callback,(void *)&acceptfd, &errmsg)!= SQLITE_OK){printf("%s\n", errmsg);}else{printf("Query record done.\n");}// 所有的记录查询发送完毕之后,给客户端发出一个结束信息msg->data[0] = '\0';send(acceptfd, msg, sizeof(MSG), 0);return 0;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/497054.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity(第八部)Vector3的三维向量和旋转(坐标和缩放也简单讲了一下)

对了&#xff0c;Unity的生命周期自行百度吧&#xff1b;我这边整理的都不是很满意 Vector 是结构体 Vector2是指里面有两个变量 Vector3是指里面有三个变量 Vector4是指里面有四个变量 Vector3常用的变量就是x y z,所以&#xff0c;它可以代表坐标、旋转、缩放、三维向量 创…

STL常见容器(list容器)---C++

STL常见容器目录&#xff1a; 6.list容器6.1 list基本概念6.2 list构造函数6.3 list 赋值和交换6.4 list 大小操作6.5 list 插入和删除6.6 list 数据存取6.7 list 反转和排序6.8自定义排序案例 6.list容器 6.1 list基本概念 功能&#xff1a; 将数据进行链式存储&#xff1b; …

密码学系列(四)——对称密码2

一、RC4 RC4&#xff08;Rivest Cipher 4&#xff09;是一种对称流密码算法&#xff0c;由Ron Rivest于1987年设计。它以其简单性和高速性而闻名&#xff0c;并广泛应用于网络通信和安全协议中。下面是对RC4的详细介绍&#xff1a; 密钥长度&#xff1a; RC4的密钥长度可变&am…

【网络那些事】

【云计算】 云计算&#xff1a;把计算资源放在某个地方&#xff0c;并通过互联网暴露出来&#xff0c;让用户可以按需使用计算资源的方式&#xff0c;就是所谓的云计算 云计算的三种服务&#xff1a; 云平台专业名词 日常叫法 亚马逊云叫法 云服务器 ECS &#xff08;Elas…

SQL注入漏洞解析-less-8(布尔盲注)

我们来看一下第八关 当我们进行尝试时&#xff0c;他只有You are in...........或者没有显示。 他只有对和错显示&#xff0c;那我们只能用对或者错误来猜他这个数据库 ?id1%27%20and%20ascii(substr(database(),1,1))>114-- ?id1%27%20and%20ascii(substr(database(),1,…

自动驾驶消息传输机制-LCM

需要用到LCM消息通讯&#xff0c;遂研究下。 这里写目录标题 1 LCM简介2. LCM源码分析3 LCM C教程与实例3.1 安装配置及介绍3.2 创建类型定义3.3 初始化LCM3.4 发布publish一个消息3.5 订阅和接收一个消息3.6 LCM进程间通讯3.7 注意事项&#xff1f;3.7.1 当数据结构定义的是数…

技术资讯:CSS滚动条样式修改,最新方式!

大家好&#xff0c;我是大澈&#xff01; 本文约800字&#xff0c;整篇阅读大约需要1分钟。 感谢关注微信公众号&#xff1a;“程序员大澈”&#xff0c;免费领取"面试礼包"一份&#xff0c;然后免费加入问答群&#xff0c;从此让解决问题的你不再孤单&#xff01;…

【查漏补缺你的Vue基础】Vue数据监听深度解析

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

RK3568 android11 调试陀螺仪模块 MPU-6500

一&#xff0c;MPU6500功能介绍 1.简介 MPU6500是一款由TDK生产的运动/惯性传感器&#xff0c;属于惯性测量设备&#xff08;IMU&#xff09;的一种。MPU6500集成了3轴加速度计、3轴陀螺仪和一个板载数字运动处理器&#xff08;DMP&#xff09;&#xff0c;能够提供6轴的运动…

小狐狸chat2.7.2免授权修复版可用版

小狐狸chat2.7.2免授权修复版可用版 在网络上面找了好几个版本不能使用&#xff0c;今天发布这个仔细测试正常使用 主要功能&#xff1a;独立版无限多开支持分销会员充值自己APP打包小程序万能创作MJ绘图多个国内接口 国外很火的ChatGPT&#xff0c;这是一种基于人工智能技术…

【前端素材】推荐优质在线家具电商Bazu平台模板(附源码)

一、需求分析 1、系统定义 家具电商平台是指专门销售家具产品的在线电子商务平台。这些平台专注于家具类商品的销售和服务&#xff0c;为消费者提供方便快捷的购买体验。 2、功能需求 家具电商平台是指专门销售家具产品的在线电子商务平台。这些平台专注于家具类商品的销售…

28. 找出字符串中第一个匹配项的下标(力扣LeetCode)

文章目录 28. 找出字符串中第一个匹配项的下标题目描述暴力KMP算法 28. 找出字符串中第一个匹配项的下标 题目描述 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。…