词典的功能主要分为五个部分,查询单词,查询历史记录,注册,登陆,删除历史记录。
主要用到的技术:JSON字符串,堆栈窗体(方便以后加新功能),QTcpSocket,LcdNumber,时间戳的转换。
通信用的是TCP通信,将TCP封在了一个头文件中,哪个文件想去通过TCP链接发送消息就可以使用头文件
QT端写的是客户端,服务器还是在我笔记上次的Linux系统下写的服务器,做了一些小修改
项目演示效果:
服务器代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "dictionary.h"
#include <sqlite3.h>
#include <signal.h>
#include <sys/wait.h>
#include <time.h>
#include "cJSON.h"
int acceptfd;
int search_word(int acceptfd);
int num = 10;
time_t t;
struct tm *tm;
char data[1024];
// 注册函数
void register_sev(int acceptfd, char *p, sqlite3 *db)
{
char sql[128] = " "; //定义数组来装insert语句
sprintf(sql, "insert into user values('%s','%s');", dic.name, dic.password);
//如果插入不成功则给dic.text赋值失败反之OK
if (sqlite3_exec(db, sql, NULL, NULL, &p) != SQLITE_OK)
{
strcpy(dic.text, "already exits!");
}
else
{
strcpy(dic.text, "OK");
}
dic.history_id = 1;
cJSON *data = cJSON_CreateObject();
cJSON_AddStringToObject(data, "text", dic.text);
cJSON_AddNumberToObject(data, "history", dic.history_id);
char *buf;
buf = cJSON_PrintUnformatted(data);
send(acceptfd, buf, strlen(buf), 0); //发送
}
// 登录函数
void login_sev(int acceptfd, char *p, char **result, int row, int line, sqlite3 *db)
{
// 定义一个输入去接收这个查询用户名和密码的语句
char buf[128];
dic.history_id = 1;
sprintf(buf, "select * from user where name = '%s' and password = '%s';", dic.name, dic.password);
// 先把输入的数据查询一下在表里,如果表里有数据则代表数据库有密码
if (sqlite3_get_table(db, buf, &result, &row, &line, &p) != SQLITE_OK)
{
perror("sev sqlite3_table error\n");
return;
}
// 如果行大于零则代表有数据成功
if (row > 0)
{
strcpy(dic.text, "login successs");
}
else
{
strcpy(dic.text, "login loose,please check your name or password!");
}
cJSON *data = cJSON_CreateObject();
cJSON_AddStringToObject(data, "text", dic.text);
cJSON_AddNumberToObject(data, "history", dic.history_id);
char *str;
str = cJSON_PrintUnformatted(data);
send(acceptfd, str, strlen(str), 0); //发送
return;
}
// 查询单词
int query_sev(int acceptfd, sqlite3 *db, char *p)
{
time_t t;
struct tm *tm;
int a = 0;
//定义一个语句去接受查询的语句
char sql2[128] = "";
if (!strcmp(dic.password, "#")) //如果在查找单词中输入#就会退出
{
return -1;
}
int found = search_word(acceptfd); //去接受查询单词这个函数的返回值 不为1则代表失败 返回1则代表成功
if (found != 1)
{
dic.history_id = 1;
strcpy(dic.text, "can't find \n");
cJSON *data = cJSON_CreateObject();
cJSON_AddStringToObject(data, "text", dic.text);
cJSON_AddNumberToObject(data, "history", dic.history_id);
char *buf;
buf = cJSON_PrintUnformatted(data);
send(acceptfd, buf, strlen(buf), 0); //发送
}
else
{
time(&t);
tm = localtime(&t);
sprintf(dic.time_sev, "%d-%d-%d %d:%d:%d", tm->tm_year + 1900,
tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
sprintf(sql2, "insert into record values('%s','%s');", dic.password, dic.time_sev); // 成功后就把查询成功的单词插入到record这个表里
if (sqlite3_exec(db, sql2, NULL, NULL, &p) != SQLITE_OK)
{
perror("record insert error\n");
return -1;
}
}
return 0;
}
// 查询单词函数
int search_word(int acceptfd)
{
//定义每次接受来的密码的长度
int len = strlen(dic.password);
//打开文件用标准IO
FILE *sp = fopen("dic.txt", "r");
if (NULL == sp)
{
perror("sp error\n");
return -1;
}
//如果dic.txt文件不为空时继续执行
while (fgets(dic.text, sizeof(dic.text), sp) != NULL)
{
char buf[32] = {};
for (int i = 0; i < 32; i++)
{
if (dic.text[i] != ' ')
{
buf[i] = dic.text[i];
}
else
{
break;
}
}
//拿密码去比较文件中单词 如果成功发送dic 并且返回1
if (!strcmp(buf, dic.password))
{
printf("%s\n", dic.text);
cJSON *data = cJSON_CreateObject();
cJSON_AddStringToObject(data, "text", dic.text);
cJSON_AddNumberToObject(data, "history", dic.history_id);
char *buf;
buf = cJSON_PrintUnformatted(data);
send(acceptfd, buf, strlen(buf), 0); //发送
return 1;
}
else
{
continue;
}
}
return -1;
}
//历史函数
int history_sev(char *p, sqlite3 *db)
{
char buf[64] = "select * from record ;";
char **pResult;
int nRow;
int nCol;
strcpy(dic.text,"");
if (sqlite3_get_table(db, buf, &pResult, &nRow, &nCol, &p) != SQLITE_OK)
{
fprintf(stderr, "select is error: %s\n", p); //如果不等于OK责代表没成功,报错
return -1;
}
else
{
for (size_t i = 2; i < nRow * nCol + 2; i++)
{
strcat(dic.text, pResult[i]);
strcat(dic.text, "\r\n");
}
printf("%s\n",dic.text);
dic.history_id = 2;
cJSON *data = cJSON_CreateObject();
cJSON_AddStringToObject(data, "text", dic.text);
cJSON_AddNumberToObject(data, "history", dic.history_id);
char *buf;
buf = cJSON_PrintUnformatted(data);
send(acceptfd, buf, strlen(buf), 0); //发送
}
return 0;
}
//删除历史记录函数
void delete_history(char *p, sqlite3 *db)
{
if (sqlite3_exec(db, "delete from record;", NULL, NULL, &p) != SQLITE_OK)
{
fprintf(stderr, "delete is error: %s\n", p); //如果不等于OK责代表没成功,报错
}
else
{
strcpy(dic.text, "删除成功!");
cJSON *data = cJSON_CreateObject();
cJSON_AddStringToObject(data, "text", dic.text);
cJSON_AddNumberToObject(data, "history", dic.history_id);
char *buf;
buf = cJSON_PrintUnformatted(data);
send(acceptfd, buf, strlen(buf), 0); //发送
}
return;
}
//处理僵尸进程
void hanlder(int arg)
{
waitpid(-1, NULL, WNOHANG);
}
int main(int argc, char const *argv[])
{
//1. 创建sql表
sqlite3 *db = NULL;
if (sqlite3_open("./dictionary.db", &db) != 0)
{
fprintf(stderr, "sqlite3 is error%s\n", sqlite3_errmsg(db));
return -1;
}
// 创建两个表
char *p = NULL;
if (sqlite3_exec(db, "create table user(name char primary key, password char);", NULL, NULL, &p) != SQLITE_OK)
{
fprintf(stderr, "create stu1 is error %s\n", p);
return -1;
}
if (sqlite3_exec(db, "create table record(password char,time char);", NULL, NULL, &p) != SQLITE_OK)
{
fprintf(stderr, "create record is error %s\n", p);
return -1;
}
// 创建指针以及行和列的变量
char **result = NULL;
int row = 0;
int line = 0;
// 创建套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("sev sockfd error\n");
return -1;
}
//填充结构体
struct sockaddr_in saddr, caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = inet_addr("192.168.50.248");
int len = sizeof(caddr);
// 绑定 和 监听
if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind error\n");
return -1;
}
if (listen(sockfd, 5) < 0)
{
perror("sev listen error\n");
return -1;
}
// 处理僵尸进程
signal(SIGCHLD, hanlder);
// 循环去接受
while (1)
{
acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
if (acceptfd < 0)
{
perror("sev acceptfd is error\n");
return -1;
}
// 创建进程
pid_t pid = fork();
if (pid < 0)
{
perror("sev pid error\n");
return -1;
}
else if (pid == 0) // 子进程
{
while (recv(acceptfd, data, sizeof(data), 0))
{
sleep(1);
printf("%s\n", data);
cJSON *root = cJSON_Parse(data);
dic.type = cJSON_GetObjectItem(root, "type")->valueint;
strcpy(dic.password, cJSON_GetObjectItem(root, "password")->valuestring);
strcpy(dic.name, cJSON_GetObjectItem(root, "name")->valuestring);
strcpy(dic.text, cJSON_GetObjectItem(root, "text")->valuestring);
strcpy(dic.time_sev, cJSON_GetObjectItem(root, "time_sev")->valuestring);
dic.history_id = 0;
printf("type = %c\n", dic.type);
printf("password = %s\n", dic.password);
printf("name = %s\n", dic.name);
printf("text = %s\n", dic.text);
printf("time_sev = %s\n", dic.time_sev);
printf("history_id = %d\n", dic.history_id);
switch (dic.type)
{
case 'r':
register_sev(acceptfd, p, db); // 注册函数
break;
case 'l':
login_sev(acceptfd, p, result, row, line, db); // 登录函数
break;
case 'q':
query_sev(acceptfd, db, p); //查询函数
break;
case 'h':
history_sev(p, db); //历史查询函数
break;
case 'd':
delete_history(p, db); // 历史记录删除函数
break;
default:
break;
}
}
}
else // 父进程
{
close(acceptfd);
}
}
return 0;
}
感谢大家的观看~,QT源码在最上方哦