应用综合项目
- 在线英英词典
- 项目功能描述
- 用户注册和登录验证
- 服务器将历史用户信息保存在数据库中,客户端输入用户名和密码,服务器端在数据库中查询,匹配,返回结果。
- 单词在线翻译
- 项目流程
- 定义数据库中表的结构
- 定义消息结果体
- 分析服务器和客户端流程
- 编写代码
client.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#define N 32
#define R 1 //USER-register
#define L 2 //USER-login
#define Q 3 //USER-query
#define H 4 //USER-history
//定义通信双方的信息结构体
typedef struct {
int type;
char name[N];
cahr data[256];
}MSG;
int do_register(int sockfd,MSG *msg)
{
msg->type=R;
printf("input name:");
scanf("%s",msg->name);
getchar();
printf("input passwd:");
scanf("%s",msg->data);
if(send(sockfd,msg,sizeof(MSG),0)<0)
{
printf("fail to send.\n");
return -1;
}
if(recv(sockfd,msg,sizeof(MSG),0)<0)
{
printf("fail to revc.\n");
return -1 ;
}
//ok or user already exist!
printf("%s\n"msg->data);
return 0;
}
int do_login(int sockfd,MSG *msg)
{
msg->type=L;
printf("input name:");
scanf("%s",msg->name);
getchar();
printf("input passwd:");
scanf("%s",msg->data);
if(send(sockfd,msg,sizeof(MSG),0)<0)
{
printf("fail to send\n");
exit(1);
}
if(recv(sockfd,msg,sizeof(MSG),0)<0)
{
printf("fail to recv");
exit(1);
}
if(strncmp(msg->data,"ok",3)==0)
{
printf("login ok\n");
return 1;
}
else
{
printf("%s\n",msg->data);
}
return 0;
}
int do_query(int sockfd,MSG *msg)
{
msg->data=Q;
puts("------------------------");
while(1)
{
printf("input word:");
scanf("%s",msg->data);
getchar();
//客户端输入“#”号,返回到上一级菜单
if(strncmp(msg->data,"#",1)==0)
break;
//将要查询的单词发送给服务器
if(send(sockfd,msg,sizeof(MSG),0)<0)
{
printf("fail to send.\n");
return -1;
}
//接收服务器返回来的单词的注释
if(recv(sockfd,msg,sizeof(MSG),0)<0)
{
printf("fail to recv.\n");
return -1;
}
printf("%s\n",msg->data);
}
}
int do_history(int sockfd,MSG *msg)
{
msg->data='H';
send(sockfd,msg,sizeof(MSG),0);
//接收服务器传回来的历史记录信息
while(1){
recv(sockfd,msg,sizeof(MSG),0);
if(msg->data[0]=='\0')
break;
//输出历史记录信息
printf("%s\n",msg->data);
}
return 0;
}
//./server 192.168.XXX.XXX 端口号
int main(int argc,char *argv[])
{
int sockfd;
struct sockaddr_serveraddr;
MSG msg;
int n;
if(argc!=3)
{
printf("usage :%s serverip port.\n",argv[0]);
return -1;
}
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("fail to socket.\n");
return -1;
}
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_add.s_addr=inet_addr(argc[1]);
serveraddr.sin_port=htons(argv[2]);
if(connect(sockfd,struct sockaddr*)*serveraddr,sizeof(serveraddr))<0)
{
perror(" fail to connect");
return -1;
}
while(1)
{
printf("****************************************\n");
printf(" *1,register 2,login 3,quit *\n");
printf("*****************************************\n");
printf("please choose:");
printf("%d",&n);
getchar();
switch(n)
{
case 1:
do_register(sockfd,&msg);
break;
case 2:
if(do_login(sockfd,&msg)==1)
{
goto next;
}
break;
case 3:
close(sockfd);
exit(0);
break;
default:
printf("Invaild data cmd.\n");
}
}
next:
while(1)
{
printf("**************************************\n");
printf("1,query_word 2.history_record 3,quit *\n");
printf("***************************************\n");
printf("please choose:");
scanf("&d",&n);
getchar();
switch(n)
{
case 1:
do_query(sockfd,&msg);
break;
case 2:
do_history(sockfd,&msg);
break;
case 3:
close(sockfd);
break;
}
}
return 0;
}
server.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include<unistd.h>
#include<sqlite3.h>
#include<signal.h>
#include<time.h>
#define N 32
#define R 1 //USER-register
#define L 2 //USER-login
#define Q 3 //USER-query
#define H 4 //USER-history
#define DATABAE "my.db"
//定义通信双方的信息结构体
typedef struct {
int type;
char name[N];
cahr data[256];
}MSG;
int do_client(int acceptfd,sqlite3 *db);
void do_register(int acceptfd,MSG *msg,sqlite3 *db);
int do_login(int acceptfd,MSG *msg,sqlite3 *db);
int do_query(int acceptfd,MSG *msg,sqlite3* db);
int do_history(int acceptfd,MSG *msg,sqlite3 *db);
int do_searchword(int acceptfd,MSG *msg,char word[]);
int history_callback(void *arg,int f_num,char ** f_value,char**f_name);
int get_date(char *date);
//./server 192.168.XXX.XXX 端口号
int main(int argc,char *argv[])
{
int sockfd;
struct sockaddr_serveraddr;
MSG msg;
int n;
sqlite3 *db;
int acceptfd;
pid_t pid;
if(argc!=3)
{
printf("usage :%s serverip port.\n",argv[0]);
return -1;
}
//打开数据库
if(sqlite3_open(DATABASE,&db)!=SQLITE_OK)
{
printf("%s\n",sqlite3_errmsg(db));
return -1;
}
else
{
printf("open DATABASE succeff.\n");
}
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("fail to socket.\n");
return -1;
}
bzero(&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_add.s_addr=inet_addr(argc[1]);
serveraddr.sin_port=htons(argv[2]);
if(bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0)
{
perror("fail to bind\n");
return -1;
}
//将套接字设为监听模式
if(listen(sockfd,5)<0)
{
printf("fail to listen.\n);
return -1;
}
signal(SIGCHLD,SIG_IGN); //处理僵尸进程
while(1)
{
if((acceptfd=accept(sockfd,NULL,NULL))<0)
{
perror("fail to accept");
reutrn -1;
}
if(pid=fork()<0)
{
perror("fail to fork");
return -1;
}
else if(pid==0) //儿子进程
{
//处理客户端具体的信息
close(sockfd);
do_client();
}
else //父进程,用来接收客户端的请求
{
close(acceptfd);
}
}
return 0;
}
int do_client(int acceptfd,sqlite3 *db)
{
MSG msg;
while(recv(acceptfd,&msg,sizeof(msg),0)>0)
{
printf("type:%d\n",,msg.type);
switch(msg.type)
{
case R:
do_regitster(acceptfd,&msg,db);
break;
case L:
do_login(acceptfd,&msg,db);
break;
case Q:
do_query(acceptfd,&msg,db);
break;
case H:
do_history(acceptfd,&msg,db);
break;
default:
printf("invalid data msg.\n");
}
}
printf("client exit.\n");
close(acceptfd);
exit(0);
return 0;
}
void do_register(int acceptfd,MSG *msg,sqlite3 *db)
{
char *errmsg;
char sql[128];
sprintf(sql,"insert into usr values('%s','%s');",msg->name,msg->data);
printf("%s\n".sql);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
printf("%s\n",errmsg);
strcpy(msg->data,"usr name already exist.");
}
else
{
printf("client register ok\n");
strcpy(msg->data,"ok");
}
if(send(acceptfd,msg,sizeof(MSG),0)<0)
{
printf("fail to send");
return -1;
}
}
int login(int acceptfd,MSG *msg,sqlite3 *db)
{
char *errmsg;
char sql[128]={};
int nrow;
int ncloumn;
char ** resultp;
sprintf(sql,"select *from usr where name='%s'and pass='%s';",msg->name,msg->data);
printf("%s\n",sql);
if(sqlite3_get_table(db,sql,&resultp,&nrow,&nclonum,&errmsg)!=SQLITE_OK)
{
printf("%s\n",errmsg);
return -1;
}
else
{
printf("get_table ok!\n");
}
//查询成功数据库中有此用户
if(nrow=1)
{
strcpy(msg->data,"ok);
send(acceptfd,msg,sizeof(MSG),0)
}
else if(nrow=0)
{
strcpy(msg->data,"usr/passwd wrong");
send(acceptfd,msg,sizeof(MSG),0);
return 1;
}
return 0;
}
int do_searchword(int acceptfd,MSG *msg,char word[])
{
FILE *fp;
char temp[512]={};
int result;
char *p;
//打开文件,读取文件,进行比对
if((fp=fopen("dict.txt","r"))==NULL)
{
perror("fail to fopen\n");
strcpy(msg->data,"failed to open dict.txt");
send(acceptfd,msg,sizeof(MSG),0);
return -1;
}
//打印出客户端要查询的单词
len=strlen(word);
printf("%s,len=%d\n",word,len);
//读文件,查询单词
while(fgets(temp,512,fp)!=NULL)
{
result=strncmp(temp,word,len);
if(result>0)
continue;
if(result<0||temp[len]!='')
break;
//表示找到了查询的单词
p=temp+len;
while(*p==' ')
{
p++;
}
//找到了注释,跳跃过所有的空格
strcpy(msg->data,p);
//注释拷贝完后,应该关闭文件
fclose(fp);
return 1;
}
}
int get_date(char *date)
{
time_t t;
struct tm *tp;
time(&t);
//进行时间格式转化
localtime(&t);
sprintf(date,"%d:%d:%d:%d:%d:%d",tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec);
}
int do_query(int acceptfd,MSG *msg,sqlite3 *db)
{
char word[64];
int found=0;
char date[128];
char sql[128];
char *errmsg;
//拿出msg结构体中要查询的单词
strcpy(word,msg->data);
found=do_searchword(acceptfd,msg,word);
if(found==1)//表明查到了,此时应该将用户,事件,单词,插入到历史纪录表中
{
//获取系统时间
get_date(date);
sprintf(sql,"insert into record value('%s','%s','%s');",msg->name,date,word);
printf("%s\n",sql);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
{
printf("%s\n",errmsg);
return -1;
}
}
else//表明没有找到
{
strcpy(msg->data,"not found!");
}
//将查询的结果发送给客户端
send(acceptfd,msg,sizeof(MSG),0);
return 0;
}
//得到查询结果并且需要将历史记录发送给客户端
int history_callback(void *arg,int f_num,char ** f_value,char**f_name)
{
//record:name,date,word
int acceptfd;
MSG msg;
aceptfd=*((int )arg);
sprintf(msg.data,"%s,%s",f_value[1],f_value[2]);
send(acceptfd,&msg,sizeof(MSG),0);
return 0;
}
int do_history(int acceptfd,MSG *msg,sqlite3 *db)
{
char sql[128]={};
sprintf(sql,"select *from record where name='%s';",msg->name);
//查询数据库
if(sqlite3_exec(db,sql,history_callback,(void *)&acceptfd,&errmsg)!=SQLITE_OK)
{
printf("%s\n",errmsg);
}
else
{
printf("query record done\n");
}
//所有的历史信息查询完毕后,给客户端发送结束信息
msg->data[0]='\0';
send(acceptfd,msg,sizeof(MSG),0);
return 0;
}
编译客户端和服务器端程序时,引入sqlite3 库
gcc server.c -o server -lsqlite3
创建数据库:sqlite3 my.db
创建两个表:create table usr (name text ,pass text);
create table record(name text,date char ,word text );