基于tcp和sqlite3数据库的电子词典项目
二十世界后半叶,伴随着社会的迅速发展与进步,以电子计算机为代表的现代科学技术获得了突飞猛进的发展并迅速和人们的日常生活结合在一起。计算机技术的发展和进步也使电子词典的诞生变得可能。虽然只有十来年的历史,电子词典却已经迅速发展壮大,成为词典家族中具有生命力的一员。
本系统是一个网络电子词典,主要功能是为用户提供一个能实现查询用户注册,用户登陆和查询单词机查询历史记录等功能。本文从项目的角度进行了简单的描述。该系统是基于Linux系统下里利用了网络的基本知识,及sqlite数据库的相关知识。
系统概述
我们的这套系统采用的是tcp协议的并发服务器设计,可以满足多用户同时登录,用户登录后可以查询单词及历史记录,对于数据的存储我们采用的是sql数据库技术,查找快速,保密性好!
>具体功能能如下:
<1>主界面
(1) 用户登录
(2) 用户注册
(3) 用户退出
<2>登陆成功后界面
(1) 用户登录
(2) 用户注册
(3) 用户退出
基本拓扑结构
详细设计
自定义服务器与客户端交换数据结构体
详细代码
这里我们我们采用多文件编译
head.h(服务器和客户端都需要):
#ifndef _HEAD_H_
#define _HEAD_H_#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include<unistd.h>//消息的类型
#define USER_REGISTER 10
#define USER_LOGIN 20
#define USER_WORD 30
#define USER_SUCCESS 40
#define USER_FAILURE 50//__attribute__((__packed__))
//作用:告诉编译器在编译的过程中取消优化对齐。
// 方便我们在发送和接收数据的时候一个字节一个字节的排列
typedef struct
{char _username[25]; //用户名char _password[25]; //密码
}__attribute__((__packed__))user_t;typedef struct
{int type; //消息类型int size; //消息大小union{user_t uinfo; //用户信息char _word[100]; }content;//客户端填单词,服务端填写单词解释
#define word content._word
#define username content.uinfo._username
#define password content.uinfo._password
}__attribute__((__packed__))mhead_t;//'\'表示多行链接上一行表示, #deifne ....do...while(0);
//表示封装成独立的语法单元,防止被语法错误。
//注意:'\'之后不要留空格,要不然编译会有警告#define EXEC_SQL(db,sql,errmsg) do{\if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) < 0)\{\fprintf(stderr,"sqlite3 execl [%s] error : %s.\n",sql,errmsg);\exit(EXIT_FAILURE);\}\
}while(0);#endif
客户端(client.c):
#include "head.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<time.h>
//用户提示界面1
int do_register();
int do_login();
int do_login2();
int do_query();
int do_histroy();
int do_task();
void help_info1()
{printf("\t-----------------------------------------------\n");printf("\t| HENRY 在线辞典 |\n");printf("\t|版本:0.0.1 |\n");printf("\t|作者:郁郁宇宇宇 |\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| HENRY 在线辞典 |\n");printf("\t|版本:0.0.1 |\n");printf("\t|作者:郁郁宇宇宇 |\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,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_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_login2(sockfd);return 0;}else{printf("\n很遗憾,用户名或密码错误\n"); return -1;}
}
int do_login2(int sockfd)
{int cmd;int fd;fd = open("log.txt",O_TRUNC);close(fd);while(1){help_info2();//进入第二个界面printf("\n请选择>");scanf("%d",&cmd);getchar();while(1){if(cmd == 1){do_query(sockfd);//进入查单词cmd = 0;break;}else if(cmd == 2){do_histroy(sockfd);//进入历史查询cmd = 0;break;}else if(cmd == 3){exit(EXIT_SUCCESS);}else{printf("\n输入错误,请重新输入\n");cmd = 0;break;}}}
}
int do_query(int sockfd)
{int n,count = 0;char timebuf[1024] = {0};char buf2[1024] = {0};char buf[1024] = {0};time_t t;mhead_t *head = (mhead_t *)buf;int fd = open("log.txt",O_RDWR | O_APPEND | O_CREAT,0777);printf("\n请输入单词:");head->type = USER_WORD;head->size = sizeof(mhead_t);fgets(head->word,sizeof(head->word),stdin);head->word[strlen(head->word) - 1] = '\0';strcpy(buf2,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;}time(&t);sprintf(timebuf,"%s %s %s",ctime(&t),buf2,buf);strcat(timebuf,"\n");write(fd,timebuf,strlen(timebuf));close(fd);printf("查询结果为:%s\n",buf);return 0;}int do_histroy(int sockfd)
{char buf[4096] = {0};int fd = open("log.txt",O_RDONLY);read(fd,buf,sizeof(buf));close(fd);printf("%s\n",buf);
}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;
}
服务器(server.c 负责监听多进程和多线程):
#include "head.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int do_client();
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);
}
do_client.c(负责与客户端交互,传输数据) :
#include "head.h"
int do_login();
int do_query();
int do_client();
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;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' and PASSWORD='%s';",_username,_password);if(sqlite3_get_table(pdb,sql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){fprintf(stderr,"sqlite3_free_table");exit(EXIT_FAILURE);}if(nrow == 1){head->type = USER_SUCCESS;}if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}//插入到数据库之后,释放dbresult结果sqlite3_free_table(dbresult);return 0;
}
int do_query(int sockfd,sqlite3 *pdb,char *_word)
{char *errmsg;char **dbresult;char buf[1024] = {0};int nrow = 0,ncolumn = 0;int n = 0,count= 0,index=0,ret=0;char sql[1024] = {0};mhead_t *head = (mhead_t *)buf; sprintf(sql,"select * from dict_table where word='%s';",_word);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 == 1){head->type = USER_SUCCESS; for(int i= 0;i<=nrow;i++){for(int j =0;j<ncolumn;j++){if(strcmp(dbresult[index],_word) == 0){send(sockfd,dbresult[index+1],sizeof(mhead_t),0); i = nrow+1;break;}index++;}putchar('\n');}}else{strcpy(buf,"该单词不存在\n");send(sockfd,buf,sizeof(mhead_t),0); }sqlite3_free_table(dbresult);
}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 : %d\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:puts(head->word);do_query(sockfd,pdb,head->word);break;defalut:exit(EXIT_SUCCESS);} }return 0;
}
以上就是全部内容了。
基于tcp和sqlite3数据库的电子词典项目相关推荐
- linux电子词典项目流程,毕业设计_linux下电子词典的设计与实现.doc
毕业设计_linux下电子词典的设计与实现 毕业设计(论文) 题目:Linux下电子词典的设计与实现 学 生 姓 名 学 号 201022080223 班 级 通信102202H班 所属院(系) 电子 ...
- 基于数据库及TCP网络编程实现的电子词典
目录 一.前言 二.项目介绍 三.功能实现 3.1. 用户注册 3.1.1 功能演示 3.1.2 功能函数实现 3.2. 用户登录 3.2.1 功能演示 3.2.2 功能函数实现 3.3. 查询单词 ...
- 电子词典——项目(文件编程、网络编程、sqlte3数据库)
基于文件IO.网络编程.sqlite3数据库--电子词典 一.电子词典主功能介绍 1.注册:客户端发起注册请求,服务器检测到请求后从用户数据库中遍历是否有该账号存在,若没有则直接注册:若存在该账号则注 ...
- 基于Linux平台的TCP通信并发服务器---在线英语词典项目
文章目录 前言 一.什么是并发服务器 二.服务器的实现 三.客户端的实现 四.代码测试结果 五.代码测试注意 总结 前言 本文是我在IO进线程.网络编程学习阶段的练习项目.项目基于linux平台,利用 ...
- 基于Linux系统sqlite3数据库的学生信息管理系统
学生信息管理系统 表:学生信息表 入学的时候--学号[主关键字] 姓名 性别 班级 籍贯考试成绩表 考试的时候生产的--学号[] 姓名 成绩 班级教师表 老师--名字 工号 教龄 班级功能:学生信息添 ...
- 基于TCP的大文件传输c语言项目
文章目录 前言:功能实现 tcp文件传输的基本过程: 1.用户登录 1.1创建数据库 2.文件普通下载和上传的实现: 2.1 普通下载 2.2 普通上传 2.3 文件秒上传的实现 2.断点下载和断点上 ...
- 22.12.1 电子词典项目流程图
- 电子词典(基于TCP协议多进程通信和数据库)
项目:电子词典 项目要求: 登录注册功能,不能重复登录,重复注册.用户信息也存储在数据库中. 单词查询功能 历史记录功能,存储单词,意思,以及查询时间,存储在数据库 基于TCP,支持多客户端连接 采用 ...
- 【基于TCP 在线电子词典】
基于TCP 在线电子词典 项目功能 流程图 客户端 服务器端 功能实现 服务器 客户端 功能演示 注册功能 登录功能 查询单词功能 查询记录 注销登录(返回上级) 不允许重复登录 Ctrl + C注销 ...
最新文章
- Vue(十)生命周期
- Scala Trait详解
- laravel的日志服务
- CloudFlare 免费CDN加速 使用方法
- jdialog模态化
- IOS Masonry自动布局
- android中OnItemClickListener的参数解释
- python生成随机验证码(字母加数字的组合)
- oc和java_oc与java c++语法区别
- “绿色高效 模块智能”金融业数据中心系列规范发布会将于12月7日召开
- penpyxl basic function demo code
- Flex布局演示01
- 交朋友游戏C语言,幼儿园小班社会教案《我会交朋友》游戏活动
- Chrome浏览器检查工具栏缩小
- 【参赛作品22】华为openGauss数据库行存储源代码解析
- PDF页码怎么设置?如何给PDF文件设置页码
- 什么是CRM?多角度解析CRM系统
- window.prompt的确定和取消事件
- Multisim14.0仿真:单相桥式全控整流电路
- win7怎么重置计算机,处理电脑系统怎么重置呢?教你恢复出厂设置