在线词典
功能:基于Linux操作系统,网络编程和数据库实现在线词典
客户端可以注册,登入,查询历史信息等操作,使用基于TCP的多线程并发服务器,并使用sqlite3数据库实现单词的导入以及对用户信息的管理。
1.注册:若用户名已经注册过,重新注册
2.登录:用户名或密码错误需重新登录
3.查询:输入要查的单词,#键结束查询
4.历史:可以查询当前用户历史查找过的单词
5.退出:退出在线词典
客户端相关代码
客户端主函数相关代码
#include "./inc/dict_socket.h"
void mainloop(int sfd);
int main(int argc, const char *argv[])
{
//判断参数是否正确
if(argc < 3)
{
printf("参数不正确 请按以下格式输入 ip port\n");
ERR_MSG();
return -1;
}
struct sockaddr_in sin;
struct sockaddr_in cin;
char name[32] = "";
int op;
int sfd = init_socket(argv[1], atoi(argv[2]), &sin);
mainloop(sfd);
return 0;
}
#if 0
1:注册
2:登录
3:退出
#endif
void mainloop(int sfd)
{
int op = 0;
char name[32] = "";
int flag = 0;
system("clear");
menu1();
while(1)
{
scanf("%d", &op);
clear();
switch(op)
{
case 1:
if(flag == 0)
{
do_register(sfd);
menu2();
}
break;
case 2:
if(flag == 0)
{
if(do_login(sfd, name) == 0)
{
flag = 1;
menu3();
}
else
{
menu2();
}
}
break;
case 3:
if(flag == 1)
{
do_quit(sfd,name);
menu2();
flag = 0;
}
break;
case 4:
if(flag == 1)
{
do_search(sfd,name);
menu3();
}
break;
case 5:
if(flag == 1)
{
do_history(sfd,name);
menu3();
}
break;
case 0:
if(flag == 0)
{
return ;
}
break;
default:
break;
}
}
}
客户端网络相关代码
#include "../inc/dict_socket.h"
int init_socket(const char* ip, short port, struct sockaddr_in* sin)
{
//创建流式套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd < 0)
{
perror("socket");
ERR_MSG();
return -1;
}
//允许端口快速重用
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("setsockopt");
ERR_MSG();
return -1;
}
//填充地址信息结构体 非必须绑定
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
sin->sin_addr.s_addr = inet_addr(ip);
if(connect(sfd, (struct sockaddr *)sin, sizeof(struct sockaddr_in)) < 0)
{
perror("connect");
ERR_MSG();
return -1;
}
printf("网络初始化成功\n");
printf("连接成功\n");
return sfd;
}
客户端操作代码
#include "../inc/op.h"
void menu1()
{
printf("\t\t****************\n");
printf("\t\t****************\n");
printf("\t\t*** 1 注册 ***\n");
printf("\t\t*** 2 登录 ***\n");
printf("\t\t*** 0 退出 ***\n");
printf("\t\t****************\n");
printf("\t\t****************\n");
}
void menu2()
{
printf("输入任意字符清屏>>");
while(getchar()!=10);
system("clear");
menu1();
}
void menu3()
{
printf("输入任意字符清屏>>");
while(getchar()!=10);
system("clear");
printf("\t\t****************\n");
printf("\t\t****************\n");
printf("\t\t*** 3 退出 ***\n");
printf("\t\t*** 4 查询 ***\n");
printf("\t\t*** 5 历史 ***\n");
printf("\t\t****************\n");
printf("\t\t****************\n");
}
int do_register(int sfd)
{
package pack;
char buf[8] = "";
pack.type = 'R';
printf("请输入用户名:");
fgets(pack.name, sizeof(pack.name), stdin);
pack.name[strlen(pack.name) - 1] = 0;
printf("请输入密码");
fgets(pack.passwd, sizeof(pack.passwd), stdin);
pack.passwd[strlen(pack.passwd) - 1] = 0;
if(send(sfd, &pack, sizeof(pack), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
// printf("发送成功\n");
if(recv(sfd, buf, sizeof(buf), 0) < 0)
{
ERR_MSG();
perror("recv");
return -1;
}
if(strncmp(buf, "success", 5) == 0)
{
printf("注册成功\n");
}
else if(strncmp(buf, "exist", 4) == 0)
{
printf("用户名已存在,注册失败\n");
}
else
{
printf("recv buf: %s\n", buf);
}
return 0;
}
int do_login(int sfd, char* name)
{
package pack;
char buf[8] = "";
pack.type = 'L';
printf("请输入用户名:");
fgets(pack.name, sizeof(pack.name), stdin);
pack.name[strlen(pack.name) - 1] = 0;
printf("请输入密码:");
fgets(pack.passwd, sizeof(pack.passwd), stdin);
pack.passwd[strlen(pack.passwd) - 1] = 0;
if(send(sfd, &pack, sizeof(pack), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
//printf("发送成功\n");
if(recv(sfd, buf, sizeof(buf), 0) < 0)
{
perror("recv");
ERR_MSG();
return -1;
}
if(strncmp(buf, "notname", 7) == 0)
{
printf("用户名不存在\n");
return -1;
}
else if(strncmp(buf, "notwd", 5) == 0)
{
printf("密码错误\n");
return -1;
}
else if(strncmp(buf, "chongfu", 7) == 0)
{
printf("重复登录\n");
return -1;
}
else if(strncmp(buf, "success", 6) == 0)
{
strcpy(name, pack.name);
printf("登陆成功\n");
return 0;
}
else
{
printf("recv : %s\n", buf);
}
return 0;
}
int do_quit(int sfd, const char* name)
{
package pack;
pack.type = 'Q';
strcpy(pack.name , name);
strcpy(pack.passwd , "1");
if(send(sfd, &pack, sizeof(pack), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
//printf("发送成功\n");
return 0;
}
int do_search(int sfd, const char* name)
{
package pack;
char world[128];
char chinese[128] = "";
pack.type = 'S';
int row = 0;
strcpy(pack.name , name);
strcpy(pack.passwd , "1");
if(send(sfd, &pack, sizeof(pack), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
//printf("发送搜索请求成功\n");
printf("请输入要查找的单词:");
fgets(world, sizeof(world), stdin);
if(send(sfd, world, sizeof(world), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
//printf("send ----%s----\n", world);
if(recv(sfd, &row, sizeof(row), 0) < 0)
{
perror("recv");
ERR_MSG();
return -1;
}
//printf("recv from : %d\n", row);
int i = 0;
for(i=0; i<row; i++)
{
if(recv(sfd, &chinese, sizeof(chinese), 0) < 0)
{
perror("recv");
ERR_MSG();
return -1;
}
printf("%s\n", chinese);
}
}
int do_history(int sfd, const char* name)
{
int row;
int i = 0;
char sndbuf[256];
package pack;
pack.type = 'H';
strcpy(pack.name , name);
strcpy(pack.passwd , "1");
if(send(sfd, &pack, sizeof(pack), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
if(recv(sfd, &row, sizeof(row), 0) < 0)
{
perror("recv");
ERR_MSG();
return -1;
}
//printf("row = %d\n", row);
for(i=1; i<row+1; i++)
{
if(recv(sfd, &sndbuf, sizeof(sndbuf), 0) < 0)
{
perror("recv");
ERR_MSG();
return -1;
}
printf("%s\b\n", sndbuf);
}
}
服务器相关代码
主函数部分
#include "./inc/sqlite.h"
#include "./inc/dict_socket.h"
#include "./inc/op.h"
void* callback(void* arg);
typedef struct
{
int newfd;
struct sockaddr_in cin;
sqlite3* db;
}Msg;
int main(int argc, const char *argv[])
{
//判断参数是否正确
if(argc < 3)
{
printf("参数不正确 请按以下格式输入 ip port\n");
ERR_MSG();
return -1;
}
//数据库初始化
sqlite3 *db;
db = init_dict_sqlite(db);
int newfd = 0;
struct sockaddr_in sin;
struct sockaddr_in cin;
socklen_t addrlen = sizeof(struct sockaddr_in);
Msg msg;
//网络初始化
int sfd = init_socket(argv[1], atoi(argv[2]), &sin);
//创建多线程并发服务器
pthread_t pid;
while(1)
{
if((newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen)) < 0)
{
perror("accept");
ERR_MSG();
return -1;
}
msg.newfd = newfd;
msg.cin = cin;
msg.db = db;
//连接成功
printf("[%s %d %d] 已连接\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
//创建线程
if(pthread_create(&pid, NULL, callback, &msg) < 0)
{
perror("pthread_create");
ERR_MSG();
return -1;
}
}
close(sfd);
return 0;
}
void* callback(void* arg)
{
pthread_detach(pthread_self());
package pack;
Msg* msg = (Msg*)arg;
int newfd = msg->newfd;
sqlite3* db = msg->db;
struct sockaddr_in cin = msg->cin;
int rett = -1;
while(1)
{
if((rett = recv(newfd, &pack, sizeof(pack), 0)) < 0)
{
perror("recv");
ERR_MSG();
return NULL;
}
printf("接收成功\n");
if(rett == 0)
{
do_quit(db, pack.name);
close(newfd);
printf("客户端已退出\n");
return NULL;
}
printf("type = %c name = %s passwd = %s\n", pack.type, pack.name, pack.passwd);
printf("[%s %d %d]\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
switch(pack.type)
{
case 'R':
do_register(db, newfd, &pack);
break;
case 'L':
do_login(db, newfd, &pack);
break;
case 'Q':
do_quit(db, pack.name);
break;
case 'S':
do_search(db, newfd, &pack);
break;
case 'H':
do_history(db, newfd, pack.name);
break;
default:
break;
}
}
pthread_exit(NULL);
服务器网络相关代码
#include "../inc/op.h"
#include "../inc/dict_socket.h"
#include "../inc/sqlite.h"
int init_socket(const char* ip, short port, struct sockaddr_in* sin)
{
//创建流式套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd < 0)
{
perror("socket");
ERR_MSG();
return -1;
}
//允许端口快速重用
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("setsockopt");
ERR_MSG();
return -1;
}
//填充地址信息结构体 绑定
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
sin->sin_addr.s_addr = inet_addr(ip);
if(bind(sfd, (struct sockaddr*)sin, sizeof(struct sockaddr_in)) < 0)
{
perror("bind");
ERR_MSG();
return -1;
}
//监听
if(listen(sfd, 10) < 0)
{
perror("listen");
ERR_MSG();
return -1;
}
printf("网络初始化成功\n");
printf("正在监听中\n");
return sfd;
}
服务器数据库相关代码
#include "../inc/op.h"
#include "../inc/dict_socket.h"
#include "../inc/sqlite.h"
sqlite3* init_dict_sqlite(sqlite3* db)
{
char sql[128] = "";
char buf[64];
char english[32] = "";
char chinese[32] = "";
//打开词典文件
FILE* pf = fopen("./dict.txt", "r");
if(NULL == pf)
{
perror("fopen");
return NULL;
}
printf("字典文件打开成功\n");
//打开数据库
if(sqlite3_open("dict.db", &db) != SQLITE_OK)
{
printf("open sqlite3 %s\n", sqlite3_errmsg(db));
printf("%d\n", sqlite3_errcode(db));
ERR_MSG();
return NULL;
}
printf("数据库打开成功\n");
//创建字典表格
char *errmsg = NULL;
strcpy(sql, "create table dict (english1 char , chinese1 char)");
int ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if(ret != SQLITE_OK)
{
//如果表已经存在
if(ret == 1)
{
printf("表格已经存在\n");
//创建用户表格
create_user_form(db);
create_history_form(db);
return db;
}
ERR_MSG();
return NULL;
}
printf("创建字典表格成功\n");
while(fgets(buf, sizeof(buf), pf) > 0)
{
buf[strlen(buf) - 1] = 0;
sscanf(buf, "%s %[^\n]", english, chinese);
insert_sqlite(db, english, chinese);
bzero(english, sizeof(english));
bzero(chinese, sizeof(chinese));
}
printf("字典初始化成功\n");
create_user_form(db);
create_history_form(db);
return db;
}
int insert_sqlite(sqlite3* db, char* english, char* chinese)
{
char sql[128] = "";
char *errmsg = NULL;
sprintf(sql,"insert into dict values (\"%s\", \"%s\");", english, chinese);
//printf("sql : %s\n", sql);
//sqlite3_exec
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec: %s\n", errmsg);
printf("%s %s\n", chinese, english);
ERR_MSG();
return -1;
}
//printf("插入成功\n");
return 0;
}
int create_user_form(sqlite3* db)
{
char sql[128] = "";
char *errmsg = NULL;
//创建用户表格
strcpy(sql, "create table if not exists user (name char primary key, passwd char, flag char)");
int ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if(ret != SQLITE_OK)
{
printf("创建用户表格失败:%s\n", errmsg);
ERR_MSG();
return -1;
}
printf("创建用户表格成功\n");
bzero(sql, sizeof(sql));
strcpy(sql,"insert into user values (\"zhangsan\", \"1234\", \"Y\");");
//printf("%s\n", sql);
#ifdef TEST
ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if(ret != SQLITE_OK)
{
printf("插入失败:%s\n", errmsg);
ERR_MSG();
return -1;
}
printf("用户插入成功\n");
#endif
return 0;
}
int create_history_form(sqlite3* db)
{
char sql[128] = "";
char *errmsg = NULL;
//创建用户表格
strcpy(sql, "create table if not exists history (name char , world char, chinese char, time char)");
int ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if(ret != SQLITE_OK)
{
printf("创建历史记录表格失败:%s\n",errmsg);
ERR_MSG();
return -1;
}
printf("创建历史记录表格成功\n");
bzero(sql, sizeof(sql));
strcpy(sql,"insert into history values (\"zhangsan\", \"1234\", \"15235465\");");
#ifdef TEST
//printf("%s\n", sql);
ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if(ret != SQLITE_OK)
{
printf("历史记录插入失败:%s\n", errmsg);
ERR_MSG();
return -1;
}
printf("历史记录插入成功\n");
#endif
return 0;
}
服务器操作相关代码
#include "../inc/op.h"
#include "../inc/dict_socket.h"
#include "../inc/sqlite.h"
//查找数据库 user 表中是否有该name
static int do_search_name(sqlite3* db, char* name,int* row, int* col, char*** presult)
{
char sql[128] = "select * from user where name=";
sprintf(sql,"%s\"%s\"", sql,name);
printf("%s\n", sql);
char *errmsg = NULL;
if(sqlite3_get_table(db, sql, presult, row, col, &errmsg) != SQLITE_OK)
{
printf("sqlite3_get_table: %s\n", errmsg);
return -1;
}
return -1;
}
/*
*用户注册
*判断表中是否有该用户
*当用户存在时,提示注册失败
*用户不存在, 加入数据库,user表中, 标志位默认置位‘N’ 未登录状态
*/
int do_register(sqlite3* db, int newfd, package* pack)
{
char sql[128] = "";
char* errmsg = NULL;
char** a = NULL;
int row = 0;
int col = 0;
char buf[8] = "";
//printf("__%d__name__%s__\n", __LINE__,pack->name);
//printf("__%d__passwd__%s__\n", __LINE__,pack->passwd);
//先查看user表中是否有该用户
do_search_name(db, pack->name, &row, &col, &a);
printf("row = %d col = %d\n", row, col);
if(0 != row)
{
printf("用户已存在\n");
strcpy(buf, "exist");
if(send(newfd, buf, sizeof(buf), 0) < 0)
{
perror("send");
return -1;
}
return -1;
}
bzero(sql, sizeof(sql));
sprintf(sql, "insert into user values ('%s', '%s', '%c')", pack->name, pack->passwd, 'N');
//ERR_MSG();
//printf("%s\n", sql);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite3_exec: %s\n", errmsg);
ERR_MSG();
return -1;
}
bzero(buf, sizeof(buf));
strcpy(buf, "success");
if(send(newfd, buf, sizeof(buf), 0) < 0)
{
perror("send");
return -1;
}
return -1;
return 0;
}
int do_login(sqlite3* db, int newfd, package* pack)
{
char sql[128] = "";
char* errmsg = NULL;
char buf[8] = "";
int row = 0;
int col = 0;
char **presult;
//查看user中是否有该用户
do_search_name(db, pack->name, &row, &col, &presult);
if(1 != row)
{
strcpy(buf, "notname");
if(send(newfd, buf, sizeof(buf), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
printf("用户不存在\n");
return -1;
}
ERR_MSG();
if(presult != NULL)
{
int i = 0;
for(i=0; i<(row+1)*col; i++)
{
printf("%d %-10s", i, presult[i]);
}
}
printf("\n");
if(strcmp(presult[4], pack->passwd)==0)
{
printf("密码一致\n");
if(strncmp(presult[5], "N",1)==0)
{
printf("无重复登录\n");
strcpy(buf, "success");
if(send(newfd, buf, sizeof(buf), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
bzero(sql, sizeof(sql));
sprintf(sql, "update user set flag='Y' where name='%s';", pack->name);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
ERR_MSG();
printf("sqlite3_exec %s\n", errmsg);
return 0;
}
return 0;
}
strcpy(buf, "chongfu");
if(send(newfd, buf, sizeof(buf), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
printf("重复登录\n");
return -1;
}
strcpy(buf, "notpw");
if(send(newfd, buf, sizeof(buf), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
printf("密码不一致\n");
return 0;
}
static int do_search_world(sqlite3* db, char* english, int* row, int* col, char*** presult)
{
char sql[128] = "select * from dict where english1=";
sprintf(sql,"%s\"%s\"", sql, english);
printf("%s\n", sql);
char *errmsg = NULL;
if(sqlite3_get_table(db, sql, presult, row, col, &errmsg) != SQLITE_OK)
{
printf("sqlite3_get_table: %s\n", errmsg);
return -1;
}
return -1;
}
static int save_history(sqlite3* db, char* name, char* english, char* chinese, char*timebuf)
{
char* errmsg = "";
char sql[128] = "insert into history values ";
sprintf(sql,"%s('%s','%s','%s','%s');", sql, name, english, chinese, timebuf);
printf("___%s____\n", sql);
int ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if(ret != SQLITE_OK)
{
printf("创建用户表格失败:%s\n", errmsg);
ERR_MSG();
return -1;
}
return 0;
}
int do_search(sqlite3* db, int newfd, package* pack)
{
char sql[128] = "";
char* errmsg = NULL;
char buf[8] = "";
int row = 0;
int col = 0;
char **presult;
char chinese[128] = "";
char english[128] = "";
time_t result;
char timebuf[128] = "";
ERR_MSG();
printf("___%s___\n", pack->name);
if(recv(newfd, english, sizeof(english), 0) < 0)
{
perror("newfd");
ERR_MSG();
return -1;
}
english[strlen(english)-1] = 0;
printf("_____________%s____\n", english);
do_search_world(db, english, &row, &col, &presult);
int i = 0;
for(i=2; i<(row+1)*col; i++)
{
printf("__%s__%d__%-10s",__FILE__,__LINE__, presult[i]);
}
printf("%d\n", row);
if(send(newfd, &row, sizeof(row), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
for(i=0; i<row; i++)
{
//sleep(2);
if(send(newfd, presult[2*i+3], 128, 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
ERR_MSG();
printf("-send------%s--------\n", presult[2*i+3]);
result = time(NULL);
strcpy(timebuf,asctime(localtime(&result)));
ERR_MSG();
printf("-------%s____---\n", timebuf);
//保存历史记录
save_history(db, pack->name, english, presult[2*i+3], timebuf);
}
}
static int do_search_history(sqlite3* db, char* name, int* row, int* col, char*** presult)
{
char sql[128] = "select * from history where name=";
sprintf(sql,"%s\"%s\"", sql, name);
printf("%s\n", sql);
char *errmsg = NULL;
if(sqlite3_get_table(db, sql, presult, row, col, &errmsg) != SQLITE_OK)
{
printf("sqlite3_get_table: %s\n", errmsg);
return -1;
}
return -1;
}
int do_history(sqlite3* db, int newfd, char* name)
{
char sql[128] = "";
char* errmsg = NULL;
char buf[8] = "";
int row = 0;
int col = 0;
int i = 0;
char **presult;
do_search_history(db, name, &row, &col, &presult);
if(send(newfd, &row, sizeof(row), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
if(0 == row)
{
strcpy(buf, "no");
if(send(newfd, buf, sizeof(buf), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
printf("无记录\n");
return -1;
}
char sndbuf[256] = "";
for(i=1; i<row+1; i++)
{
sprintf(sndbuf, "%s %s %s %s", presult[i*col+0], presult[i*col+1], presult[col*i+2], presult[col*i+3]);
sndbuf[strlen(sndbuf)-1] = 0;
if(send(newfd, sndbuf, sizeof(sndbuf), 0) < 0)
{
perror("send");
ERR_MSG();
return -1;
}
printf("send %s_________\n", sndbuf);
}
printf("11111111111111111111111111\n");
}
int do_quit(sqlite3* db, char* name)
{
printf("111111111111111111111111\n");
char* errmsg = NULL;
char sql[128] = "update user set flag=\"N\" where name=";
sprintf(sql, "%s\'%s\'", sql, name);
printf("%s\n", sql);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
ERR_MSG();
printf("sqlite3_exec %s\n", errmsg);
return 0;
}
printf("name is quit\n");
return -1;
}