头文件:
#ifndef __HEAD_H__
#define __HEAD_H__#include <myhead.h>#define N 32
typedef struct {int type;char name[N];char data[256];int option;int flag;
}MSG;#define R 1 // 用户注册
#define L 2 // 用户登录
#define Q 3 // 查询单词
#define H 4 // 历史记录#define DATABASE "my.db" //创建的数据库#define SERADDR "192.168.114.156"
#define SERPORT 8888 #endif
服务器:
#include "head.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;}//创建子进程if((pid = fork()) < 0){perror("fail to fork");return -1;}//子进程else if(pid == 0) {close(sockfd);do_client(acceptfd, db);}//父进程else {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("用户已退出\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++;elsebreak;}*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{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);}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, "已到末尾");send(acceptfd, info, sizeof(info), 0);return 1;
}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 "head.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("**********************请输入序号进行对应操作*********************\n");printf("****************************1.注册*******************************\n");printf("****************************2.登录*******************************\n");printf("****************************3.退出*******************************\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("输入不合法,请重新输入\n");}}return 0;
}int SubMenu(int sockfd)
{int n;MSG msg;while(1){printf("*****************************查询界面****************************\n");printf("**********************请输入序号进行对应操作*********************\n");printf("**************************1.查询单词*****************************\n");printf("**************************2.查询历史记录*************************\n");printf("**************************3.退出*****************************\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("请输入单词 (输入88退出): ");scanf("%s", msg->data);while (getchar() != 10);//如果输入的是#,返回if (strcmp(msg->data, "88") == 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, "已到末尾")){break;}}return 0;}