思维导图
客户端
#include "head.h"
//用户提示界面
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)
{
//接收数据
//未完全接收的话,可以在接收
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)
{
//接收数据
//未完全接收的话
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;
}
//由于后面要传递参数
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;
}
//数据库中手动创建2个表:user_table,word_table
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;
}