项目要求:
1.登录注册功能,不能重复登录,重复注册
2.单词查询功能
3.历史记录功能,存储单词,意思,以及查询时间
4.基于 TCP ,支持多客户端连接
5.采用数据库保存用户信息与历史记录
6.将 dict . txt 的数据导入到到数据库中保存。
7.按下 ctrl + c 退出客户端后,注销该客户端的登录信息
格式要求:
1, main 函数只跑逻辑,不允许胞功能能代码
2,功能代码封装成函数
流程图
代码
//头文件
#ifndef __INET_H__
#define __INET_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netinet/in.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <sqlite3.h>
#include <time.h>
#define ERR(msg) do{\
fprintf(stderr,"%d--",__LINE__);\
perror(msg);\
}while(0)
#endif
//服务器
#include "inet.h"
#define SER_IP "192.168.8.205"
#define SER_PORT 7777
#define N 128
struct data_type
{
int nfd;
struct sockaddr_in cin;
};
//服务器初始化
int ser_init();
//登录功能,并记录下正在登录中的用户
int login(int nfd,char *buf,char *name);
//退出是删除登录的用户
int del_temp_usr(char *name);
//注册功能
int sign_up(int nfd,char *buf);
//查找单词,并记录下查询结果
int find_word(int nfd,char *buf,char *name);
//查看该name的历史记录
int history(int nfd,char *name);
void *task(void *arg)
{
int nfd=((struct data_type*)arg)->nfd;
struct sockaddr_in cin=((struct data_type*)arg)->cin;
//接收客户端登录信息,判断是否是已注册用户
//回复相应信息给客户端
char buf[N]="";
char name[10]="";
while(1)
{
bzero(buf,N);
ssize_t res_rcv=recv(nfd,buf,N,0);
if(res_rcv<0)
{
ERR("recv");
return NULL;
}
else if(res_rcv==0)
{
printf("%d号客户端退出\n",nfd);
//退出后删除此用户的登录信息
del_temp_usr(name);
pthread_exit(NULL);
}
switch(buf[0])
{
case '1':
//如果登录功能函数返回值为1则登陆成功
if(login(nfd,buf,name)==1)
{
while(1)
{
bzero(buf,N);
res_rcv=recv(nfd,buf,N,0);
if(res_rcv<0)
{
ERR("recv");
return NULL;
}
else if(res_rcv==0)
{
printf("%d号客户端退出\n",nfd);
//退出后删除此用户的登录信息
del_temp_usr(name);
pthread_exit(NULL);
}
switch(buf[0])
{
case '1':find_word(nfd,buf,name);break;
case '2':history(nfd,name);break;
case '3':goto END;
default:break;
}
}
}
break;
case '2':sign_up(nfd,buf);break;
case '3':goto END;
default:break;
}
}
END:
close(nfd);
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
int sfd=ser_init();
printf("服务器就绪\n");
struct sockaddr_in cin;
socklen_t addr=sizeof(cin);
while(1)
{
int nfd=accept(sfd,(struct sockaddr*)&cin,&addr);
if(nfd<0)
{
ERR("accept");
return -1;
}
printf("%d号客户端连接成功\n[%s:%d]\n",nfd,\
inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
struct data_type info={nfd,cin};
pthread_t tid;
if(pthread_create(&tid,NULL,task,(void *)&info)<0)
{
ERR("pthread_create");
return -1;
}
pthread_detach(tid);
}
close(sfd);
return 0;
}
int ser_init()
{
//创建套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR("socket");
return -1;
}
//设置端口允许重用
int a=1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&a,sizeof(a))<0)
{
ERR("setsockopt");
return -1;
}
//绑定服务器IP和端口
struct sockaddr_in sin={AF_INET,htons(SER_PORT),inet_addr(SER_IP)};
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR("bind");
return -1;
}
//设置为被动监听状态
if(listen(sfd,10)<0)
{
ERR("listen");
return -1;
}
return sfd;
}
int login(int nfd,char *buf,char *name)
{
char passwd[10]="";
char *p=buf+1;
int count=0;
int i=0;
//获取输入的账户和密码
while(*p)
{
if(*p==' ')
{
strcpy(passwd,p+1);
break;
}
name[i++]=*p++;
}
//打开数据库
sqlite3 *db=NULL;
if(sqlite3_open("./wang.db",&db)!=SQLITE_OK)
{
printf("%d--sqlite3_open:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
char *msg=NULL;
//创建一个表记录正在登陆中的用户
char sql[N]="create table if not exists temp_usr (name char);";
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
char **temp_pres=NULL;
int temp_row=0;
int temp_col=0;
//打开存储已注册的用户信息的表
strcpy(sql,"create table if not exists usr (name char primary key,passwd char);");
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
char **pres=NULL;
int row=0;
int col=0;
int flag=0;
strcpy(sql,"select * from usr");
if(sqlite3_get_table(db,sql,&pres,&row,&col,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
//只遍历用户表里的name信息
for(int i=0;i<((row+1)*col)/2;i++)
{
//先判断输入的name是否是注册过的
if(strcmp(name,pres[2*i])==0)
{
flag=1;
bzero(buf,N);
//再判断输入的密码是否正确
if(strcmp(passwd,pres[2*i+1])==0)
{
//然后遍历记录临时登录的用户信息表
//判断是否是正在登录的用户
strcpy(sql,"select * from temp_usr");
if(sqlite3_get_table(db,sql,&temp_pres,&temp_row,&temp_col,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
for(int j=1;j<((temp_row+1)*temp_col);j++)
{
if(strcmp(temp_pres[j],name)==0)
{
strcpy(buf,"account logined in");
if(send(nfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
return -1;
}
}
//如果不是正在登陆中的用户则把该用户记录到临时用户表中
bzero(sql,N);
sprintf(sql,"insert into temp_usr values ('%s');",name);
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
//如果不是正在登陆中的用户,则登陆成功
strcpy(buf,"login success");
if(send(nfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
return 1;
}
else
{
//密码错误,登录失败
strcpy(buf,"passwd error");
if(send(nfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
break;
}
}
}
if(flag==0)
{
bzero(buf,N);
//不是已注册用户
strcpy(buf,"account not exist");
if(send(nfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
}
sqlite3_free_table(pres);
sqlite3_free_table(temp_pres);
if(sqlite3_close(db)<0)
{
printf("%d--sqlite3_close:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
return 0;
}
int del_temp_usr(char *name)
{
sqlite3 *db=NULL;
if(sqlite3_open("./wang.db",&db)!=SQLITE_OK)
{
printf("%d--sqlite3_open:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
char *msg=NULL;
char sql[N]="create table if not exists temp_usr (name char);";
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
bzero(sql,N);
sprintf(sql,"delete from temp_usr where name='%s';",name);
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
if(sqlite3_close(db)<0)
{
printf("%d--sqlite3_close:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
return 0;
}
int sign_up(int nfd,char *buf)
{
char name[10]="";
char passwd[10]="";
char *p=buf+1;
int i=0;
//获取输入的账户和密码
while(*p)
{
if(*p==' ')
{
strcpy(passwd,p+1);
break;
}
name[i++]=*p++;
}
//打开数据库
sqlite3 *db=NULL;
if(sqlite3_open("./wang.db",&db)!=SQLITE_OK)
{
printf("%d--sqlite3_open:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
char *msg=NULL;
char sql[N]="create table if not exists usr (name char primary key,passwd char);";
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
char **pres=NULL;
int row=0;
int col=0;
int flag=0;
bzero(sql,N);
strcpy(sql,"select * from usr");
if(sqlite3_get_table(db,sql,&pres,&row,&col,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
//只遍历用户表里的name信息
for(int i=0;i<((row+1)*col)/2;i++)
{
//如果已存在则不注册
if(strcmp(name,pres[2*i])==0)
{
bzero(buf,N);
strcpy(buf,"account already exists");
if(send(nfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
return -1;
}
}
bzero(sql,N);
//注册用户信息
sprintf(sql,"insert into usr values ('%s','%s');",name,passwd);
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
bzero(buf,N);
strcpy(buf,"sign up success");
if(send(nfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
sqlite3_free_table(pres);
if(sqlite3_close(db)<0)
{
printf("%d--sqlite3_close:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
return 0;
}
int find_word(int nfd,char *buf,char *name)
{
//打开数据库
sqlite3 *db=NULL;
if(sqlite3_open("./wang.db",&db)!=SQLITE_OK)
{
printf("%d--sqlite3_open:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
char *msg=NULL;
char sql[N]="create table if not exists dict (word char,meaning char);";
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
//查询词典表
char **pres=NULL;
int row=0;
int col=0;
int flag=0;
bzero(sql,N);
sprintf(sql,"select * from dict where word='%s';",buf+1);
if(sqlite3_get_table(db,sql,&pres,&row,&col,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
char err_word[N]="";
strcpy(err_word,buf+1);
bzero(buf,N);
//单词输入错误
if(row==0)
{
sprintf(buf,"[%s]\tword not exist\n",err_word);
}
//将查找到的单词及意思存储到buf中
else
{
int k=col;
for(int i=1;i<row+1;i++)
{
for(int j=0;j<col;j++)
{
strcat(buf,pres[k++]);
strcat(buf," ");
}
strcat(buf,"\n");
}
}
//发给用户查询结果
if(send(nfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
//创建一个表记录该用户的查询记录
strcpy(sql,"create table if not exists history (name char,result char,time char);");
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
//记录查询时间
time_t t;
t=time(NULL);
char find_time[N]="";
struct tm *tm=localtime(&t);
sprintf(find_time,"%d-%02d-%02d %02d:%02d:%02d",tm->tm_year+1900,\
tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec);
//将用户名、查询结果、查询时间写入表中
char buf1[N]="";
char buf2[N]="";
char *p=buf;
int i=0;
while(*p)
{
buf1[i++]=*p++;
if(*p=='\n')
{
bzero(sql,N);
sprintf(sql,"insert into history values ('%s','%s','%s')",name,buf1,find_time);
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
if(*(p+1))
{
strcpy(buf2,p+1);
buf2[strlen(buf2)-1]=0;
bzero(sql,N);
sprintf(sql,"insert into history values ('%s','%s','%s')",name,buf2,find_time);
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
}
break;
}
}
sqlite3_free_table(pres);
if(sqlite3_close(db)<0)
{
printf("%d--sqlite3_close:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
return 0;
}
int history(int nfd,char *name)
{
//打开数据库
sqlite3 *db=NULL;
if(sqlite3_open("./wang.db",&db)!=SQLITE_OK)
{
printf("%d--sqlite3_open:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
char *msg=NULL;
char sql[N]="create table if not exists history (name char,result char,time char);";
if(sqlite3_exec(db,sql,NULL,NULL,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
char **pres=NULL;
int row=0;
int col=0;
bzero(sql,N);
//遍历该用户的历史记录
sprintf(sql,"select * from history where name='%s';",name);
if(sqlite3_get_table(db,sql,&pres,&row,&col,&msg)!=SQLITE_OK)
{
printf("%d--sqlite3_exec:%s\n",__LINE__,msg);
return -1;
}
char buf[1024]="";
int k=col;
for(int i=1;i<row+1;i++)
{
for(int j=0;j<col;j++)
{
strcat(buf,pres[k++]);
strcat(buf," ");
}
strcat(buf,"\n");
}
if(send(nfd,buf,1024,0)<0)
{
ERR("send");
return -1;
}
sqlite3_free_table(pres);
if(sqlite3_close(db)<0)
{
printf("%d--sqlite3_close:%s\n",__LINE__,sqlite3_errmsg(db));
return -1;
}
return 0;
}
//客户端
#include "inet.h"
#define SER_IP "192.168.8.205"
#define SER_PORT 7777
#define N 128
//客户端初始化
int cli_init();
//登录功能
int login(int sfd,char *msg);
//注册功能
int sign_up(int sfd,char *msg);
//查单词功能
int find_word(int sfd,char *msg);
//查历史记录功能
int history(int sfd,char *msg);
int main(int argc, const char *argv[])
{
int sfd=cli_init();
printf("服务器连接成功\n");
struct sockaddr_in cin;
socklen_t addr=sizeof(cin);
char msg[N]="";
char h_msg[1024]="";
while(1)
{
printf("1---登录\n");
printf("2---注册\n");
printf("3---退出\n");
printf("请输入:");
char ch=getchar();
while(getchar()!=10);
switch(ch)
{
case '1':
login(sfd,msg);
printf("%s\n",msg);
//判断接收到的信息是否是登录成功
if(strcmp(msg,"login success")==0)
{
while(1)
{
printf("1---查单词\n");
printf("2---查历史记录\n");
printf("3---退出\n");
printf("请输入:");
ch=getchar();
while(getchar()!=10);
switch(ch)
{
case '1':
find_word(sfd,msg);
printf("%s",msg);
break;
case '2':
history(sfd,h_msg);
printf("%s",h_msg);
break;
case '3':goto END;
default:printf("输入错误\n");
}
printf("输入任意字符清屏:");
while(getchar()!=10);
system("clear");
}
}
break;
case '2':
sign_up(sfd,msg);
printf("%s\n",msg);
break;
case '3':goto END;
default:printf("输入错误\n");
}
printf("输入任意字符清屏:");
while(getchar()!=10);
system("clear");
}
END:
close(sfd);
return 0;
}
int cli_init()
{
//创建套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
ERR("socket");
return -1;
}
//设置端口允许重用
int a=1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&a,sizeof(a))<0)
{
ERR("setsockopt");
return -1;
}
//获取服务器IP和端口
struct sockaddr_in sin={AF_INET,htons(SER_PORT),inet_addr(SER_IP)};
//连接服务器
if(connect(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR("connect");
return -1;
}
return sfd;
}
int login(int sfd,char *msg)
{
char buf[N]="";
buf[0]='1';
char name[10]="";
char passwd[10]="";
printf("请输入账户:");
scanf("%s",name);
while(getchar()!=10);
printf("请输入密码:");
scanf("%s",passwd);
while(getchar()!=10);
sprintf(buf+1,"%s %s",name,passwd);
if(send(sfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
bzero(msg,N);
if(recv(sfd,msg,N,0)<0)
{
ERR("recv");
return -1;
}
return 0;
}
int sign_up(int sfd,char *msg)
{
char buf[N]="";
buf[0]='2';
char name[10]="";
char passwd[10]="";
printf("请输入账户:");
scanf("%s",name);
while(getchar()!=10);
printf("请输入密码:");
scanf("%s",passwd);
while(getchar()!=10);
sprintf(buf+1,"%s %s",name,passwd);
if(send(sfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
bzero(msg,N);
if(recv(sfd,msg,N,0)<0)
{
ERR("recv");
return -1;
}
return 0;
}
int find_word(int sfd,char *msg)
{
char buf[N]="";
buf[0]='1';
char word[20]="";
printf("请输入要查找的单词:");
fgets(buf+1,N,stdin);
buf[strlen(buf)-1]=0;
if(send(sfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
bzero(msg,N);
if(recv(sfd,msg,N,0)<0)
{
ERR("recv");
return -1;
}
return 0;
}
int history(int sfd,char *h_msg)
{
char buf[N]="";
buf[0]='2';
if(send(sfd,buf,N,0)<0)
{
ERR("send");
return -1;
}
bzero(h_msg,1024);
if(recv(sfd,h_msg,1024,0)<0)
{
ERR("recv");
return -1;
}
return 0;
}