common.h
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#define N 32
typedef struct {
int type;
char name[N];
char data[256];
int option;
int flag;
}MSG;
#define R 1 // user - register
#define L 2 // user - login
#define Q 3 // user - query
#define H 4 // user - history
#define DATABASE "my.db" //创建的数据库
#define SERADDR "127.0.0.1"
#define SERPORT 5001
#endif
服务器
#include "common.h"
void init_sql(sqlite3 *db);
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 get_data(char *date);//获取时间
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in serveraddr;
int acceptfd;
sqlite3 *db;
pid_t pid;
if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
{
printf("%s\n", sqlite3_errmsg(db));
return -1;
}
else
{
printf("open DATABASE success.\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_addr.s_addr = inet_addr(SERADDR);
serveraddr.sin_port = htons(SERPORT);
int reuse = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("setsockopt");
return -1;
}
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); //处理僵尸进程
if (sqlite3_open("./my.db", &db) != SQLITE_OK)
{
fprintf(stderr, "line:%d sqlite_open:%s\n", __LINE__, sqlite3_errmsg(db));
return -1;
}
init_sql(db);
struct sockaddr_in cin;
socklen_t cin_len = sizeof(cin);
while(1)
{
if((acceptfd = accept(sockfd, NULL, NULL)) < 0)
{
perror("fail to accept");
return -1;
}
printf("[%s:%d]连接到服务器..\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
if((pid = fork()) < 0)
{
perror("fail to fork");
return -1;
}
else if(pid == 0)
{//son process
close(sockfd);
do_client(acceptfd, db);
}
else
{//father process
close(acceptfd);
}
}
return 0;
}
int do_client(int acceptfd, sqlite3 *db)
{
MSG msg;
while(recv(acceptfd, &msg, sizeof(msg), 0) > 0)
{
switch(msg.option)
{
case R:
do_register(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 init_sql(sqlite3 *db)
{
printf("正在初始化...\n");
//创建表
char sql[256] = "";
char *errmsg = NULL;
strcpy(sql, "create table if not exists usr (name char PRIMARY KEY,passwd char,status char);");
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec error:%s\n", errmsg);
return;
}
strcpy(sql, "create table if not exists log (name char,word char,explain char,time char);");
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec error:%s\n", errmsg);
return;
}
strcpy(sql, "create table if not exists dict (Word char,Explain char);");
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec error:%s\n", errmsg);
return;
}
//判断词库存不存在
char **result = NULL;
int rows = 1;
int columns = 0;
// char sql[128] = "select * from stu";
strcpy(sql, "select * from dict");
if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
{
printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
return;
}
sqlite3_free_table(result);
if (rows < 7987)
{
printf("正在导入词库...\n");
FILE *fp = fopen("./dict.txt", "r");
if (NULL == fp)
{
perror("fopen");
return;
}
char buff[300];
char Word[64];
char Explain[256];
char *p = NULL;
while (NULL != fgets(buff, sizeof(buff), fp))
{
p = buff;
while (1)
{
if (*p != ' ' || (*p == ' ' && *(p + 1) != ' '))
p++;
else
break;
}
*p = '\0';
p++;
//获取单词
strcpy(Word, buff);
//跳过空格
while (*p == ' ')
{
p++;
}
//截取解释
strcpy(Explain, p);
sprintf(sql, "insert into dict values(\"%s\",\"%s\")", Word, Explain);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
return;
}
}
}
printf("单词库导入成功\n");
}
void do_register(int acceptfd, MSG *msg, sqlite3 *db)//注册用户实现
{
char sql[512] = {0};
char *errmsg;
sprintf(sql, "insert into usr values(\"%s\",\"%s\",'no');", msg->name, msg->data);
// name为主键,插入失败则用户名已经存在
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
// printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
sprintf(msg->data, "用户名 %s 已存在!!", msg->name);
}
else
{ printf("注册了一个新用户为: %s\n",msg->name);
strcpy(msg->data, "注册成功!!");
}
send(acceptfd, msg, sizeof(MSG), 0);
return;
}
int do_login(int acceptfd, MSG *msg, sqlite3 *db)//用户登录实现
{
char sql[512] = {0};
char *errmsg, **result;
int rows, columns;
//通过sqlite3_get_table函数查询记录是否存在
sprintf(sql, "select * from usr where name = '%s' and passwd = '%s'", msg->name, msg->data);
if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
{
printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
}
//通过row参数判断是否能够查询到疾记录,如果值为0,则查询不到,如果值为非0,则查询到
if (rows == 0)
{
strcpy(msg->data, "用户名或密码错误");
msg->flag = 0; //失败
}
else
{
if (strcmp("no", result[5]) == 0)
{
strcpy(msg->data, "登录成功");
sprintf(sql, "update usr set status = 'yes' where name = '%s'", msg->name); //登录之后状态设置为yes;
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
}
msg->flag = 1; //成功
printf("%s 登录了\n", msg->name);
}
else
{
strcpy(msg->data, "不允许重复登录\n");
msg->flag = 0;
}
}
send(acceptfd, msg, sizeof(MSG), 0);
return 0;
}
int do_query(int acceptfd, MSG *msg, sqlite3 *db)//用户查询单词实现
{
char sql[512] = "", *errmsg = NULL;
int found = 0;
char date[128];
char **result = NULL;
int rows = 0;
int columns = 0;
sprintf(sql, "select * from dict where Word='%s'", msg->data);
if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
{
printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
return -1;
}
if (0 == rows)//没有查到
{
strcpy(msg->data, "Not Found!!!");
send(acceptfd, msg, sizeof(MSG), 0);
}
else
{
printf("%s\t\t%s\n", result[2], result[3]);
strcpy(msg->data, result[3]);
//如果执行成功,还需要保存历史记录
//获取时间
get_data(date);
//通过sqlite3_exec函数插入数据
bzero(sql, sizeof(sql));
sprintf(sql, "insert into log values('%s', '%s', '%s', '%s')", msg->name, result[2], result[3], date);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
}
printf("%s 查询并插入记录成功!\n",msg->name);
send(acceptfd, msg, sizeof(MSG), 0);
}
return 0;
}
int do_history(int acceptfd, MSG *msg, sqlite3 *db)//查询历史记录
{
char sql[512] = "", *errmsg = NULL;
int found = 0;
char info[512];
char **result = NULL;
int rows = 0;
int columns = 0;
printf("%s 查询了记录...\n", msg->name);
sprintf(sql, "select * from log where name='%s'", msg->name);
if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
{
printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
return -1;
}
//将记录逐条发送给客户端
for (int i = 1; i <= rows; i++)
{
sprintf(info, "%s\t%s\t%s\t%s\n", result[i * columns], result[i * columns + 1], result[i * columns + 2], result[i * columns + 3]);
send(acceptfd, info, sizeof(info), 0);
}
strcpy(info, "query end");
send(acceptfd, info, sizeof(info), 0);
return 1;
}
//int history_callback(void* arg,int f_num,char** f_value,char** f_name);//查询历史函数使用的回调
//int do_searchword(int acceptfd, MSG *msg, char word[]);//查询单词函数的回调
int get_data(char *date)//获取时间
{
time_t t;
struct tm *tp;
time(&t);
tp = localtime(&t);
sprintf(date, "%d-%02d-%02d %02d:%02d:%02d",
1900 + tp->tm_year, 1 + tp->tm_mon, tp->tm_mday,
tp->tm_hour, tp->tm_min, tp->tm_sec);
}
客户端
#include "common.h"
int do_register(int sockfd, MSG *msg); //注册用户
int do_login(int sockfd, MSG *msg); //用户登录
int do_query(int sockfd, MSG *msg); //查询单词
int do_history(int sockfd, MSG *msg); //查询历史
int SubMenu(int sockfd); //二级子菜单
char name[20];
int flag=0;//页面跳转使用
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in serveraddr;
int n;
MSG msg;
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_addr.s_addr = inet_addr(SERADDR);
serveraddr.sin_port = htons(SERPORT);
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(">");
scanf("%d", &n);
getchar();
switch(n)
{
case 1:
do_register(sockfd, &msg);
break;
case 2:
if(do_login(sockfd, &msg) == 1)
{
SubMenu(sockfd);
}
break;
case 3:
close(sockfd);
exit(0);
break;
default:
printf("Invalid data cmd.\n");
}
}
return 0;
}
int SubMenu(int sockfd)
{
int n;
MSG msg;
while(1)
{
printf("-----------------------------------------------------\n");
printf("- 1.query_word 2.history_record 3.quit -\n");
printf("-----------------------------------------------------\n");
printf(">");
scanf("%d", &n);
getchar();
switch(n)
{
case 1:
do_query(sockfd, &msg);
break;
case 2:
do_history(sockfd, &msg);
break;
case 3:
close(sockfd);
exit(0);
break;
default :
printf("Invalid data cmd.\n");
}
}
return 0;
}
int do_register(int sockfd, MSG *msg) //注册用户
{
msg->option = R;
printf("请输入要注册的用户名>>>");
scanf("%s", msg->name);
while (getchar() != 10)
;
printf("请输入密码>>>");
scanf("%s", msg->data);
while (getchar() != 10)
;
//将用户名及密码发送给服务器,判断是否存在
send(sockfd, msg, sizeof(MSG), 0);
recv(sockfd, msg, sizeof(MSG), 0);
//接收服务器发回来的消息来判断是否成功
printf("Register: %s\n", msg->data);
return 0;
}
int do_login(int sockfd, MSG *msg) //用户登录
{
//设置操作码
msg->option = L;
//输入用户名
printf("请输入用户名>>>");
scanf("%s", msg->name);
while (getchar() != 10)
;
//输入密码
printf("请输入密码>>>");
scanf("%s", msg->data);
while (getchar() != 10)
;
//发送数据给服务器
send(sockfd, msg, sizeof(MSG), 0);
//接收服务器发送的数据
recv(sockfd, msg, sizeof(MSG), 0);
//判断是否登录成功
printf("%s\n", msg->data);
if (msg->flag == 0)
{
return 0;
}
else
{
strcpy(name, msg->name);
return 1;
}
}
int do_query(int sockfd, MSG *msg) //查询单词
{
msg->option = Q;
strcpy(msg->name, name);
printf("---------查询界面---------\n");
while (1)
{
printf("请输入单词 (输入#退出): ");
scanf("%s", msg->data);
while (getchar() != 10)
;
//如果输入的是#,返回
if (strcmp(msg->data, "#") == 0)
{
break;
}
send(sockfd, msg, sizeof(MSG), 0);
recv(sockfd, msg, sizeof(MSG), 0);
printf("EXPLANTION %s\n", msg->data);
}
return 0;
}
int do_history(int sockfd, MSG *msg) //查询历史
{
char info[512];
msg->option = H;
strcpy(msg->name, name);
send(sockfd, msg, sizeof(MSG), 0);
while (1)
{
recv(sockfd, info, sizeof(info), 0);
printf("%s\n", info);
if (0 == strcmp(info, "query end"))
{
break;
}
}
return 0;
}