数据库创建及导入单词表
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
// 1.打开或创建数据库
sqlite3 *db = NULL;
int rc;
if (sqlite3_open("./word.db", &db) != SQLITE_OK)//打开或创建库
{
printf("sqlite3_open err:%s\n", sqlite3_errmsg(db));
return -1;
}
printf("sqlite3_open success\n");
// 2.创建表
char *errmsg = NULL;//返回创建数据库表的错误
//创建一个两列的单词表,用于存储单词及注释
if (sqlite3_exec(db, "create table if not exists wd1 (word char, annotation char);", NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("create err: %sn", errmsg);
sqlite3_close(db);
return -1;
}
//创建一个两列的账户表,用于存储账户名及对应密码
if (sqlite3_exec(db, "create table if not exists user (name char, password char);", NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("create err: %sn", errmsg);
sqlite3_close(db);
return -1;
}
printf("create success\n");
// 3.向表中插入数据
FILE *fp = fopen(argv[1], "r");//打开要插入的文件流
if (fp == NULL)
{
printf("failed to open file\n");
sqlite3_close(db);
return -1;
}
char buf[1024]; //读取的一行
char word[32]; //单词
char ant[1024]; //保存注释
while (fgets(buf, sizeof(buf), fp) != NULL) //读一行
{
sscanf(buf, "%99[^ ] %256[^\n]", word, ant); //将第一个单词放到单词数组中,后面的内容放到注释数组中
char sql[1024];//存放命令内容
sprintf(sql, "insert into wd1 values(\"%s\", \"%s\");", word, ant); // 构造插入语句,将单词及注释插入到单词表中
rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if (rc != SQLITE_OK)
{
printf("insert err: %s\n", errmsg);
return -1;
}
}
fclose(fp);//关闭文件描述符
// 5.关闭数据库连接
sqlite3_close(db);
return 0;
}
头函数及传输协议
#ifndef __HEAD_H__
#define __HEAD_H__//防止重包含
#include
#include
#include
#define N 32
enum type_t //运行命令
{
R=4, //register注册
L, //login登录
Q, //query搜索
H, //history历史
};
typedef struct //数据包结构体
{
int type;//执行命令类型
char name[N]; //用户名
char data[1024]; //密码或要查询的单词
} MSG_t;
typedef struct node_t
{
struct sockaddr_in addr; //ip地址
struct node_t *next; //链表下一个地址
} list_t;
#endif
云词典服务器端
/*服务器创建代码 */
#include
#include /* See NOTES */
#include
#include
#include /* superset of previous */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "head.h"
MSG_t msg;
int n;
sqlite3 *db = NULL; //命令输入
char *errmsg = NULL; //错误码
int hang, lie; //数据库行和列
int k = 0;
int Register(sqlite3 *db, int sockfd) //注册函数
{
char **result = NULL; //数据库返回内容
//3.向表中插入数据
//(1)执行函数
char sq1[128]; //保存命令
sprintf(sq1, "select * from user where name = \"%s\";", msg.name);
sqlite3_get_table(db, sq1, &result, &hang, &lie, &errmsg);//判断数据库中是否已经存在该账户
if (hang != 0)
{
sprintf(msg.data, "账户已存在;\n");
send(sockfd, &msg, sizeof(msg), 0);
return -1;
}
else //成功注册
{
sprintf(sq1, "insert into user values(\"%s\",\"%s\");", msg.name, msg.data);
if (sqlite3_exec(db, sq1, NULL, NULL, &errmsg) == SQLITE_OK) //""需要用\转意,注册成功插入用户表内
{
sprintf(sq1, "create table if not exists \"%s\" (word char, time char);", msg.name); //每注册一个用户创建一个新表
if (sqlite3_exec(db, sq1, NULL, NULL, &errmsg) != SQLITE_OK) //创建新表
{
printf("create err: %s", errmsg);
sqlite3_close(db);
return -1;
}
else
{
printf("creat %s success\n", msg.name);
}
sprintf(msg.data, "OK");
send(sockfd, &msg, sizeof(msg), 0); //注册成功发送消息
memset(msg.data, 0, sizeof(msg.data));
return 0;
}
else //否则插入失败
{
printf("insert value err;%s\n", errmsg);
return -1;
}
}
}
//用户登录
int loginclient(sqlite3 *db, int sockfd)
{
char **result = NULL; //数据库返回内容
char sq1[128]; //保存命令
sprintf(sq1, "select * from user where name = \"%s\";", msg.name);
sqlite3_get_table(db, sq1, &result, &hang, &lie, &errmsg); //判断数据库中是否已经存在该账户
if (hang != 0) //如果能读出内容则行数不为0
{
if (strcmp(result[3], msg.data) == 0) //判断密码是否正确
{
sprintf(msg.data, "OK");
send(sockfd, &msg, sizeof(msg), 0);
return 0;
}
else //密码错误
{
sprintf(msg.data, "password err\n");
send(sockfd, &msg, sizeof(msg), 0);
return -1;
}
}
else //反之未注册
{
sprintf(msg.data, "no register\n"); //未注册
send(sockfd, &msg, sizeof(msg), 0);
return -1;
}
}
//查询单词注释
int chatclient(sqlite3 *db, int sockfd) //查询单词函数
{
char **result = NULL; //数据库返回内容
char sq1[128]; //保存命令
sprintf(sq1, "select * from wd1 where word = \"%s\";", msg.data);
sqlite3_get_table(db, sq1, &result, &hang, &lie, &errmsg); //判断是否查到该单词
if (hang != 0)
{
sprintf(msg.data, "%s", result[3]); //将注释内容发送到客户端
send(sockfd, &msg, sizeof(msg), 0); //发送该单词注释
time_t th;
time(&th); //获取当前时间
char times[128];
struct tm *ts;
ts = localtime(&th); //将当时间转化为标准时间
sprintf(times, "%4d-%2d-%2d %2d:%2d:%2d", ts->tm_year + 1900, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec);
//先将时间放到一个字符串中,再放到命令语句中
sprintf(sq1, "insert into \"%s\" values(\"%s\", \"%s\");", msg.name, result[2], times); // 构造插入语句
int rc = sqlite3_exec(db, sq1, NULL, NULL, &errmsg); //将查询时间保存到数据库中
if (rc != SQLITE_OK)
{
printf("insert err: %s\n", errmsg);
return -1;
}
return 0;
}
else //未找到该单词
{
sprintf(msg.data, "word unfund\n");
send(sockfd, &msg, sizeof(msg), 0);
return -1;
}
}
int history(sqlite3 *db, int sockfd) //查询历史记录
{
char **result = NULL; //数据库返回内容
char sq1[128]; //保存命令
sprintf(sq1, "select * from \"%s\";", msg.name); //查询单词查询历史
sqlite3_get_table(db, sq1, &result, &hang, &lie, &errmsg);
if (hang != 0)
{
for (int j = 0; j < hang; j++) //拼接表内内容到字符数组中
{
strcat(msg.data, result[j * lie + 2]);
strcat(msg.data, " "); //两个表内内容间添加空格间隔
strcat(msg.data, result[j * lie + 3]);
strcat(msg.data, "\n"); //两行间换行
}
send(sockfd, &msg, sizeof(msg), 0); //发送该单词查询结果
return 0;
}
else if (hang == 0) //历史记录为空
{
sprintf(msg.data, "history is void");
send(sockfd, &msg, sizeof(msg), 0); //发送该单词查询结果
return 0;
}
}
int main(int argc, char const *argv[])
{
// 1.打开或创建数据库
int rc;
if (sqlite3_open("./word.db", &db) != SQLITE_OK)
{
printf("sqlite3_open err:%s\n", sqlite3_errmsg(db));
return -1;
}
printf("sqlite3_open success\n"); //打开数据库成功
if (argc < 2) //行传参正确
{
printf("plase input \n");
return -1;
}
//1.创建套接字,用于链接
int sockfd;
int acceptfd; //接收套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) //容错
{
perror("socket err");
return -1;
}
//2.绑定 ip+port 填充结构体
struct sockaddr_in saddr;
saddr.sin_family = AF_INET; //协议族ipv4
saddr.sin_port = htons(atoi(argv[1])); //端口号,htons将无符号短整数hostshort从主机字节顺序到网络字节顺序。
saddr.sin_addr.s_addr = inet_addr("0.0.0.0"); //ip地址,转化为16进制表示
socklen_t len = sizeof(saddr); //结构体大小
//bind绑定ip和端口
if (bind(sockfd, (struct sockaddr *)&saddr, len) < 0)
{
perror("bind err");
return -1;
}
//3.启动监听,把主动套接子变为被动套接字
if (listen(sockfd, 6) < 0)
{
perror("listen err");
return -1;
}
//4.创建表
fd_set readfds; //原表
fd_set tempfds; //创建一个临时表,用来保存新表
FD_ZERO(&readfds); //原表置空
//5.填表
FD_SET(sockfd, &readfds); //将要监测的文件描述符插入到表中
int maxfd = sockfd; //表内最大描述符
int ret;
//6.循环监听 select
while (1)
{
tempfds = readfds; //每次循环前重新赋值一次
int ret = select(maxfd + 1, &tempfds, NULL, NULL, NULL); //监测
if (ret < 0)
{
perror("select err");
return -1;
}
if (FD_ISSET(sockfd, &tempfds)) //监听是否有客户端链接
{
//阻塞等待客户端的链接请求
acceptfd = accept(sockfd, (struct sockaddr *)&saddr, &len);
//获取客户端的ip和端口,(struct sockaddr *)&saddr:用来存放返回的ip,和端口
if (acceptfd < 0)
{
perror("accept err");
return -1;
}
printf("client ip:%s ,port:%d:connect success\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
//打印已经接入的客户端IP
FD_SET(acceptfd, &readfds); //将新接入的客户端文件描述符插入到原表中
if (acceptfd > maxfd) //如果新插入的文件描述符大于已知最大文件描述符,则更新表内最大文件描述符
{
maxfd = acceptfd;
}
}
for (int i = 5; i <= maxfd; i++) //遍历判断是否有信号传输
{
if (FD_ISSET(i, &tempfds)) //监测客户端文件描述符
{
int ret = recv(i, &msg, sizeof(msg), 0); //接收的信号
if (ret < 0) //接收错误
{
perror("recv err.");
return -1;
}
else if (ret == 0)
{
printf("%d client exit\n", i); //客户端退出
close(i); //关闭描述符
FD_CLR(i, &readfds); //删除文件描述符
}
else
{
switch (msg.type)
{
case R: //注册
Register(db, i);
break;
case L: //登录
loginclient(db, i);
break;
case Q: //搜索
chatclient(db, i);
break;
case H: //历史
history(db, i);
break;
default:
break;
}
}
}
}
}
close(sockfd);
close(acceptfd);
return 0;
}
云词典客户端
/*客户端创建代码 */
#include
#include /* See NOTES */
#include
#include
#include /* superset of previous */
#include
#include
#include
#include
#include "head.h"
#define N 32
MSG_t msg;
int n; //命令输入
//注册操作
void do_register(int sockfd)
{
while (1)
{
msg.type = R; //注册状态
printf("请输入您的用户名:");
scanf("%s", msg.name);
getchar(); //回收一个垃圾字符
if (memcmp(msg.name, "#", 1) == 0) //注册过程中输入#退出注册页面
{
printf("退出注册\n");
break;
}
printf("请输入您的密码:");
scanf("%s", msg.data);
getchar();
send(sockfd, &msg, sizeof(msg), 0);
recv(sockfd, &msg, sizeof(msg), 0); //接收客户端消息,判断是否注册成功
printf("register:%s\n", msg.data);
if (memcmp(msg.data, "OK", 2) == 0) //服务器返回的msg.data == OK注册成功
{
break;
}
}
}
//登录操作
int do_login(int sockfd)
{
while (1)
{
msg.type = L; //登录状态
printf("请输入您的用户名:");
scanf("%s", msg.name);
getchar();
if (memcmp(msg.data, "#", 1) == 0) //退出查询页面,先判断退出后发送内容
{
printf("退出查询\n");
msg.type = 0;//当发送给服务器为结束内容,让服务器端读出且无法识别type,继续等待事件
memset(msg.data,0,sizeof(msg.data));//将msg.data中的#清空
send(sockfd, &msg, sizeof(msg), 0);
break;
}
printf("请输入您的密码:");
scanf("%s", msg.data);
getchar();
send(sockfd, &msg, sizeof(msg), 0);
recv(sockfd, &msg, sizeof(msg), 0);
printf("login:%s\n", msg.data);
if (memcmp(msg.data, "OK", 2) == 0) //服务器返回的msg.data=OK登录成功
{
return 1;
}
}
}
//查询操作
void do_query(int sockfd)
{
msg.type = Q;
while (1)
{
printf("请输入你要查询的单词内容:");
scanf("%s", msg.data);
getchar();
if (memcmp(msg.data, "#", 1) == 0) //退出查询页面,先判断退出后发送内容
{
printf("退出查询\n");
msg.type = 0;//当发送给服务器为结束内容,让服务器端读出且无法识别type,继续等待事件
memset(msg.data,0,sizeof(msg.data));
send(sockfd, &msg, sizeof(msg), 0);
break;
}
send(sockfd, &msg, sizeof(msg), 0);
recv(sockfd, &msg, sizeof(msg), 0);
printf("annotation:%s\n", msg.data); //打印接收的信息/注释
}
}
//查询历史记录
void do_history(int sockfd)
{
// memset(msg.data, 0, sizeof(msg.data));
msg.type = H;
send(sockfd, &msg, sizeof(msg), 0);
recv(sockfd, &msg, sizeof(msg), 0); //接收信息,接一次打一次.
printf("%s\n", msg.data);
}
//主函数
int main(int argc, char const *argv[])
{
if (argc < 3)
{
printf("plase input \n");
return -1;
}
//1.创建套接字,用于链接
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket err");
return -1;
}
//文件描述符 0 -> 标准输入 1->标准输出 2->标准出错 3->socket
printf("sockfd:%d\n", sockfd);
//2.绑定 ip+port 填充结构体
struct sockaddr_in saddr;
saddr.sin_family = AF_INET; //协议族ipv4
saddr.sin_port = htons(atoi(argv[2])); //端口号,htons将无符号短整数hostshort从主机字节顺序到网络字节顺序。
saddr.sin_addr.s_addr = inet_addr(argv[1]); //ip地址,转化为16进制表示
socklen_t len = sizeof(saddr); //结构体大小
//3用于连接服务器;
if (connect(sockfd, (struct sockaddr *)&saddr, len) < 0)
{
perror("connect err");
return -1;
}
int flag = 0;
while (1)
{
printf("*******************************************************\n");
printf("* *\n");
printf("* 1: 注册 2: 登录 3: 退出 *\n");
printf("*******************************************************\n");
printf("请输入命令:");
scanf("%d", &n);
getchar();
switch (n)
{
case 1:
do_register(sockfd);
break;
case 2:
if (do_login(sockfd) == 1)
{
while (1)
{
if (flag == 1)
{
flag = 0;
break;
}
printf("*******************************************************\n");
printf("* *\n");
printf("* 1: 查询单词 2: 历史记录 3: 退出 *\n");
printf("*******************************************************\n");
printf("请输入命令:");
scanf("%d", &n);
getchar();
switch (n)
{
case 1:
do_query(sockfd);
break;
case 2:
printf("search history\n");
do_history(sockfd);
break;
case 3:
flag = 1;
break;
default:
break;
}
}
}
break;
case 3:
return 0;
default:
break;
}
}
close(sockfd);
return 0;
}