项目要求:
- 登录注册功能,不能重复登录,重复注册。用户信息也存储在数据库中。
- 单词查询功能
- 历史记录功能,存储单词,意思,以及查询时间,存储在数据库
- 基于TCP,支持多客户端连接(多进程、多线程、多路复用)
- 采用数据库保存用户信息与历史记录
- 将dict.txt的数据导入到数据库中保存。
- 返回上级、按下ctrl+c退出客户端后,该客户端退出登录
server.c
int do_register(int sockfd, MSG_T *msg, sqlite3 *db);
int do_login(int sockfd, MSG_T *msg, sqlite3 *db);
int do_searchword(MSG_T *msg, char *word);
int do_query(int sockfd, MSG_T *msg, sqlite3 *db);
int history_callback(void *arg, int colCount, char **colValue, char **colName);
int do_history(int sockfd, MSG_T *msg, sqlite3 *db);
int do_client(int acceptfd, sqlite3 *db);
int main(int argc, const char *argv[])
{
int sockfd, acceptfd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
char ip_addr[16]; //存放ip地址
sqlite3 *db = NULL;
char *errmsg = NULL;
char sql[1024] = "";
pid_t pid;
//数据库操作
if (sqlite3_open(DATABASE, &db) != SQLITE_OK) //打开数据库
{
printf("%s\n", sqlite3_errmsg(db));
return -1;
}
sprintf(sql, "create table if not exists user(name text primary key, passwd text);");
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK) //创建用户表
{
printf("%s\n", errmsg);
return -1;
}
memset(sql, 0, sizeof(sql));
sprintf(sql, "create table if not exists record(name text, date text, word text);");
if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK) //创建记录表
{
printf("%s\n", errmsg);
return -1;
}
// 申请socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("fail to socket\n");
return -1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("192.168.3.107");
server_addr.sin_port = htons(8888);
bzero(&(server_addr.sin_zero), sizeof(server_addr.sin_zero));
//绑定套接字
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0)
{
perror("bind error\n");
return -1;
}
//将套接字设为监听模式
if (listen(sockfd, 5) < 0)
{
perror("listen error\n");
exit(1);
}
printf("listen success.\n");
//处理僵尸进程
signal(SIGCHLD, SIG_IGN);
while (1)
{
//接收客户端的连接请求
if ((acceptfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen)) < 0)
{
perror("accept error\n");
return -1;
}
if (inet_ntop(AF_INET, &client_addr.sin_addr, ip_addr, addrlen) < 0)
{
perror("inet_ntop error\n");
return -1;
}
printf("client(%s:%d) is connected!\n", ip_addr, htons(client_addr.sin_port));
//创建子进程
if ((pid = fork()) < 0)
{
perror("fork error\n");
return -1;
}
else if (pid == 0) //子进程,处理客户端请求
{
close(sockfd);
do_client(acceptfd, db);
}
else //父进程,用来接收客户端的连接请求
{
close(acceptfd);
}
}
return 0;
}
client.c
int do_register(int sockfd, MSG_T *msg)
int do_login(int sockfd, MSG_T *msg)
int do_query(int sockfd, MSG_T *msg)
int do_history(int sockfd, MSG_T *msg)
int main(int argc, const char *argv[])
{
int sockfd;
struct sockaddr_in server_addr;
int input_nbr;
MSG_T send_msg;
// 申请socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket error\n");
return -1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("192.168.3.107");
server_addr.sin_port = htons(8888);
bzero(&(server_addr.sin_zero), sizeof(server_addr.sin_zero));
//连接服务器
if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) < 0)
{
perror("connect error\n");
return -1;
}
while (1)
{
printf("***********************************************\n");
printf("\t 1.注册 2.登录 3.退出 \n");
printf("***********************************************\n");
printf("请选择功能:");
scanf("%d", &input_nbr);
getchar();//回收垃圾字符
// 一级菜单
switch (input_nbr)
{
case 1:
do_register(sockfd, &send_msg);
break;
case 2:
if (do_login(sockfd, &send_msg) == 1)
{
goto _login;
}
break;
case 3:
close(sockfd);
exit(0);
break;
default:
printf("请输入正确的选项 \n");
break;
}
}
//二级菜单,登录后进行单词查询
_login:
while(1)
{
system("clear");
printf("***********************************************\n");
printf("\t 1.查询单词 2.历史查询 3.退出\n");
printf("***********************************************\n");
printf("请选择功能:");
input_nbr = 0;
scanf("%d", &input_nbr);
getchar();//回收垃圾字符
switch (input_nbr)
{
case 1:
do_query(sockfd, &send_msg);
break;
case 2:
do_history(sockfd, &send_msg);
break;
case 3:
close(sockfd);
exit(0);
break;
default:
printf("input_nbr error\n");
break;
}
}
return 0;
}