1、在线词典一般的饿运行过程:例如
— 服务器端将用户信息和历史记录保存在数据库中。客户端输入用户和密码,服务器端在数据库中查找、匹配,返回结果;
— 定义数据库中表的结构;
— 定义消息结构体;
— 分析服务器端和客户端 流程;
— 编码实现;
— 总结: 在做任何的项目之前,都应该首先根据 项目需求 画出 流程图,根据流程图,编程时将更加有目的性;
#include "onlin_dic.h"
#include
#include
#define DATABACK "my.db"
void cli_data_handle(int sockefd,sqlite3* db);
int do_searchword(sqlite3* db,_MSG *msg ,char word[]);//在文件中直接查找dict.txt
int do_register(int newfd , sqlite3* db , _MSG* msg)
{
char *errmsg;
char sql[128];
sprintf(sql,"insert into usr values('%s','%s');",msg->name,msg->data);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
printf("insert faile !!");
strcpy(msg->data,"usr name already exist.");
}else
{
printf("client register ok !\n");
strcpy(msg->data,"ok");
}
if(send(newfd,msg,sizeof(_MSG),0) < 0)
{
printf("faile to faile");
return -1;
}
return 1;
}
int do_history(int newfd , sqlite3* db , _MSG* msg)
{
char sql[128];
char history_word[255]= {0};
int nrow;
int ncloumn;
char** resultp;
char* errmsg;
int index;
int i,j;
int index2;
sprintf(sql,"select * from record where name = '%s';",msg->name);
if(sqlite3_get_table(db,sql,&resultp,&nrow,&ncloumn,&errmsg) != SQLITE_OK )
{
printf("sqlite3_get_table faile !!");
}else printf("sqlite3_get_table ok\n");//根据用户名以及密码,查找返回查找过得相应的记录
index = 0;//列数
for(i = 0;i<=nrow;i++)//行数
{
for(j = 0;j<=ncloumn;j++)
{
index2 = index;
printf("%s ",resultp[index++]);
strcat(history_word,resultp[index2]);
strcat(history_word," ");
}
strcat(history_word,"\r\n");
printf("\n");
}
strcpy(msg->data,history_word);
if(send(newfd,msg,sizeof(_MSG),0) < 0)
{
printf("To %s send faile !!",msg->name);
return -1;
}
printf("%d \n",strlen(msg->data));
return 1;
}
int do_login(int newfd , sqlite3* db , _MSG* msg)
{
char sql[128];
char *errmsg;
int nrow;
int ncloumn;
char** resultp;
int flag = -1;
sprintf(sql,"select * from usr where name = '%s'and pass = '%s';",msg->name,msg->data);
if(sqlite3_get_table(db,sql,&resultp,&nrow,&ncloumn,&errmsg) != SQLITE_OK )
{
printf("%s",errmsg);
return flag;
}else printf("sqlite3_get_table ok");
//查询成功,数据库中拥有此用户
if(nrow == 1)
{
flag = 1;
printf("query ok\n");
strcpy(msg->data,"ok");
}else//查询错误 用户名或密码错误
{
flag = -1;
printf("query faile \n");
strcpy(msg->data,"usr or pass wrong !");
}
if(send(newfd,msg,sizeof(_MSG),0) < 0)
{
printf("faile to send");
return -1;
}
return flag;
}
int do_query(int newfd , sqlite3* db , _MSG* msg)
{
int found;
char word[64];
char sql[128];
char* errmsg;
char timedata[64];
time_t t;
struct tm *tp;
char name[32];
strcpy(name,msg->name);
strcpy(word,msg->data);
printf("Client %s query_word %s \n",msg->name,word);
found = do_searchword(db,msg,word);
if(found == 1)//如果查找成功了,则数据、查找时间,用户等信息存入数据库
{
time(&t);
tp = localtime(&t);
sprintf(timedata,"%d-%02d-%02d %02d:%02d:%02d",tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec);
sprintf(sql,"insert into record values('%s','%s','%s');",name,word,timedata);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) < 0)
{
perror("sqlite3_exec");
strcpy(msg->data,"sqlite3_exec NO found");
}else
{
printf("query success !!!\n");
}
}else
{
strcpy(msg->data,"NO found !\n");//查找失败了
}
if(send(newfd,msg,sizeof(_MSG),0) < 0)
{
printf("send to faile !!!");
return -1;
}
return 1;
}
int do_searchword(sqlite3* db,_MSG *msg ,char word[])//在文件中直接查找dict.txt
{
FILE *fp;
int len = 0;
char buf[512] = {};
int result;
char *p;
if((fp = fopen("dict.txt","r")) ==NULL )
{
perror("fopen");
return -1;
}
//打印出,客户端要查寻的单词
len = strlen(word);
printf("%s len = %d \n",word,len);
//按行读文件,来查询单词
while(fgets(buf,512,fp) != NULL)//从指定的文件一行一行的读出数据
{
result = strncmp(buf,word,len);
if(result == 0 && buf[len] == ':')
{
p = buf + len ;
//找到之后
strcpy(msg->data,p);
fclose(fp);
return 1;
}else
{
continue;
}
}
fclose(fp);
return 0;
}
int main(int argc, const char *argv[])
{
sqlite3 * db;
int sockefd;
struct sockaddr_in sin;
int port = 0;
char * errmsg;
if(argc < 3)
{
printf("Usage : %s ServerIP ServerPort \n",argv[0]);
printf("ServerIP: server ip addr !!!");
printf("ServerPort: server port !!!!");
exit(1);//异常退出
}
/*0 、创建,打开数据库*/
if(sqlite3_open(DATABACK,&db) != SQLITE_OK)
{
printf("%s \n",sqlite3_errmsg(db));
return -1;
}else{
printf("DATABACK db success !!!\n");
}
/*创建表格*/
if(sqlite3_exec(db,"create table usr(name text primary key ,pass text);",NULL,NULL,&errmsg) != SQLITE_OK)
{
printf("usr 已存在\n");
}else
{
printf("create usr success !!\n");
}
if(sqlite3_exec(db,"create table record(name text,word text,time text);",NULL,NULL,&errmsg) != SQLITE_OK)
{
printf("record 已存在\n");
}else
{
printf("create record success !!!\n");
}
port = atoi(argv[2]);
/*1、 socket()创建 文件描述符 */
if((sockefd = socket(AF_INET, SOCK_STREAM , 0)) < 0)
{
perror("socket");
exit(1);
}
#if 0
/*优化:可立即绑定在 任何服务器IP上*/
if( socketopt() < 0)
{
}
#endif
/*2、绑定 */
/*2.1 、 填充 结构体sockaddr_in*/
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
if(inet_pton(AF_INET,argv[1],(void*)&sin.sin_addr) == -1)
{
perror("inet_pton");
printf("Server Starting!!! ip: %s port: %s \n",argv[1],argv[2]);
exit(1);
}
/*2.2 int bind(int sockefd,const struct sockaddr *addr ,socklen_t addrlen) 绑定*/
if(bind(sockefd,(struct sockaddr*)&sin,sizeof(sin)) < 0 )
{
perror("bind");
exit(1);
}
/*3、使用listen(int sockfd , int backlog) 将主动套接字 改为 被动套接字*/
if(listen(sockefd,5) < 0)//将套接字设置为监听模式
{
perror("listen");
exit(1);
}
printf("Server Starting!!! ip: %s port: %s \n",argv[1],argv[2]);
int newfd = -1;
while(1)
{
pid_t pid = -1;
newfd = accept(sockefd ,NULL,NULL);
if(newfd < 0)
{
perror("accept");
exit(1);
}
if((pid = fork()) < 0)
{
perror("fork");
break;
}else if(pid == 0)//子进程
{
close(sockefd);
cli_data_handle(newfd,db);
return 0;
}else //父进程
{
close(newfd);
}
}
close(sockefd);
return 0;
}
void cli_data_handle(int sockefd,sqlite3* db)
{
int newfd = sockefd;
static _MSG msg;
while(recv(newfd,&msg,sizeof(_MSG),0))
{
switch(msg.type)
{
case R:
printf("recv client register(注册) data:%d \n",msg.type);
do_register(newfd,db,&msg);
break;
case L:
printf("recv client login(登录) data:%d \n",msg.type);
if(do_login(newfd ,db,&msg))printf("%s login success\n",msg.data);
break;
case H:
printf("recv client %s history(查询历史记录) data:%d \n",msg.name,msg.type);
do_history(newfd,db,&msg);
break;
case Q:
printf("recv client %s query(查询单词) data:%d \n",msg.name,msg.type);
do_query(newfd,db,&msg);
break;
default:
printf("Invalid data msg. \n");
}
}
close(newfd);
exit(0);
return;
}
#include "onlin_dic.h"
#include
#include
int do_register(int sockfd,_MSG *msg)
{
msg->type = R;
printf("input name (输入注册姓名):");
scanf("%s",msg->name);
getchar();//去除无用字符
printf("input pass(输入登录密码):");
scanf("%s",msg->data);
getchar();
printf("name :%s pass:%s \n",msg->name,msg->data);
//ssize_t send(int sockfd,const void* buf,size_t len , int flags)
if(send(sockfd,msg,sizeof(_MSG),0) < 0)//发送注册信息给服务器
{
printf("faile to send !\n");
return -1;
}
if(recv(sockfd,msg,sizeof(_MSG),0) < 0)
{
printf("Faile to recv !\n");
return -1;
}
return 0;
}
int do_logic(int sockfd , _MSG *msg)
{
msg->type = L;
printf("input name (输入姓名):");
scanf("%s",msg->name);
getchar();//去除无用字符
printf("input pass(输入密码):");
scanf("%s",msg->data);
getchar();
printf("登录信息:name :%s pass:%s \n",msg->name,msg->data);
//ssize_t send(int sockfd,const void* buf,size_t len , int flags)
if(send(sockfd,msg,sizeof(_MSG),0) < 0)//发送注册信息给服务器
{
printf("faile to send !\n");
return -1;
}
if(recv(sockfd,msg,sizeof(_MSG),0) < 0)
{
printf("Faile to recv \n!");
return -1;
}
if(strncmp(msg->data,"ok",sizeof("ok")) == 0)
{
printf("%s login %s \n",msg->name,msg->data);
return 1;
}else
{
printf("%s login %s \n",msg->name,msg->data);
}
printf("接受服务器回复信息:%s \n",msg->data);
return 0;
}
void do_query_word(int sockfd,_MSG *msg)
{
msg->type = Q;
while(1)
{
printf("Input query_word(输入需要查询的单词,**退出) :");
scanf("%s",msg->data);
getchar();
if(strncmp(msg->data,"**",strlen("**")) == 0)
{
break;
}
if(send(sockfd,msg,sizeof(_MSG),0) < 0)
{
perror("send");
continue;
}
if(recv(sockfd,msg,sizeof(_MSG), 0) < 0)
{
perror("recv");
continue;
}
printf("%s",msg->data);
}
return;
}
void do_hostoty_recoyd(int sockfd,_MSG* msg)
{
msg->type = H;
if(send(sockfd,msg,sizeof(_MSG),0) < 0)
{
perror("send");
return;
}
if(recv(sockfd,msg,sizeof(_MSG),0) < 0)
{
perror("recv");
return;
}
printf("hostory_recoyd:\n%s \n",msg->data);
return;
}
int do_next_ui(int sockfd , _MSG *msg)
{
int m;
while(1)
{
printf("*********************************************************************************\n");
printf("/*1:query_word(查询单词) 2:hostory_recoyd(历史记录) 3:quit(返回上级菜单)*/\n");
printf("*********************************************************************************\n");
printf("input(请输入命令) :");
m = 0;
scanf("%d",&m);
if(m<0 && m> 9)continue;
getchar();
switch(m)
{
case 1:
do_query_word(sockfd,msg);
break;
case 2:
do_hostoty_recoyd(sockfd,msg);
break;
case 3:
return 0;
default:
printf("输入有误!!!\n");
}
}
return 0;
}
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in sin;
_MSG msg;
int port;
int n;
if(argc < 3)
{
printf("Usage : %s ServerIP ServerPort \n",argv[0]);
printf("ServerIP : server ip addr \n");
printf("ServerPort: server port (>5000)\n");
exit(0);
}
port = atoi(argv[2]);//字符串 转整数
/*1、socket(int domain , int type , int protocol ) 生成特殊的文件描述符*/
if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1 )
{
perror("socket");
exit(1);//异常退出
}
/*2、填充 sockaddr_in 结构体*/
/*2.1 填充结构体*/
bzero(&sin,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
/*int inet_pton(int af,const char * src , void *dst)*/
if(inet_pton(AF_INET,argv[1],(void*)&sin.sin_addr) == -1)
{
perror("inet_pton");
exit(1);
}
/*3 连接int connect(int sockfd , const struct sockaddr *addr,socklen_t
* addrlen)*/
if(connect(sockfd , (struct sockaddr*)&sin,sizeof(sin)) < 0 )
{
perror("connect");
exit(1);
}
while(1)
{
bzero(&msg,sizeof(_MSG));
printf("**************************************************\n");
printf("/*1:register(注册) 2:login(登录) 3:quit(退出字典)*/\n");
printf("**************************************************\n");
printf("input(请输入命令) :");
n = 0;
bzero(&msg,sizeof(_MSG));
scanf("%d",&n);
switch(n)
{
case 1:
do_register(sockfd,&msg);
break;
case 2:
if(do_logic(sockfd,&msg) == 1)
{
do_next_ui(sockfd,&msg);
}
break;
case 3:
close(sockfd );
exit(0);
default:
printf("input error(输入错误,请重新输入) !!\n");
break;
}
}
close(sockfd);
return 0;
}
#ifndef _ONLIN_DIC_H__
#define _ONLIN_DIC_H__
#include //perror();
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define N 32
#define L 1
#define R 2
#define Q 3
#define H 4
typedef struct {
int type;
char name[N];
char data[255];//password or word
}_MSG;
#endif