项目名称:无源在线词典项目

一,概述  

  基于C语言的网络电子词典项目,使用到了tcp协议的并发服务器设计、网络编程、文件I/O、数据库等多方面的知识。可以满足多用户同时登陆,用户登陆后可以查询单词及历史记录,具有查找快速,保密性好等优点。

开发工具: Linux平台GCC交叉编译环境
功能描述:
1、可进行用户注册、登录
2、可对用户查找的单词进行存储,放入SQLite数据库中,对历史记录进行查询。
3、可进行查看和修改用户信息,包括用户名,密码等
4、分为客户端和服务器端,客户端进行用户的注册登录和查找单词等操作,服务器端进行操作数据库,进行存储和查找 
 

项目框架


二,需求分析 

1.注册:若用户名已经注册过,可重新注册
2.登录:用户名或密码错误需重新登录
3.查询:输入要查的单词,#键结束查询
4.历史:可以查询当前用户历史查找过的单词
5.退出:退出在线词典

server服务端(流程图)

client客户端

 三,项目流程

1.首先搭建一个tcp客户端,一级界面包含组成、登录、退出,二级界面包含单词查询、历史记录、退出。

2.由客户端首先进入注册界面,输入注册的账号和密码,账号和密码就传入到user数据库中保存。再进入登录界面,输入账号和密码,当匹配到user数据库中有相同的账号和密码的时候,就进入二级界面。选择单词查询,输入查询的单词后,匹配dict数据库中的单词,找到该单词后返回单词在数据库中的注释,同时记录进去一条历史记录。选择历史记录,就可调出本次查询的单词、查询时间等信息。选择退出后结束该程序。

四,实战代码:

(1)客服端开发:

主程序

int main(int argc, const char *argv[])
{int sockfd;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;}struct sockaddr_in  serveraddr;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;}char buf[100];while(1){printf("*****************************************************************\n");printf("* 1.register          2.login              3.quit               *\n");printf("*****************************************************************\n");printf("Please choose:");fgets(buf, sizeof(buf), stdin);n = atoi(buf);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:");fgets(buf, sizeof(buf), stdin);n = atoi(buf);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;
}

函数——注册

//注册
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);getchar();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);getchar();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;
}

服务器开发:

主程序

//0主函数
int main(int argc, const char *argv[])
{int sockfd;struct sockaddr_in  serveraddr;int n;MSG  msg;sqlite3 *db;int acceptfd;pid_t pid;char *errmsg;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;}elseprintf("open DATABASE success.\n");if(sqlite3_exec(db, "create table if not exists usr(name text primary key,pass text);",//primary key主关键字只能有一个NULL, NULL, &errmsg) != SQLITE_OK){printf("%s\n", errmsg);}elseprintf("Create or open usr table success.\n");if(sqlite3_exec(db, "create table if not exists record(name text ,data text,word text);",NULL, NULL, &errmsg) != SQLITE_OK){printf("%s\n", errmsg);}elseprintf("Create or open record table 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_child_handle);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;
}

函数——登录进入

//1登陆
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;
}

函数——注册

//2注册
void do_register(int acceptfd, MSG *msg, sqlite3 *db)
{char * errmsg;char sql[500];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 ;
}

函数——登录

//3登陆
int do_login(int acceptfd, MSG *msg , sqlite3 *db)
{char sql[500] = {};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;}elseprintf("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;
}

函数——查询

//3查询
int do_query(int acceptfd, MSG *msg , sqlite3 *db)
{char word[64];int found = 0;char date[128] = {};char sql[500] = {};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;
}

函数——打开文件查词

//3.1打开文件查词
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;
}

函数——获得日期

//3.2获得日期
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;
}

函数——查询历史

//4.查询历史
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);elseprintf("Query record done.\n");// 所有的记录查询发送完毕之后,给客户端发出一个结束信息msg->data[0] = '\0';send(acceptfd, msg, sizeof(MSG), 0);return 0;
}

函数——历史结果--回调函数 得到查询结果,并且需要将历史记录发送给客户端

//4.1历史结果--回调函数
// 得到查询结果,并且需要将历史记录发送给客户端
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;
}

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

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

相关文章

JAVA集成国密SM4

JAVA集成国密SM4加解密 一、pom配置二、代码集成2.1、目录结构2.2、源码2.3、测试 三、遇到的坑3.1、秘钥长度3.2、转码问题 四、相关链接 国密算法概述&#xff1a;https://blog.csdn.net/qq_38254635/article/details/131801527 SM4对称算法 SM4 无线局域网标准的分组数据算…

c++内存映射文件

概念 将一个文件直接映射到进程的进程空间中&#xff08;“映射”就是建立一种对应关系,这里指硬盘上文件的位置与进程逻辑地址空间中一块相同区域之间一 一对应,这种关系纯属是逻辑上的概念&#xff0c;物理上是不存在的&#xff09;&#xff0c;这样可以通过内存指针用读写内…

qt 32位编译 内存溢出 无法 运行在win7 32位

项目在 编译32位系统 内存溢出 设置成了x64 但是 最后在xp32位系统运行提示 在下载了n个dll之后发现这种状况无穷无尽&#xff0c;后来在查阅资料时发现可以直接打开qt安装目录下的“vcredist”文件夹&#xff0c;将对应位数的程序拷到win7电脑上&#xff0c;直接运行&…

Orleans 微软基于 Actor 的分布式框架

一、Actor模型工作原理 Actor模型是一种并发编程模型&#xff0c;它基于消息传递实现&#xff0c;是一种轻量级的并发模型。在Actor模型中&#xff0c;每个Actor都是一个独立的执行单元&#xff0c;它可以接收和发送消息&#xff0c;并且可以执行一些本地操作&#xff0c;但是不…

【ARM Cortex-M 系列 1 -- Cortex-M0, M3, M4, M7, M33 差异】

文章目录 Cortex-M 系列介绍Cortex-M0/M0 介绍Cortex-M3/M4 介绍Cortex-M7 介绍Cotex-M33 介绍 下篇文章&#xff1a;ARM Cortex-M 系列 2 – CPU 之 Cortex-M7 介绍 Cortex-M 系列介绍 Cortex-M0/M0 介绍 Cortex-M0 是 ARM 公司推出的一款微控制器&#xff08;MCU&#xff0…

网络安全在2023好入行吗?

前言 023年的今天&#xff0c;慎重进入网安行业吧&#xff0c;目前来说信息安全方向的就业对于学历的容忍度比软件开发要大得多&#xff0c;还有很多高中被挖过来的大佬。 理由很简单&#xff0c;目前来说&#xff0c;信息安全的圈子人少&#xff0c;985、211院校很多都才建…

高时空分辨率、高精度一体化预测技术之风、光、水能源自动化预测技术

能源是国民经济发展和人民生活必须的重要物质基础。在过去的200多年里&#xff0c;建立在煤炭、石油、天然气等化石燃料基础上的能源体系极大的推动了人类社会的发展。但是人类在使用化石燃料的同时&#xff0c;也带来了严重的环境污染和生态系统破坏。近年来&#xff0c;世界各…

python appium UI 自动化测试框架讨论

目录 前言&#xff1a; 框架共性总结 Auto_Analysis 权限弹窗识别 前言&#xff1a; Python Appium UI自动化测试框架是一种用于测试移动应用程序的工具&#xff0c;它结合了Python编程语言和Appium测试框架的功能。 框架共性总结 1 自动找设备 连接设备 2 自动启 appium …

《数据结构》数据结构概念,顺序表,链表

目录 1. 为什么学习数据结构&#xff1f; 2. 数据结构 2.1. 数据 2.2. 逻辑结构 2.3. 存储结构 2.4. 操作 3. 算法 3.1. 算法与程序 3.2. 算法与数据结构 3.3. 算法的特性 3.4. 如何评价一个算法的好坏 4. 线性表 4.1. 顺序表 4.2. 单向链表 4.3. 单向循环链表&…

SpringBoot使用Redis作为缓存器缓存数据的操作步骤以及避坑方案

1.非注解式实现 2.1使用之前要明确使用的业务场景 例如我们在登录时&#xff0c;可以让redis缓存验证码&#xff0c;又如在分类下显示菜品数据时&#xff0c;我们可以对分类和菜品进行缓存数据等等。 2.2导入Redis相关依赖 <dependency><groupId>org.springfra…

SpringAMQP - 消息传输时,如何提高性能?解决 SQL 注入问题?

目录 一、问题背景 二、从消息转化器根源解决问题 1.引入依赖 2.在服务生产者和消费者中都重新定义一个 MessageConverter&#xff0c;注入到 Spring 容器中 一、问题背景 在SpringAMQP的发送方法中&#xff0c;接收消息的类型是Object&#xff0c;也就是说我们可以发送任意…

DB-Engines排名公布 GBASE南大通用入围国产数据库TOP 3

什么是DB-Engines排名&#xff1f; DB-Engines排名是数据库领域的流行度榜单&#xff0c;它对全球范围内的419款数据库&#xff08;截至2023年7月&#xff09;进行排名&#xff0c;每月更新一次&#xff0c;排名越靠前&#xff0c;则表示越流行。在很多技术选型的场合&#xf…

【idea】idea全局设置Maven配置

Idea版本&#xff1a;2021.1.1 1、点击File->Close project 2、点击Customize->All settings 3、设置Maven

# Linux终端控制字符详解以及简单应用实践

Linux终端控制字符详解以及简单应用实践 文章目录 Linux终端控制字符详解以及简单应用实践1 控制字符表2 控制字符 ESC &#xff08;0x1B&#xff0c;^[&#xff09;子参数表3 控制字符 ESC &#xff08;0x1B&#xff0c;^[&#xff09;子参数表 - 字符颜色参照表4 实践&#x…

Python实现HBA混合蝙蝠智能算法优化循环神经网络分类模型(LSTM分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蝙蝠算法是2010年杨教授基于群体智能提出的启发式搜索算法&#xff0c;是一种搜索全局最优解的有效方法…

2023无监督摘要顶会论文合集

2023无监督摘要顶会论文合集 写在最前面ACL-2023Aspect-aware Unsupervised Extractive Opinion Summarization 面向的无监督意见摘要&#xff08;没找到&#xff09;Unsupervised Extractive Summarization of Emotion Triggers *情绪触发(原因)的 *无监督 *抽取式 摘要&#…

DETR (DEtection TRansformer)基于自建数据集开发构建目标检测模型超详细教程

目标检测系列的算法模型可以说是五花八门&#xff0c;不同的系列有不同的理论依据&#xff0c;DETR的亮点在于它是完全端到端的第一个目标检测模型&#xff0c;DETR&#xff08;Detection Transformer&#xff09;是一种基于Transformer的目标检测模型&#xff0c;由Facebook A…

Redis 从入门到精通【进阶篇】之高可用集群(Redis Cluster)详解

文章目录 0. 前言设计目标核心概念 1. 架构设计和原理1.1. 数据分片2. 节点间通信6. 扩容和缩容 2. 总结3. Redis从入门到精通系列文章4. Redis Cluster面试题4.1. Redis Cluster如何进行扩容和缩容&#xff1f;4.2. Redis Cluster如何进行故障转移&#xff1f;4.3. Redis Clus…

【问题分析解决】git添加.gitignore后不生效问题

一&#xff0c;问题现象 在已经提交过的git管理的项目中&#xff0c;新增加一个.gitignore文件&#xff0c;或者修改.gitignore文件之后&#xff0c;新增的内容不生效。 二&#xff0c;问题原因 因为我们误解了.gitignore文件的用途&#xff0c;该文件只能作用于Untracked F…

JDK JRE JVM

JDK JRE JVM JDKJREJVM三者之间的联系三者之间的区别 JDK JDK是用于开发、编译、调试和运行Java应用程序的软件包&#xff0c;包含了Java编程语言的开发工具和Java运行时环境。JDK包括Java编译器&#xff08;javac&#xff09;、Java虚拟机&#xff08;JVM&#xff09;和Java类…