1. 登录注册功能,不能重复登录,重复注册
2. 单词查询功能
3. 历史记录功能,存储单词,意思,以及查询时间
4. 基于TCP,支持多客户端连接
5. 采用数据库保存用户信息与历史记录
6. 将dict.txt的数据导入到数据库中保存。
7. 按下ctrl+c退出客户端后,注销该客户端的登录信息
8. 使用并发服务器
头文件:
#ifndef __SERVER_H__
#define __SERVER_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 6666
#define IP "192.168.10.90"
#define R 1 //注册
#define L 2 //登录
#define S 3 //查单词
#define Q 4 //查记录
#define B 5 //回退
typedef struct msg
{
char name[20];//用户名
char data[128];//密码|单词|消息
int option;//判断执行什么操作
int flag;//成功或失败
}MSG;
void init_sql(sqlite3 *db);
void handler(int sig);
void init_internet(int sockfd, int port, char *addr);
void client_deal(int newfd, sqlite3 *db);
void Register(int sockfd, MSG *msg, sqlite3 *db);
void Login(int newfd, MSG *msg, sqlite3 *db);
int Search_word();
void getdata(char *date);
int Query_log(int newfd, MSG *msg, sqlite3 *db);
void off(MSG *msg, sqlite3 *db);
#endif
服务器实现代码:
#include
#include "server.h"
int main(int argc, const char *argv[])
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
int newfd;
pid_t pid;
if (sockfd < 0)
{
perror("socket");
return -1;
}
init_internet(sockfd, PORT, IP);
signal(SIGCHLD, handler);
sqlite3 *db = NULL;
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 ((newfd = accept(sockfd, (struct sockaddr *)&cin, &cin_len)) < 0)
{
perror("accept");
return -1;
}
printf("[%s:%d]连接到服务器..\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
if ((pid = fork()) < 0)
{
perror("fork");
return -1;
}
else if (0 == pid) //子进程执行处理代码
{
client_deal(newfd, db);
}
else //父进程负责连接
{
close(newfd);
}
}
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 handler(int sig) //处理僵尸进程
{
while (waitpid(-1, NULL, WNOHANG) > 0)
;
}
void init_internet(int sockfd, int port, char *addr)
{
int reuse = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("setsockopt");
return;
}
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(addr);
sin.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("bind");
return;
}
if (listen(sockfd, 10) < 0)
{
perror("listen");
return;
}
}
//客户端处理函数
void client_deal(int newfd, sqlite3 *db)
{
MSG msg;
while (1) // 接收客户端发来的请求
{
char sql[512];
char *errmsg = NULL;
int res = recv(newfd, &msg, sizeof(MSG), 0);
if (res < 0)
{
perror("recv");
return;
}
else if (0 == res)
{
printf("client quit\n");
sprintf(sql, "update usr set status = 'no' where name = '%s'", msg.name); //退出后登录状态为No
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
}
exit(0);
}
else
{
switch (msg.option)
{
case R:
Register(newfd, &msg, db);
break;
case L:
Login(newfd, &msg, db);
break;
case S:
Search_word(newfd, &msg, db);
break;
case Q:
Query_log(newfd, &msg, db);
break;
case B:
off(&msg, db);
}
}
}
return;
}
//注册功能
void Register(int sockfd, 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(sockfd, msg, sizeof(MSG), 0);
return;
}
//登录功能
void Login(int newfd, 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(newfd, msg, sizeof(MSG), 0);
return;
}
//查询单词功能
int Search_word(int newfd, 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(newfd, msg, sizeof(MSG), 0);
}
else
{
printf("%s\t\t%s\n", result[2], result[3]);
strcpy(msg->data, result[3]);
//如果执行成功,还需要保存历史记录
//获取时间
getdata(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(newfd, msg, sizeof(MSG), 0);
}
return 0;
}
//获取系统当前时间
void getdata(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);
}
//查询记录
int Query_log(int newfd, 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(newfd, info, sizeof(info), 0);
}
strcpy(info, "query end");
send(newfd, info, sizeof(info), 0);
return 1;
}
//注销
void off(MSG *msg, sqlite3 *db) //注销登录后,设置状态为no
{
char sql[512];
char *errmsg = NULL;
sprintf(sql, "update usr set status = 'no' where name = '%s'", msg->name); //登录之后状态设置为no;
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);
}
头文件
#ifndef __SERVER_H__
#define __SERVER_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 6666
#define IP "192.168.10.90"
#define R 1 //注册
#define L 2 //登录
#define S 3 //查单词
#define Q 4 //查记录
#define B 5 //回退
typedef struct msg
{
char name[20];//用户名
char data[128];//密码|单词|消息
int option;//判断执行什么操作
int flag;//成功或失败
}MSG;
void init_sql(sqlite3 *db);
void handler(int sig);
void init_internet(int sockfd, int port, char *addr);
void client_deal(int newfd, sqlite3 *db);
void Register(int sockfd, MSG *msg, sqlite3 *db);
void Login(int newfd, MSG *msg, sqlite3 *db);
int Search_word();
void getdata(char *date);
int Query_log(int newfd, MSG *msg, sqlite3 *db);
void off(MSG *msg, sqlite3 *db);
#endif
客户端实现代码:
#include
#include "client.h"
char name[20];
int flag=0;//页面跳转使用
int main(int argc, const char *argv[])
{
MSG msg;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket");
return -1;
}
init_internet(sockfd, PORT, IP);
START:
main_chose(sockfd, msg);
if (flag == 1)
{
chose(sockfd, msg);
goto START;
}
if(flag==0)
{
goto END;
}
END:
close(sockfd);
return 0;
}
void main_chose(int sockfd, MSG msg)
{
int res = 0;
while (1)
{
main_menu();
int chose;
printf("请选择>>>");
scanf("%d", &chose);
while (getchar() != 10)
;
switch (chose)
{
case 1:
Register(sockfd, &msg);
break;
case 2:
res = Login(sockfd, &msg);
break;
case 3:
return;
default:
printf("输入错误\n");
break;
}
if (1 == res)
{
flag = 1; //跳下一个页面;
printf("按任意键进入下一页面>>>");
while (getchar() != 10)
;
break;
}
printf("按任意键清屏>>>");
while (getchar() != 10)
;
}
return;
}
void chose(int sockfd, MSG msg)
{
while (1)
{
menu();
int chose;
printf("请选择>>>");
scanf("%d", &chose);
while (getchar() != 10)
;
switch (chose)
{
case 1:
Search_word(sockfd, &msg);
break;
case 2:
Query_log(sockfd, &msg);
break;
case 3:
Back(sockfd,&msg);
flag=0;
return;
default:
printf("输入错误\n");
break;
}
printf("按任意键清屏>>>");
while (getchar() != 10)
;
}
return;
}
void main_menu()
{
system("clear");
printf("=======================电子词典============================\n");
printf("------------------------主界面-----------------------------\n");
printf("\t\t\t1.注册\n");
printf("\t\t\t2.登录\n");
printf("\t\t\t3.退出\n");
printf("-----------------------------------------------------------\n");
}
void menu()
{
system("clear");
printf("=======================电子词典============================\n");
printf("-----------------------功能菜单----------------------------\n");
printf("\t\t\t1.查单词\n");
printf("\t\t\t2.查询记录\n");
printf("\t\t\t3.返回上级\n");
printf("-----------------------------------------------------------\n");
}
//连接服务器
void init_internet(int sockfd, int port, char *addr)
{
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(addr);
sin.sin_port = htons(port);
if (-1 == connect(sockfd, (struct sockaddr *)&sin, sizeof(sin)))
{
perror("connect");
return;
}
printf("connect success\n");
}
//注册功能
void 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;
}
//登录功能
int 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 Search_word(int sockfd, MSG *msg)
{
msg->option = S;
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 Query_log(int sockfd, MSG *msg)
{
char info[512];
msg->option = Q;
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;
}
//返回上一级,退出登录
void Back(int sockfd,MSG*msg)
{
msg->option = B;
strcpy(msg->name, name);
send(sockfd, msg, sizeof(MSG), 0);
main_menu();
}
1.客户端
2.服务器
1.客户端
2.服务器
1.客户端
2.服务器
1.客户端
2.服务器
1.客户端
2.服务器
客户端