功能展示
1.打印登录界面,未注册用户需先进行注册,若未注册就登陆则会提示用户不存在;
2.注册,若注册时输入的账户信息已存在则会提示用户已存在;
3.登陆;
4.单词查询,按1输入想要查询的单词,输入“#”退出查询;
5.历史记录查询,打印查询的时间及查询内容;
6.退出。
代码实现
服务器
#include "head.h"
int flag = 0;
char str[512] = {0};
int callback(void *buf, int num, char **value, char **name)
{
flag = 1;
strcpy(str, value[1]);
return 0;
}
int main(int argc, char const *argv[])
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0); //建立TCP传输控制协议
if (socket < 0)
{
perror("socket err\n");
return -1;
}
printf("sockfd:%d\n", sockfd);
struct sockaddr_in saddr, caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[1]));
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind err\n");
return -1;
}
printf("bind ok\n");
if (listen(sockfd, 6) < 0)
{
perror("listen err\n");
return -1;
}
printf("listen ok\n");
sqlite3 *db; //打开用户账户表
if (sqlite3_open("./ydict.db", &db) != SQLITE_OK)
{
fprintf(stderr, "open user err %s", sqlite3_errmsg(db));
return -1;
}
int acceptfd, len = sizeof(caddr), ret;
char buf[128] = {0};
MSG_t msg;
char *errmsg = NULL;
char sql[128] = {0};
text_t text;
time_t t;
struct tm *tm;
while (1) //循环接收客户端的连接请求
{
acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
if (acceptfd < 0)
{
perror("accept err\n");
return -1;
}
printf("accept ok\n");
printf("ip:%s port:%d\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
sqlite3_exec(db, "delete from history", callback, NULL, &errmsg);
while (1) //循环接收客户端注册与登录指令
{
flag = 0;
ret = recv(acceptfd, &msg, sizeof(msg), 0);
if (msg.type == regis)
{
sprintf(sql, "select * from user where name=\"%s\"", msg.name);
sqlite3_exec(db, sql, callback, NULL, &errmsg);
if (flag == 1)
{
sprintf(text.buf, "register : user \"%s\" already exist!!!", msg.name);
memset(sql, 0, sizeof(sql));
}
else
{
sprintf(sql, "insert into user values(\"%s\",\"%s\");", msg.name, msg.password);
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "insert dict err %s\n", errmsg);
return -1;
}
strcpy(text.buf, "register : OK");
}
send(acceptfd, &text, sizeof(text), 0);
}
if (msg.type == login)
{
sprintf(sql, "select * from user where name=\"%s\" and password=\"%s\"", msg.name, msg.password);
sqlite3_exec(db, sql, callback, NULL, &errmsg);
if (flag == 1)
{
text.type = right;
strcpy(text.buf, "login success");
send(acceptfd, &text, sizeof(text), 0);
break;
}
else
{
strcpy(text.buf, "input error , please try again");
send(acceptfd, &text, sizeof(text), 0);
}
}
if (msg.type == quit)
{
printf("client quit\n");
}
}
while (1) //登录后循环接收客户端的操作指令
{
recv(acceptfd, &text, sizeof(text), 0);
if (text.type == query_word)
{
flag = 0;
if (strcmp(text.buf, "#") != 0)
{
time(&t);
tm = localtime(&t);
sprintf(buf, "%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(sql, "insert into history values(\"%s\",\"%s\");", buf, text.buf);
sqlite3_exec(db, sql, NULL, NULL, &errmsg);
sprintf(sql, "select * from dict where word=\"%s\"", text.buf);
sqlite3_exec(db, sql, callback, NULL, &errmsg);
if (flag == 1)
strcpy(text.buf, str);
else
strcpy(text.buf, "input error , please try again");
send(acceptfd, &text, sizeof(text), 0);
}
}
if (text.type == history_record)
{
char **result = NULL;
int row, column, k = 0;
sqlite3_get_table(db, "select * from history;", &result, &row, &column, &errmsg);
while (k <= (row * column))
{
sprintf(buf, "%s : %s", result[k], result[k + 1]);
k += column;
send(acceptfd, buf, sizeof(buf), 0);
}
send(acceptfd, "over", sizeof(buf), 0);
}
if (msg.type == quit)
{
printf("client quit\n");
break;
}
}
}
return 0;
}
客户端
#include "head.h"
int main(int argc, char const *argv[])
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0); //建立tcp传输控制协议
if (sockfd < 0)
{
perror("sockfd err\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("输入服务器网络地址");
if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) //与服务器连接
{
perror("connect err\n");
return -1;
}
int num;
MSG_t msg;
char buf[128] = {0};
text_t text;
while (1)
{
printf("**********************************\n");
printf("* 1: register 2: login 3: quit *\n");
printf("**********************************\n");
printf("please input your choice: ");
scanf("%d", &num); //循环输入注册、登录指令进行判断
switch (num)
{
case 1:
msg.type = regis;
printf("input name:");
scanf("%s", msg.name);
printf("input password:");
scanf("%s", msg.password);
send(sockfd, &msg, sizeof(msg), 0);
break;
case 2:
msg.type = login;
printf("input name:");
scanf("%s", msg.name);
printf("input password:");
scanf("%s", msg.password);
send(sockfd, &msg, sizeof(msg), 0);
break;
case 3:
msg.type = quit;
send(sockfd, &msg, sizeof(msg), 0);
return 0;
}
recv(sockfd, &text, sizeof(text), 0);
printf("%s\n", text.buf);
putchar(10);
if (text.type == right)
break;
}
while (1) //登录后循环输入操作指令
{
printf("*********************************************\n");
printf("* 1: query_word 2: history_record 3: quit *\n");
printf("*********************************************\n");
printf("please input your choice: ");
scanf("%d", &num);
putchar(10);
switch (num)
{
case 1:
while (1)
{
text.type = query_word; //单词查询
printf("input word(# to quit) : ");
scanf("%s", text.buf);
send(sockfd, &text, sizeof(text), 0);
if (strcmp(text.buf, "#") == 0)
break;
else
{
recv(sockfd, &text, sizeof(text), 0);
printf("%s\n", text.buf);
putchar(10);
}
}
break;
case 2:
text.type = history_record; //历史记录查询
send(sockfd, &text, sizeof(text), 0);
while (1)
{
recv(sockfd,buf,sizeof(buf),0);
if (strcmp(buf,"over")==0)
break;
printf("%s\n",buf);
}
break;
case 3:
msg.type = quit; //登出
send(sockfd, &msg, sizeof(msg), 0);
printf("bye~~\n");
return 0;
break;
}
putchar(10);
}
return 0;
}
head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <poll.h>
#include <sqlite3.h>
#include <time.h>
//消息对应的结构体
typedef struct msg_t
{
int type;
char name[32];
char password[128];
} MSG_t;
typedef struct TEXT
{
int type;
char buf[128];
} text_t;
enum un
{
regis,
login,
quit,
query_word,
history_record,
error,
right,
};
#endif
单词文本导入数据库
#include <stdio.h>
#include <sqlite3.h>
int callback(void *buf, int num, char **value, char **name);
int main(int argc, char const *argv[])
{
sqlite3 *db;
// 打开数据库
if (sqlite3_open("./ydict.db", &db) != SQLITE_OK)
{
fprintf(stderr, "open ydict err %s", sqlite3_errmsg(db));
return -1;
}
//操作数据库
char *errmsg = NULL;
//创建表
if (sqlite3_exec(db, "create table history(time char,word char);",
NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "create dict err %s\n", errmsg);
//return -1;
}
sqlite3_close(db);
return 0;
}
此外,需要在数据库中创建三个表,分别来储存单词文本,用户信息,历史记录
代码讲解
该云词典的核心内容是sql数据库的操作,表格的建立,数据的插入、删除和查询是支撑辞典运行的关键。
登陆之前,输入账号时在表格中查询该账号是否存在,不存在则反馈信息,若存在且账号密码一致则登陆
登录后进入查询循环,每次查询单词都要将查询时间和单词插入历史表格中,以供查询历史记录使用,时间可以用localtime函数。