- #include <stdio.h>
- #include <sqlite3.h>
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- 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 <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h>
- #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 <stdio.h>
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h> /* superset of previous */
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sqlite3.h>
- #include <signal.h>
- #include <sys/select.h>
- #include <time.h>
- #include <sys/time.h>
- #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 <stdio.h>
- #include <sys/types.h> /* See NOTES */
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/ip.h> /* superset of previous */
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #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;
- }
-