项目要求:
- 登录注册功能,不能重复登录,重复注册。用户信息也存储在数据库中。
- 单词查询功能
- 历史记录功能,存储单词,意思,以及查询时间,存储在数据库
- 基于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;}// 申请socketif ((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;// 申请socketif ((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;
}