一、概述 

本文章是来自于华清远见的一个基于C语言的网络电子词典项目,使用到了tcp协议的并发服务器设计、网络编程、文件I/O、数据库等多方面的知识。可以满足多用户同时登陆,用户登陆后可以查询单词及历史记录,具有查找快速,保密性好等优点。对于初学嵌入式的同学们是一个非常不错的练习项目。

二、拓扑结构图

三、项目流程

简化版流程图

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

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

四、实现效果

注册

登录

查单词

查历史记录

五、代码

客户端代码

#include "head.h"
//用户提示界面1
void help_info1()
{printf("\t-----------------------------------------------\n");printf("\t|               HENRY   在线辞典               |\n");printf("\t|版本:0.0.1                                    |\n");printf("\t|作者:Demons457                                |\n");printf("\t|功能:                                         |\n");printf("\t|    [1] 登录                                  |\n");printf("\t|    [2] 注册                                  |\n");printf("\t|    [3] 退出                                  |\n");printf("\t|注意:用户只有登录成功后才能进入查单词界面     |\n");printf("\t------------------------------------------------\n");return;
}
void help_info2()
{printf("\t-----------------------------------------------\n");printf("\t|     欢迎进入单词查询系统,很高兴为您服务     |\n");printf("\t|版本:0.0.1                                    |\n");printf("\t|作者:Demons457                                |\n");printf("\t|功能:                                         |\n");printf("\t|    [1] 查单词                                |\n");printf("\t|    [2] 查询历史记录                          |\n");printf("\t|    [3] 退出查询系统                          |\n");printf("\t|注意:用户只有登录成功后才能进入查单词界面     |\n");printf("\t------------------------------------------------\n");return;
}//用户输入指令,供大家选择
enum{LOGIN    = 1,  //登陆REGISTER = 2,  //注册QUIT     = 3,  //退出QUERY    = 1,  //查询单词HISTORY  = 2,  //查询历史
};int init_tcp(char *ip,char *port)
{int sockfd;struct sockaddr_in server_addr;if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0){perror("Fail to socket"); exit(EXIT_FAILURE);}bzero(&server_addr,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(port));server_addr.sin_addr.s_addr = inet_addr(ip);if(connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0){perror("Fail to bind");   exit(EXIT_FAILURE);}return sockfd;
}int do_register(int sockfd)
{int n = 0;int count = 0;char buf[1024] = {0};//定义发送的协议头mhead_t *head = (mhead_t *)buf;printf("\n您正在注册,请输入用户名和密码\n");head->type = USER_REGISTER;head->size = sizeof(mhead_t);printf("Input username : ");fgets(head->username,sizeof(head->username),stdin);head->username[strlen(head->username) - 1] = '\0';printf("Input password : ");fgets(head->password,sizeof(head->password),stdin);head->password[strlen(head->password) - 1] = '\0';//发给服务器端if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}bzero(&buf,sizeof(buf));while(1){//接收数据,TCP是可靠的连接,若是数据//未完全接收的话,可以在接收n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){perror("Fail to send");exit(EXIT_FAILURE);}//若是数据未发送完成,再次接收的时候可补充count += n;if(count == sizeof(mhead_t))break;}if(head->type == USER_SUCCESS){printf("\n恭喜您,注册成功!\n");    return 0;}else{printf("\n很遗憾,这个用户名已经被其它用户注册过了,请重新注册");  return -1;}}
int do_query(int sockfd)
{int n = 0;int fd;int count = 0;char buf[1024] = {0};char buf1[128]={0};char buf2[128]={0};char buf3[]="\n";fd=open("/home/linux/22061/2/client/history.txt",O_RDWR|O_CREAT|O_TRUNC,0666);if(fd<0){perror("Fail to open");return -1;}//定义发送的协议头mhead_t *head = (mhead_t *)buf;printf("\n您正在查询单词\n");head->type = USER_WORD;head->size = sizeof(mhead_t);printf("pelse input word : ");fgets(head->word,sizeof(head->word),stdin);head->word[strlen(head->word) - 1] = '\0';strcpy(buf1,head->word);if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}bzero(&buf,sizeof(buf));while(1){//接收数据,TCP是可靠的连接,若是数据//未完全接收的话,可以在接收n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){perror("Fail to send");exit(EXIT_FAILURE);}//若是数据未发送完成,再次接收的时候可补充count += n;if(count == sizeof(mhead_t))break;}//把服务器返回的信息打印出来if(head->type == USER_SUCCESS){printf(" word:%s\n",head->word); time_t t;time(&t);sprintf(buf2,"\n%s\n",ctime(&t));write(fd,buf1,strlen(buf1));write(fd,buf2,strlen(buf2));write(fd,head->word,strlen(head->word));write(fd,buf3,strlen(buf3));close(fd);return 0;}else{printf("\n很遗憾,没有此单词,请重新输入\n");  return -1;}}
int do_history(int sockfd)
{int fd,n;char buf[1024]={0};fd=open("/home/linux/22061/2/client/history.txt",O_RDONLY);if(fd<0){perror("Fail to open");return -1;}while(1){n=read(fd,buf,sizeof(buf));if(0==n)break;puts(buf);}return 0;
}
int do_task2(int sockfd)
{int cmd;while(1){//提示界面帮助,用户选择help_info2(); printf("\n\n请选择>");scanf("%d",&cmd);//吃掉回车键getchar();switch(cmd){//用户查询单词case QUERY:if(do_query(sockfd) < 0)continue;break;//用户登陆case HISTORY:if(do_history(sockfd)<0)continue;break;case QUIT:exit(EXIT_SUCCESS);default:printf("Unknow cmd.\n");continue;}}return 0;
}int do_login(int sockfd)
{int n = 0;int count = 0;char buf[1024] = {0};//定义发送的协议头mhead_t *head = (mhead_t *)buf;printf("\n您正在登陆,请输入用户名和密码\n");head->type = USER_LOGIN;head->size = sizeof(mhead_t);printf("Input username : ");fgets(head->username,sizeof(head->username),stdin);head->username[strlen(head->username) - 1] = '\0';printf("Input password : ");fgets(head->password,sizeof(head->password),stdin);head->password[strlen(head->password) - 1] = '\0';//发给服务器端if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}bzero(&buf,sizeof(buf));while(1){//接收数据,TCP是可靠的连接,若是数据//未完全接收的话,可以在接收n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){perror("Fail to send");exit(EXIT_FAILURE);}//若是数据未发送完成,再次接收的时候可补充count += n;if(count == sizeof(mhead_t))break;}if(head->type == USER_SUCCESS){printf("\n恭喜您,登陆成功!\n");  do_task2(sockfd);return 0;}else{printf("\n很遗憾,您的帐号或密码错误,请重新输入");    return -1;}}
int do_task(int sockfd)
{int cmd;while(1){//提示界面帮助,用户选择help_info1(); printf("\n\n请选择>");scanf("%d",&cmd);//吃掉回车键getchar();switch(cmd){//用户注册,我们先来写注册的函数case REGISTER:if(do_register(sockfd) < 0)continue;break;//用户登陆case LOGIN:if(do_login(sockfd)<0)continue;break;case QUIT:exit(EXIT_SUCCESS);default:printf("Unknow cmd.\n");continue;}}return 0;
}//./client ip port
//由于后面要传递参数,故这里的const省略
int main(int argc, char *argv[])
{int sockfd;    int addr_len = sizeof(struct sockaddr);struct sockaddr_in peer_addr;if(argc < 3){fprintf(stderr,"Usage : %s argv[1] argv[2]\n",argv[0]);  exit(EXIT_FAILURE);}sockfd = init_tcp(argv[1],argv[2]);do_task(sockfd);return 0;
}

服务器代码

#include "head.h"void signal_handler(int signum)
{waitpid(-1,NULL,WNOHANG);return;
}
int init_tcp(char *ip,char *port)
{int sockfd;struct sockaddr_in server_addr;if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0){perror("Fail to socket");exit(EXIT_FAILURE);}bzero(&server_addr,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port   = htons(atoi(port));server_addr.sin_addr.s_addr = inet_addr(ip);if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0){perror("Fail to bind");exit(EXIT_FAILURE);}listen(sockfd,5);printf("listen....\n");return sockfd;
}//.server ip port db
//数据库中已经手动创建了2个表:user_table,word_table
//注:由于我们后面函数要传承,故这里的const应该去掉
int main(int argc, char *argv[])
{int pid;   sqlite3 *pdb;int listenfd,connect_fd;int addr_len = sizeof(struct sockaddr);struct sockaddr_in peer_addr;if(argc < 4){fprintf(stderr,"Usage : %s ip port system.db.\n",argv[0]);exit(EXIT_FAILURE);}//探测子进程的改变状态,回收僵尸态子进程if(signal(SIGCHLD,signal_handler) == SIG_ERR){perror("Fail to signal");exit(EXIT_FAILURE);}if(sqlite3_open(argv[3],&pdb) != SQLITE_OK){fprintf(stderr,"sqlite3 open %s : %s.\n",argv[3],sqlite3_errmsg(pdb));exit(EXIT_FAILURE);}//初始化tcp连接,得到监听套接字listenfd = init_tcp(argv[1],argv[2]);//提取客户段的链接请求,创建子进程和客户端交互while(1){if((connect_fd = accept(listenfd,(struct sockaddr *)&peer_addr,&addr_len)) < 0){perror("Fail to accept");exit(EXIT_FAILURE);}if((pid = fork()) < 0){perror("Fail to fork");exit(EXIT_FAILURE);}//创建子进程处理客户端的请求if(pid == 0){close(listenfd);do_client(connect_fd,pdb);}close(connect_fd);}exit(EXIT_SUCCESS);
}
#include "head.h" int do_register(int sockfd,sqlite3 *pdb,char *_username,char *_password)
{char *errmsg;char buf[1024];char **dbresult;int nrow = 0,ncolumn = 0;char sql[1024] = {0};mhead_t *head = (mhead_t *)buf;  sprintf(sql,"select * from user_table where NAME='%s';",_username);if(sqlite3_get_table(pdb,sql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){fprintf(stderr,"sqlite3 get table error : %s.\n",errmsg);exit(EXIT_FAILURE);}//没有这样的用户名if(nrow == 0){//录入数据库bzero(sql,sizeof(sql));sprintf(sql,"insert into user_table values('%s','%s');",_username,_password);EXEC_SQL(pdb,sql,errmsg);printf("ok ........\n");head->type = USER_SUCCESS;if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}//注册失败,用户名存在}else{head->type = USER_FAILURE;if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}//表示未知    printf("???????\n");}//插入到数据库之后,释放dbresult结果sqlite3_free_table(dbresult);return 0;
}int do_login(int sockfd,sqlite3 *pdb,char *_username,char *_password)
{  char *errmsg;int i,j;char buf[1024];char **dbresult;int nrow = 0,ncolumn = 0;char sql[1024] = {0};mhead_t *head = (mhead_t *)buf;    char *zsql="select * from user_table";int index=0;
//查找数据库中是否有该帐号//    sprintf(sql,"select * from user_table where NAME='%s';",_username);if(sqlite3_get_table(pdb,zsql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){fprintf(stderr,"sqlite3 get table error : %s.\n",errmsg);exit(EXIT_FAILURE);}//登陆for(i=0;i<=nrow;i++){for(j=0;j<ncolumn;j++){if(strcmp(dbresult[index],_username)==0&&strcmp(dbresult[index+1],_password)==0){printf("登陆成功\n");head->type=USER_SUCCESS;printf("%d\n",head->type);if(send(sockfd,buf,sizeof(mhead_t),0)<0){perror("Fail to send");exit(EXIT_FAILURE);}sqlite3_free_table(dbresult);return 0;}}index++;}//帐号密码错误head->type=USER_FAILURE;if(send(sockfd,buf,sizeof(mhead_t),0)<0){perror("Fail to send");exit(EXIT_FAILURE);}printf("??????\n");sqlite3_free_table(dbresult);return 0;
}
int do_word(int sockfd,sqlite3 *pdb,char *_word)
{char *errmsg;int i,j;char buf[1024];char **dbresult;int nrow = 0,ncolumn = 0;char sql[1024] = {0};char *zsql="select * from dict_table";int index;mhead_t *head = (mhead_t *)buf;
//查找数据库中是否有该单词//sprintf(sql,"select * from dict_table where word='%s';",_word);if(sqlite3_get_table(pdb,zsql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){fprintf(stderr,"sqlite3 get table error : %s.\n",errmsg);exit(EXIT_FAILURE);}for(i=0;i<=nrow;i++){for(j=0;j<ncolumn;j++){if(strcmp(dbresult[index],_word)==0){//查单词printf("ok\n");head->type=USER_SUCCESS;strcpy(head->word,dbresult[index+1]);if(send(sockfd,buf,sizeof(mhead_t),0)<0){perror("Fail to send");exit(EXIT_FAILURE);}printf("%d\n",index);sqlite3_free_table(dbresult);return 0;}index++;}}//查找失败,没有该单词head->type=USER_FAILURE;if(send(sockfd,buf,sizeof(mhead_t),0)<0){perror("Fail to send");exit(EXIT_FAILURE);}printf("?????\n");sqlite3_free_table(dbresult);return 0;
}
int do_client(int sockfd,sqlite3 *pdb)
{int n;int count = 0;char buf[1024];mhead_t *head = (mhead_t *)buf;   while(1){count = 0;//接收协议头while(1){n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){exit(EXIT_FAILURE);}count += n;printf("count : %d mhead_t : %ld\n",count,sizeof(mhead_t));if(count == sizeof(mhead_t))break;}switch(head->type){case USER_REGISTER:do_register(sockfd,pdb,head->username,head->password);    break;case USER_LOGIN:do_login(sockfd,pdb,head->username,head->password);break;case USER_WORD:do_word(sockfd,pdb,head->word);break;defalut:exit(EXIT_SUCCESS);}    }return 0;
}

注:要完全实现该项目,还需要专门的数据库文件、Makefile、head.h文件等,以上代码和思路提供给大家参考,谢谢。

基于C语言的网络电子词典相关推荐

  1. 基于SSH的通讯网络电子计费系统 毕业论文+任务书+开题报告+文献综述+外文翻译及原文+答辩PPT+代码清单+项目源码及数据库文件

    下载地址:https://download.csdn.net/download/junkyio321/40671271 项目介绍: 基于SSH的通讯网络电子计费系统 毕业论文+任务书+开题报告+文献综 ...

  2. java 解析数据包_一种基于Java语言的网络通讯数据包解析方法与流程

    本发明涉及网络通讯领域,特别涉及一种基于Java语言的网络通讯数据包解析方法. 背景技术: 计算机系统和网络的大量普及使用使全球跨入了信息化时代.但是,正由于现代社会中几乎一切都在"计算机化 ...

  3. 基于 TCP协议和sqlite3数据库的网络电子词典(个人项目)

    一.开发环境:Ubuntu 16.04 二.项目描述: 基于TCP协议的并发服务器设计,采用sql数据库进行数据存储,文件保存历史查询数据,能满足多用户同时登陆,实现用户的注册.登录以及退出,登录成功 ...

  4. 基于android的电子词典设计_基于Android平台下的电子词典的设计与实现

    摘要:现如今已经是二十一世纪,以计算机为代表的现代科学获得了蓬勃快速的发展并快速和人们的日常行为结合在一起.同时随着英语对人类的生活有着越来越大的影响,计算机信息技术的发展与进步也使电子语言词典的诞生 ...

  5. 便于查询增加索引文件 c语言,英汉电子词典小项目总结

    最近通过所学习的c语言的知识,我们几个小伙伴们合作写了一个功能不完整的电子词典,有一些注意的地方,在这里总结下. 下面是电子词典的需求分析 C语言项目--查字典 [项目需求描述] 一.单词查询 给定文 ...

  6. 基于C语言STC89C52单片机电子密码锁的设计与仿真

    arm实现较为简单, 功能较为完善, 因此使用单片机控制较多. 显示器少数用数码管. 而本文所介绍的电子密码锁使用移植性及可读性强的高级语言C语言编写, 使用更加方便. 从经济适用的角度出发, 采用S ...

  7. c语言密码锁门禁系统程序,基于C语言STC89C52单片机电子密码锁的系统设计与仿真...

    摘 要:介绍一种通过 Protues 软件成功仿真的电子密码锁的实现过程.它采用高可靠性的STC89C52单片机来实现*和密码酌识别,采用具备IC总线接田的EPROM芯片来完成密码的聋储,通过l602 ...

  8. 基于C语言的网络编程的项目

    首先,这个项目仅仅只是一个模板,需要大家进行后续开发,我把此模板进行开源 我这个项目运用到的技术有TCP通信协议.IO多路复用.sqlite3数据库.循环服务器等,在进行编写之前,需要大家进行了解(当 ...

  9. 基于C语言的网络编程笔记分享

    网络编程 OSI模型与TCP/IP协议体系结构 OSI模型 七层 理想化模型(并不是真正使用的模型,有参考价值) 应用层 数据处理 表示层 数据的加密解密ASCII -> 电信号 -> A ...

最新文章

  1. 腾讯Elasticsearch海量规模背后的内核优化剖析
  2. IOS性能调优系列:使用Time Profiler发现性能瓶颈
  3. JFileChooser多选、选择目录
  4. POJ 2229 Sumsets
  5. 女朋友当众甩了我一巴掌,我扑上去......
  6. 07-异常处理——动手动脑
  7. ps图片如何实现渐变
  8. zero-shot learning
  9. 地方命令SqlServer2008中解决在表上点右键把【编辑前200行】变成【编辑前10000行】的方法!...
  10. zabbix监控操纵系统日志
  11. pragma autonomous_transaction详解
  12. 使用Photoshop+960 Grid System模板进行网页设计
  13. Windows监控日志文件 Tail for Win32
  14. 爱测未来移动-iTest特色功能介绍
  15. Java 实例 - 字符串小写转大写
  16. 伊拉克COR证书电子电器
  17. BIM模型文件下载——某幼儿园设计方案Revit模型
  18. 教你一招利用python在网上接单赚钱,月薪过万太香了
  19. 百度智能运维的技术演进之路
  20. 电弧故障断路器全国产化电子元件推荐方案

热门文章

  1. EclipseSVN更新和提交
  2. dicom 的mm换算成像素Pixel
  3. 电子设计教程17:从共射极放大电路到射极跟随电路
  4. linux web 网站搭建
  5. zzulioj 1029: 三角形判定
  6. win7 svchost.exe占用内存和CPU很高,电脑很卡的解决方法
  7. 应用MATLAB求解线性代数题目(三)——n维向量
  8. [转载] 晓说——第5期:张学良观虎斗旧电报还原军阀“宫心计”
  9. PM 如何进行测试?
  10. 几个cve漏洞库查询网站