TCP协议和sqlite3数据库的网络电子词典个人项目
一、开发环境:Ubuntu 16.04
二、项目描述:
基于TCP协议的并发服务器设计,采用sql数据库进行数据存储,文件保存历史查询数据,能满足多用户同时登陆,实现用户的注册、登录以及退出,登录成功后即可使用单词查询和查询历史记录功能。
三、代码实现思路:
- 使用sqlite3数据库,创建用户信息表和单词表。
- 服务器采用基于TCP协议的多进程技术,可以满足多用户同时登录。
- 服务器接收客户端的注册请求,将用户名和密码存入数据库的注册表中。
- 服务器接收客户端的登录请求,将登录信息与注册表中的信息进行比对,反馈对比信息。
- 客户端登录成功后,开启查询单词和历史记录功能。
- 服务器接收客户端的查询单词后,对比数据库中的单词表,反馈给客户端相应的信息。并用文件IO接收从服务器发来的单词及其释义。
- 若客服端发送查询历史记录请求后,打开历史记录文件描述符,打印出该用户查询过的所有历史记录。
四、运用技术点:
- 采用文件IO对历史数据进行读写操作。
- 采用TCP协议的并发服务器设计。
- SQLite3数据库。
五、背景
任何一种词语,使用频率高了,就会成为公共词汇。英语作为一种国际通用
性语言,部分单词已成为公共词汇,并且直接应用到汉语中来。因其表达简洁,
准确而受到人们青睐。但是,这些新引入或者比较专业词汇,对于较少关注新闻,
接触网络的群体而言,就会造成阅读困难。传统的纸质英汉词典因为更新周期久,
携带不便,价格相对昂贵而不能广泛应用。方便,高效,快捷的电子词典才能满
足现代人的需要。
参考资料
名称 |
作者 |
出版社 |
Unix网络编程 |
||
TCP/IP协议详解 |
||
Unix高级环境编程 |
六、系统概述
我们的这套系统采用的是tcp协议的并发服务器设计,可以满足多用户同时登录,用户登录后可以查询单词及历史记录,对于数据的存储我们采用的是sql数据库技术,查找快速,保密性好!
>具体功能能如下:
<1>主界面
(1) 用户登录
(2) 用户注册
(3) 用户退出
<2>登陆成功后界面
(1) 查询单词
(2) 查询历史记录
(3) 用户退出
<3>详细设计
消息类型设计
宏名设计 |
说明 |
USER_REGISTER |
用户注册 |
USER_LOGIN |
用户登陆 |
USER_WORD |
用户查询单词 |
USER_SUCCESS |
登陆成功 |
USER_FALIURE |
登陆失败 |
4.2结构体的设计
注:__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._passwd
}__attribute__((__packed__))mhead_t;
#define EXEC_SQL(db,sql,errmsg) do{\
if(sqlite3_exec(db,sql,NULL,NULL,&merrmsg) < 0)\
{\
fprintf(stderr,“sqlite exec [%s]error : %s\n”,sql,errmsg);\
exit(EXIT_FAILURE);
}\
}while(0);
七、服务器
-
-
-
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)
-
{
-
int i,j,index = 0,ret;
-
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));
-
EXEC_SQL(pdb,sql,errmsg);
-
printf("ok........\n");
-
for(i = 0;i <= nrow;i )
-
{
-
for(j = 0;j < ncolumn;j )
-
{
-
if(strcmp(dbresult[index],_password) == 0)
-
{
-
head->type = USER_SUCCESS;
-
if(send(sockfd,buf,sizeof(mhead_t),0) < 0)
-
{
-
perror("Fail to send");
-
exit(EXIT_FAILURE);
-
}
-
i = nrow 1;
-
break;
-
}
-
index ;
-
}
-
}
-
}else if(nrow == 0)
-
{
-
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 get_data()
-
{
-
time_t t;
-
time(&t);//获得从1970年1月1日开始到现在有多少秒
-
printf("current time:%s\n",ctime(&t));//获得当前的时间
-
return 0;
-
}
-
-
int do_query(int sockfd,sqlite3 *pdb,char *_word)
-
{
-
int ret;
-
char *errmsg;
-
char buf[1024] = {0};
-
char **dbresult;
-
char sql[1024] = {0};
-
int nrow = 0,ncolumn = 0;
-
mhead_t *head = (mhead_t *)buf;
-
int i = 0,j = 0,index = 0;
-
-
sprintf(sql,"select * from dict_table where word = '%s';",_word);
-
printf("%s\n",_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 > 0)
-
{
-
printf("ok........\n");
-
for(i = 0;i <= nrow;i )
-
{
-
for(j = 0;j < ncolumn;j )
-
{
-
if(strcmp(dbresult[index],_word) == 0)
-
{
-
puts(dbresult[index 1]);
-
sprintf(head->word,"%s:%s\n",_word,dbresult[index 1]);
-
i=nrow 1;
-
break;
-
}
-
index ;
-
}
-
}
-
head->type = USER_SUCCESS;
-
printf("%s\n",head->word);
-
if(send(sockfd,buf,sizeof(mhead_t),0) < 0)
-
{
-
perror("Fail to send");
-
exit(EXIT_FAILURE);
-
}
-
-
}
-
else if(nrow == 0)
-
{
-
head->type = USER_FAILURE;
-
if(send(sockfd,buf,sizeof(mhead_t),0) < 0)
-
{
-
perror("Fail to send");
-
exit(EXIT_FAILURE);
-
}
-
else
-
//表示未知
-
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 : %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:
-
do_query(sockfd,pdb,head->word);
-
break;
-
defalut:
-
exit(EXIT_SUCCESS);
-
}
-
}
-
-
return 0;
-
}
八、客户端
-
-
//用户提示界面1
-
void help_info1()
-
{
-
printf("\t-----------------------------------------------\n");
-
printf("\t| 在线辞典 |\n");
-
printf("\t|版本:0.0.1 |\n");
-
printf("\t|作者:XXX |\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|作者:XXX |\n");
-
printf("\t|功能: |\n");
-
printf("\t| [1] 查询单词 |\n");
-
printf("\t| [2] 查询历史 |\n");
-
printf("\t| [3] 退出 |\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{ sprintf(buf,"%s\n",head->word);
-
write(fd,buf,strlen(buf));
-
-
printf("\n很遗憾,这个用户名已经被其它用户注册过了,请重新注册");
-
return -1;
-
}
-
}
-
-
int do_query(int sockfd)
-
{
-
time_t t;
-
time(&t);//获得从1970年1月1日开始到现在有多少秒
-
-
int fd;
-
int n = 0,count = 0;
-
char buf[1024] = {0};
-
char time[1024] = {0};
-
mhead_t *head = (mhead_t *)buf;
-
head->type = USER_WORD;
-
head->size = sizeof(mhead_t);
-
-
fd = open("history.txt",O_RDWR | O_CREAT | O_APPEND,0666);
-
printf("\n您正在查询单词!\n");
-
printf("请输入你想要查询的单词:");
-
fgets(head->word,sizeof(head->word),stdin);
-
head->word[strlen(head->word) - 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("%s\n",head->word);
-
sprintf(time,"current time:%s\n%s\n",ctime(&t),head->word);//获得当前时间
-
write(fd,time,strlen(time));
-
printf("%s\n",time);
-
return 0;
-
}
-
else
-
{
-
printf("\nno such word!\n");
-
}
-
close(fd);
-
return 0;
-
}
-
-
-
int do_history(int sockfd)
-
{
-
int n = 0;
-
char buf[1024] = {0};
-
int fd;
-
fd = open("history.txt",O_RDONLY);
-
while(1)
-
{
-
memset(buf,0,sizeof(buf));
-
n = read(fd,buf,sizeof(buf));
-
if(0 == n)
-
break;
-
printf("%s",buf);
-
}
-
close(fd);
-
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");
-
return 0;
-
}else{
-
printf("\n登陆用户信息错误,请重试!\n");
-
return -1;
-
}
-
}
-
int do_task(int sockfd)
-
{
-
int cmd;
-
while(1)
-
{
-
//提示界面帮助,用户选择
-
help_info1();
-
-
printf("\n\n请选择>");
-
scanf("%d",&cmd);
-
//吃掉回车键
-
getchar();
-
switch(cmd)
-
{
-
//用户登陆
-
case LOGIN:
-
if(do_login(sockfd) < 0)
-
continue;
-
do_task2(sockfd);
-
break;
-
//用户注册,我们先来写注册的函数
-
case REGISTER:
-
if(do_register(sockfd) < 0)
-
continue;
-
do_task2(sockfd);
-
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;
-
}
九、运行结果
1、先运行服务器
2、再运行客户端
3、登陆
4、 查询单词
5、查询历史记录
6、退出
7、注册
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfkijge
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24