基于TCP的在线词典系统(分阶段实现)(阻塞io和多路io复用(select)实现)

1.功能说明

一共四个功能:

                注册

                登录

                查询单词

                查询历史记录

单词和解释保存在文件中,单词和解释只占一行,

一行最多300个字节,单词和解释之间至少有一个空格。

2.功能演示

3、分阶段完成各个功能

3.1 完成服务器和客户端的连接

service.c

#include <head.h>int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <port> <ip>\n", argv[0]);exit(-1);}// 创建套接字int sockfd;struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("sockfd error");exit(-1);}// 填充服务器网络信息结构体serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);memset(&clientaddr, 0, sizeof(clientaddr));// 绑定if (-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("bind error");exit(-1);}// 监听printf("%d\n", sockfd);if (listen(sockfd, 5) < 0){perror("fail to listen");exit(-1);}int acceptfd;while (1){acceptfd = 0;printf("阻塞等待客户端连接...\n");if (-1 == (acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len))){perror("accept errror");exit(-1);}printf("111111111\n");printf("客户端[%s][%d]连接成功...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));pid_t pid;pid = fork();if (pid == -1){perror("fork error");exit(-1);}else if (pid == 0){// 子进程}else{// 父进程wait(NULL);}}return 0;
}

client.c

#include <head.h>
void print_menu();
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <ip> <port>\n", argv[1]);exit(-1);}// 创建套接字int sockfd;if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0))){perror("socket error");exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len = sizeof(serveraddr);serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));if (-1 == connect(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("connect error");exit(-1);}printf("连接服务器成功...\n");while (1){print_menu();sleep(10);}return 0;
}
void print_menu()
{printf("-------------------------------------\n");printf("|    1.regist     2.login     3.quit|\n");printf("-------------------------------------\n");return;
}

3.2 新增完成注册和退出功能

service.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define H 4
#define DATABASE "test.db"
typedef struct _MSG
{int type;char name[32];char data[128];
} msg_t;
void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db);
void do_quit(msg_t *msg, int acceptfd, sqlite3 *my_db);
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <port> <ip>\n", argv[0]);exit(-1);}// 创建数据库sqlite3 *my_db;if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)){printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}// 创建套接字int sockfd;struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("sockfd error");exit(-1);}// 填充服务器网络信息结构体serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);memset(&clientaddr, 0, sizeof(clientaddr));// 绑定if (-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("bind error");exit(-1);}// 监听printf("%d\n", sockfd);if (listen(sockfd, 5) < 0){perror("fail to listen");exit(-1);}int acceptfd;msg_t msg;while (1){acceptfd = 0;printf("阻塞等待客户端连接...\n");if (-1 == (acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len))){perror("accept errror");exit(-1);}printf("111111111\n");printf("客户端[%s][%d]连接成功...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));pid_t pid;pid = fork();if (pid == -1){perror("fork error");exit(-1);}else if (pid == 0){while (1){if (-1 == recv(acceptfd, &msg, sizeof(msg), 0)){perror("recv error");exit(-1);}// printf("msg_type = %d\n", msg.type);// printf("msg.name = %s\n", msg.name);// printf("msg.data = %s\n", msg.data);switch (msg.type){case R:do_regist(&msg, acceptfd, my_db);break;case L:break;case Q:printf("客户端[%s][%d]退出了...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));do_quit(&msg, acceptfd, my_db);break;case H:break;}}// 子进程}else{// 父进程close(acceptfd);wait(NULL);}}return 0;
}
void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char sqlstr[512] = {0};char *errmsg;// printf("msg]msg.type = %d\n", msg->type);// printf("[msg]msg.name = %s\n", msg->name);// printf("[msg]msg.data = %s\n", msg->data);sprintf(sqlstr, "insert into user values('%s','%s')", msg->name, msg->data);// printf("[do_regist]sqlstr = %s\n", sqlstr);if (sqlite3_exec(my_db, sqlstr, NULL, NULL, &errmsg) != SQLITE_OK){printf("errmsg = %s\n", errmsg);sprintf(msg->data, "user already exit,regist fail");}else{strcpy(msg->data, "OK");}// printf("[do_regist_send]msg.type = %d\n", msg->type);// printf("[do_regist_send]msg.name = %s\n", msg->name);// printf("[do_regist_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return;
}
void do_quit(msg_t *msg, int acceptfd, sqlite3 *my_db)
{exit(-1);
}

client.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define H 4
#define DATABASE "test.db"
typedef struct _MSG
{int type;char name[32];char data[128];
} msg_t;
void print_menu();
void login_user(msg_t msg, int sockfd);
void exit_system(msg_t *msg, int sockfd);
int regist_user(msg_t *msg, int sockfd);
int check_user(msg_t msg, int sockfd);
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <ip> <port>\n", argv[1]);exit(-1);}// 创建套接字sqlite3 *my_db;if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)){printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}int sockfd;if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0))){perror("socket error");exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len = sizeof(serveraddr);serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));int choose = 0;msg_t msg;if (-1 == connect(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("connect error");exit(-1);}printf("连接服务器成功...\n");while (1){print_menu();printf("请输入您的选择:");scanf("%d", &choose);switch (choose){case R:regist_user(&msg, sockfd);case L:login_user(msg, sockfd);break;case Q:exit_system(&msg, sockfd);break;}}return 0;
}
void print_menu()
{printf("-------------------------------------\n");printf("|    1.regist     2.login     3.quit|\n");printf("-------------------------------------\n");return;
}
void exit_system(msg_t *msg, int sockfd)
{system("clear");msg->type = Q;if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}close(sockfd);printf("欢迎下次使用基于TCP的在线词典系统...\n");exit(-1);
}
int check_user(msg_t msg, int sockfd)
{printf("[check_user_send]msg.type = %d\n", msg.type);printf("[check_user_send]msg.name = %s\n", msg.name);printf("[check_user_send]msg.data = %s\n", msg.data);if (-1 == send(sockfd, &msg, sizeof(msg), 0)){perror("send error");exit(-1);}memset(&msg, 0, sizeof(msg));if (-1 == recv(sockfd, &msg, sizeof(msg), 0)){perror("recv error");exit(-1);}printf("[check_user_recv]msg.type = %d\n", msg.type);printf("[check_user_recv]msg.name = %s\n", msg.name);printf("[check_user_recv]msg.data = %s\n", msg.data);if (strcmp(msg.data, "user already exit,regist fail") == 0){return -1;}else{return 0;}
}
int regist_user(msg_t *msg, int sockfd)
{memset(msg, 0, sizeof(msg_t));msg->type = R;printf("[注册]请输入用户名:");scanf("%s", msg->name);printf("[注册]请输入密码:");scanf("%s", msg->data);// printf("[regist_user]msg.type = %d\n", msg->type);// printf("[regist_user]msg.name = %s\n", msg->name);// printf("[regist_user]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}// printf("[regist_send]msg.type = %d\n", msg->type);// printf("[regist_send]msg.name = %s\n", msg->name);// printf("[regist_send]msg.data = %s\n", msg->data);memset(msg, 0, sizeof(msg));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}// printf("[regist_recv]msg.type = %d\n", msg->type);// printf("[regist_recv]msg.name = %s\n", msg->name);// printf("[regist_recv]msg.data = %s\n", msg->data);if (strncmp(msg->data, "OK", 3) == 0){printf("注册成功...\n");return 1;}printf("用户名已存在,注册失败...\n");return 0;
}
void login_user(msg_t msg, int sockfd)
{return;
}

结果图:

3.3 新增完成登录功能(密码和用户名都正确才能登录成功)

service.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define S 4
#define H 5
#define E 6
#define DATABASE "test.db"
#define FILEPATH "./dict.txt"
typedef struct _MSG
{int type;char name[256];char data[128];
} msg_t;
void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db);
void do_quit(msg_t *msg, int acceptfd, sqlite3 *my_db);
int do_login(msg_t *msg, int acceptfd, sqlite3 *my_db);
int do_search(msg_t *msg, int acceptfd, sqlite3 *my_db, FILE *fp);
void getdata(char *data);
void do_history(msg_t *msg, int acceptfd, sqlite3 *my_db);
int flafs = 0; // 全局变量 使得系统只有在第一次查询时 打开一次文件,第二次不用再打开
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <port> <ip>\n", argv[0]);exit(-1);}// 创建数据库sqlite3 *my_db;if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)){printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}FILE *fp; // 传入do_search();// 创建套接字int sockfd;struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("sockfd error");exit(-1);}// 填充服务器网络信息结构体serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);memset(&clientaddr, 0, sizeof(clientaddr));// 绑定if (-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("bind error");exit(-1);}// 监听printf("%d\n", sockfd);if (listen(sockfd, 5) < 0){perror("fail to listen");exit(-1);}int acceptfd;msg_t msg;while (1){acceptfd = 0;printf("阻塞等待客户端连接...\n");if (-1 == (acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len))){perror("accept errror");exit(-1);}printf("111111111\n");printf("客户端[%s][%d]连接成功...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));pid_t pid;pid = fork();if (pid == -1){perror("fork error");exit(-1);}else if (pid == 0){while (1){if (-1 == recv(acceptfd, &msg, sizeof(msg), 0)){perror("recv error");exit(-1);}printf("[main]msg_type = %d\n", msg.type);printf("[main]msg.name = %s\n", msg.name);printf("[main]msg.data = %s\n", msg.data);switch (msg.type){case R:do_regist(&msg, acceptfd, my_db);break;case L:do_login(&msg, acceptfd, my_db);break;case Q:printf("客户端[%s][%d]退出了...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));do_quit(&msg, acceptfd, my_db);break;case S:do_search(&msg, acceptfd, my_db, fp);break;case H:do_history(&msg, acceptfd, my_db);break;case E:break;}}// 子进程}else{// 父进程close(acceptfd);wait(NULL);}}return 0;
}
void getdata(char *data)
{time_t t;struct tm *tp;time(&t);tp = localtime(&t);sprintf(data, "%d-%d-%d %d:%d:%d", 1900 + tp->tm_year, 1 + tp->tm_mon, tp->tm_mday,tp->tm_hour, tp->tm_min, tp->tm_sec);
}
void do_history(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char databuff[128] = {0};getdata(databuff);memset(msg, 0, sizeof(msg_t));msg->type = H;char sqlbuff[256] = {0};sprintf(sqlbuff, "select * from record");return;
}
int do_search(msg_t *msg, int acceptfd, sqlite3 *my_db, FILE *fp)
{char buff[256] = {0};printf("要查询的单词为:%s\n", msg->data);int word_len = 0;char *p = NULL;word_len = strlen(msg->data);printf("要查询的单词%s的长度%d\n", msg->data, word_len);// if (flafs == 0)// {// printf("第一次查询,单词文件打开中...\n");if (NULL == (fp = fopen(FILEPATH, "r"))){printf("[第一次]打开单词文件失败...\n");strcpy(msg->data, "open error or EOF");if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}}p = NULL;fgets(buff, sizeof(buff), fp);while (strncmp(msg->data, buff, word_len) != 0){if (fgets(buff, sizeof(buff), fp) == NULL){strcpy(msg->data, "NO_WORLD");// printf("11111111111111111\n");printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}}printf("[strncmp]msg.data = %s\n", msg->data);printf("[strncmp]buff=%s\n", buff);p = buff;p += word_len;if (*p != ' '){// printf("22222222222\n");strcpy(msg->data, "NO_WORLD");printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}while (*p == ' '){p++;}strcpy(msg->data, p);printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}fclose(fp);return 1;
}void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char sqlstr[512] = {0};char *errmsg;printf("[msg]msg.type = %d\n", msg->type);printf("[msg]msg.name = %s\n", msg->name);printf("[msg]msg.data = %s\n", msg->data);sprintf(sqlstr, "insert into user values('%s','%s')", msg->name, msg->data);printf("[do_regist]sqlstr = %s\n", sqlstr);if (sqlite3_exec(my_db, sqlstr, NULL, NULL, &errmsg) != SQLITE_OK){printf("errmsg = %s\n", errmsg);strcpy(msg->data, "user already exit,regist fail");}else{strcpy(msg->data, "OK");}printf("[do_regist_send]msg.type = %d\n", msg->type);printf("[do_regist_send]msg.name = %s\n", msg->name);printf("[do_regist_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return;
}
// int callback(void *arg, int ncolumn, char **f_value, char **f_name)
// {
//     int i = 0;
//     int flag = 0;
//     msg_t *msg_callback = (msg_t *)arg;
//     printf("[msg_callbackmsg_callback.type = %d\n", msg_callback->type);
//     printf("[msg_callback]msg_callback.name = %s\n", msg_callback->name);
//     printf("[msg_callback]msg_callback.data = %s\n", msg_callback->data);
//     if (0 == flag)
//     {
//         // 先打印字段名
//         for (i = 0; i < ncolumn; i++)
//         {
//             // strcpy(msg_callback->data, "user or passwd ereror");
//             printf("\n");
//         }
//         flag = 1;
//     }
//     // 再打印字段的值
//     for (i = 0; i < ncolumn; i++)
//     {
//         if ((f_value[i] != msg_callback->name) || (f_value[i] != msg_callback->data))
//         {
//             strcpy(msg_callback->data, "user or passwd ereror");
//         }
//         else
//         {
//             strcpy(msg_callback->data, "OK");
//         }
//     }
//     return 0; // 这里的回调函数要求必须有返回值 如果没有会报错 query aborted
// }int do_login(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char sqlstr[512] = {0};printf("[msg]msg.type = %d\n", msg->type);printf("[msg]msg.name = %s\n", msg->name);printf("[msg]msg.data = %s\n", msg->data);sprintf(sqlstr, "select * from user where name='%s' and passwd='%s'", msg->name, msg->data);printf("[do_login]sqlstr = %s\n", sqlstr);char *errmsg, **result;int nrow, ncolumn;// 通过sqlite3_get_table函数查询记录是否存在sprintf(sqlstr, "select * from user where name = '%s' and passwd = '%s'", msg->name, msg->data);if (sqlite3_get_table(my_db, sqlstr, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK){printf("error : %s\n", errmsg);}// 通过nrow参数判断是否能够查询到疾记录,如果值为0,则查询不到,如果值为非0,则查询到if (nrow == 0){strcpy(msg->data, "user or passwd ereror");printf("[do_login_send]msg.type = %d\n", msg->type);printf("[do_login_send]msg.name = %s\n", msg->name);printf("[do_login_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}else{strncpy(msg->data, "OK", 256);printf("[do_login_send]msg.type = %d\n", msg->type);printf("[do_login_send]msg.name = %s\n", msg->name);printf("[do_login_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 1;}
}
void do_quit(msg_t *msg, int acceptfd, sqlite3 *my_db)
{exit(-1);
}

client.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define S 4
#define H 5
#define E 6
#define DATABASE "test.db"
#define FILEPATH "./dict.txt"
typedef struct _MSG
{int type;char name[256];char data[128];
} msg_t;
void print_menu();
int login_user(msg_t *msg, int sockfd, sqlite3 *my_db);
void exit_system(msg_t *msg, int sockfd);
int regist_user(msg_t *msg, int sockfd);
int check_user(msg_t msg, int sockfd);
int search_world(msg_t *msg, int sockfd, sqlite3 *my_db);
int exit_search(msg_t *msg, int sockfd);
void query_menu();
void printf_history(msg_t *msg, int sockfd, sqlite3 *my_db);
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <ip> <port>\n", argv[1]);exit(-1);}// 创建套接字sqlite3 *my_db;if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)){printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}int sockfd;if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0))){perror("socket error");exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len = sizeof(serveraddr);serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));int choose = 0;msg_t msg;if (-1 == connect(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("connect error");exit(-1);}printf("连接服务器成功...\n");
NEXT2:while (1){print_menu();printf("请输入您的选择(1-3):");scanf("%d", &choose);switch (choose){case R:regist_user(&msg, sockfd);break;case L:if (login_user(&msg, sockfd, my_db) == 1){goto NEXT;}break;case Q:close(sockfd);// system("clear");printf("欢迎下次使用基于TCP的在线词典系统...\n");exit(0);}}
NEXT:while (1){// system("clear");query_menu();printf("请输入您的选择(4-6):");scanf("%d", &choose);switch (choose){case S:search_world(&msg, sockfd, my_db);break;case H:printf_history(&msg, sockfd, my_db);break;case E:goto NEXT2;break;}}return 0;
}
void print_menu()
{printf("-------------------------------------\n");printf("|  1.regist     2.login     3.quit  |\n");printf("-------------------------------------\n");return;
}
void query_menu()
{printf("-------------------------------------\n");printf("|  4.search    5.history    6.quit  |\n");printf("-------------------------------------\n");return;
}
void exit_system(msg_t *msg, int sockfd)
{system("clear");msg->type = Q;if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}close(sockfd);printf("欢迎下次使用基于TCP的在线词典系统...\n");exit(-1);
}void printf_history(msg_t *msg, int sockfd, sqlite3 *my_db)
{// memset(msg, 0, sizeof(msg_t));// printf("[printf_history]msg.type = %d\n", msg->type);// printf("[printf_history]msg.name = %s\n", msg->name); // 单词// printf("[printf_history]msg.data = %s\n", msg->data); // OKmsg->type = H;printf("<---历史记录如下--->\n");while (1){if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}if (strcmp(msg->data, "***OVER***") == 0){break;}printf("%s:%s\n", msg->name, msg->data);}return;
}
int regist_user(msg_t *msg, int sockfd)
{memset(msg, 0, sizeof(msg_t));msg->type = R;printf("[注册]请输入用户名:");scanf("%s", msg->name);printf("[注册]请输入密码:");scanf("%s", msg->data);// printf("[regist_user]msg.type = %d\n", msg->type);// printf("[regist_user]msg.name = %s\n", msg->name);// printf("[regist_user]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}// printf("[regist_send]msg.type = %d\n", msg->type);// printf("[regist_send]msg.name = %s\n", msg->name);// printf("[regist_send]msg.data = %s\n", msg->data);memset(msg, 0, sizeof(msg));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}// printf("[regist_recv]msg.type = %d\n", msg->type);// printf("[regist_recv]msg.name = %s\n", msg->name);// printf("[regist_recv]msg.data = %s\n", msg->data);if (strcmp(msg->data, "OK") == 0){printf("注册成功...\n");return 1;}printf("用户名已存在,注册失败...\n");return 0;
}
int login_user(msg_t *msg, int sockfd, sqlite3 *my_db)
{memset(msg, 0, sizeof(msg_t));msg->type = L;printf("[登录]请输入用户名:");scanf("%s", msg->name);printf("[登录]请输入密码:");scanf("%s", msg->data);// printf("[login_user]msg.type = %d\n", msg->type);// printf("[login_user]msg.name = %s\n", msg->name);// printf("[login_user]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");return -1;}// printf("[login_user_send]msg.type = %d\n", msg->type);// printf("[login_user_send]msg.name = %s\n", msg->name);// printf("[login_user_send]msg.data = %s\n", msg->data);// memset(msg, 0, sizeof(msg_t));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");return -1;}// printf("[login_user_recv]msg.type = %d\n", msg->type);// printf("[login_user_recv]msg.name = %s\n", msg->name);// printf("[login_user_recv]msg.data = %s\n", msg->data);if (strcmp(msg->data, "OK") == 0){printf("登录成功...\n");return 1;}printf("用户名或密码错误...\n");return 0;
}
// int exit_search(msg_t *msg, int sockfd)
// {
//     return 0;
// }
int search_world(msg_t *msg, int sockfd, sqlite3 *my_db)
{// msg->type = S;while (1){// memset(msg, 0, sizeof(msg_t));msg->type = S;printf("[查询]请输入要查询的单词(按#退出):");scanf("%s", msg->data);if (msg->data[strlen(msg->data) - 1] == '\n'){msg->data[strlen(msg->data) - 1] = '\0';}// printf("[scanf]msg->name = %s\n", msg->name);if (strcmp(msg->data, "#") == 0){printf("你主动退出了查单词功能...\n");break;}// printf("[do_search_send]msg.type = %d\n", msg->type);// printf("[do_search_send]msg.name = %s\n", msg->name);// printf("[do_search_send]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}memset(msg, 0, sizeof(msg));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}// printf("[do_search_recv]msg.type = %d\n", msg->type);// printf("[do_search_recv]msg.name = %s\n", msg->name);// printf("[do_search_recv]msg.data = %s\n", msg->data);if (strncmp(msg->data, "NO_WORLD", 8) == 0){printf("[*****没有此单词*****]...\n");// return 0;}else{printf("[*****解释*****]:%s", msg->data);}}return 0;
}int check_user(msg_t msg, int sockfd)
{// printf("[check_user_send]msg.type = %d\n", msg.type);// printf("[check_user_send]msg.name = %s\n", msg.name);// printf("[check_user_send]msg.data = %s\n", msg.data);if (-1 == send(sockfd, &msg, sizeof(msg), 0)){perror("send error");exit(-1);}memset(&msg, 0, sizeof(msg));if (-1 == recv(sockfd, &msg, sizeof(msg), 0)){perror("recv error");exit(-1);}// printf("[check_user_recv]msg.type = %d\n", msg.type);// printf("[check_user_recv]msg.name = %s\n", msg.name);// printf("[check_user_recv]msg.data = %s\n", msg.data);if (strcmp(msg.data, "user already exit,regist fail") == 0){return -1;}else{return 0;}
}

运行结果图

 

3.4 完成查询单词功能(search)

单词文件

链接:https://pan.baidu.com/s/17qgZZpO7YyyQ0pCLYclg8A 
提取码:关注收藏后,私信获取

service.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define S 4
#define H 5
#define E 6
#define DATABASE "test.db"
#define FILEPATH "./dict.txt"
typedef struct _MSG
{int type;char name[256];char data[128];
} msg_t;
void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db);
void do_quit(msg_t *msg, int acceptfd, sqlite3 *my_db);
int do_login(msg_t *msg, int acceptfd, sqlite3 *my_db);
int do_search(msg_t *msg, int acceptfd, sqlite3 *my_db, FILE *fp);
int flafs = 0; // 全局变量 使得系统只有在第一次查询时 打开一次文件,第二次不用再打开
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <port> <ip>\n", argv[0]);exit(-1);}// 创建数据库sqlite3 *my_db;if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)){printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}FILE *fp; // 传入do_search();// 创建套接字int sockfd;struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("sockfd error");exit(-1);}// 填充服务器网络信息结构体serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);memset(&clientaddr, 0, sizeof(clientaddr));// 绑定if (-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("bind error");exit(-1);}// 监听printf("%d\n", sockfd);if (listen(sockfd, 5) < 0){perror("fail to listen");exit(-1);}int acceptfd;msg_t msg;while (1){acceptfd = 0;printf("阻塞等待客户端连接...\n");if (-1 == (acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len))){perror("accept errror");exit(-1);}printf("111111111\n");printf("客户端[%s][%d]连接成功...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));pid_t pid;pid = fork();if (pid == -1){perror("fork error");exit(-1);}else if (pid == 0){while (1){if (-1 == recv(acceptfd, &msg, sizeof(msg), 0)){perror("recv error");exit(-1);}printf("[main]msg_type = %d\n", msg.type);printf("[main]msg.name = %s\n", msg.name);printf("[main]msg.data = %s\n", msg.data);switch (msg.type){case R:do_regist(&msg, acceptfd, my_db);break;case L:do_login(&msg, acceptfd, my_db);break;case Q:printf("客户端[%s][%d]退出了...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));do_quit(&msg, acceptfd, my_db);break;case S:do_search(&msg, acceptfd, my_db, fp);break;case H:break;case E:break;}}// 子进程}else{// 父进程close(acceptfd);wait(NULL);}}return 0;
}
int do_search(msg_t *msg, int acceptfd, sqlite3 *my_db, FILE *fp)
{char buff[256] = {0};printf("要查询的单词为:%s\n", msg->name);int word_len = 0;char *p = NULL;word_len = strlen(msg->name);printf("要查询的单词%s的长度%d\n", msg->name, word_len);// if (flafs == 0)// {// printf("第一次查询,单词文件打开中...\n");if (NULL == (fp = fopen(FILEPATH, "r"))){printf("[第一次]打开单词文件失败...\n");strcpy(msg->name, "open error or EOF");strcpy(msg->data, "search error");if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}}p = NULL;fgets(buff, sizeof(buff), fp);while (strncmp(msg->name, buff, word_len) != 0){if (fgets(buff, sizeof(buff), fp) == NULL){strcpy(msg->name, "NO_WORLD");// printf("11111111111111111\n");printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}}printf("[strncmp]msg.name = %s\n", msg->name);printf("[strncmp]buff=%s\n", buff);p = buff;p += word_len;if (*p != ' '){// printf("22222222222\n");strcpy(msg->name, "NO_WORLD");printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}while (*p == ' '){p++;}strcpy(msg->name, "OK");strcpy(msg->data, p);printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}fclose(fp);return 1;
}void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char sqlstr[512] = {0};char *errmsg;printf("[msg]msg.type = %d\n", msg->type);printf("[msg]msg.name = %s\n", msg->name);printf("[msg]msg.data = %s\n", msg->data);sprintf(sqlstr, "insert into user values('%s','%s')", msg->name, msg->data);printf("[do_regist]sqlstr = %s\n", sqlstr);if (sqlite3_exec(my_db, sqlstr, NULL, NULL, &errmsg) != SQLITE_OK){printf("errmsg = %s\n", errmsg);strcpy(msg->data, "user already exit,regist fail");}else{strcpy(msg->data, "OK");}printf("[do_regist_send]msg.type = %d\n", msg->type);printf("[do_regist_send]msg.name = %s\n", msg->name);printf("[do_regist_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return;
}
// int callback(void *arg, int ncolumn, char **f_value, char **f_name)
// {
//     int i = 0;
//     int flag = 0;
//     msg_t *msg_callback = (msg_t *)arg;
//     printf("[msg_callbackmsg_callback.type = %d\n", msg_callback->type);
//     printf("[msg_callback]msg_callback.name = %s\n", msg_callback->name);
//     printf("[msg_callback]msg_callback.data = %s\n", msg_callback->data);
//     if (0 == flag)
//     {
//         // 先打印字段名
//         for (i = 0; i < ncolumn; i++)
//         {
//             // strcpy(msg_callback->data, "user or passwd ereror");
//             printf("\n");
//         }
//         flag = 1;
//     }
//     // 再打印字段的值
//     for (i = 0; i < ncolumn; i++)
//     {
//         if ((f_value[i] != msg_callback->name) || (f_value[i] != msg_callback->data))
//         {
//             strcpy(msg_callback->data, "user or passwd ereror");
//         }
//         else
//         {
//             strcpy(msg_callback->data, "OK");
//         }
//     }
//     return 0; // 这里的回调函数要求必须有返回值 如果没有会报错 query aborted
// }int do_login(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char sqlstr[512] = {0};printf("[msg]msg.type = %d\n", msg->type);printf("[msg]msg.name = %s\n", msg->name);printf("[msg]msg.data = %s\n", msg->data);sprintf(sqlstr, "select * from user where name='%s' and passwd='%s'", msg->name, msg->data);printf("[do_login]sqlstr = %s\n", sqlstr);char *errmsg, **result;int nrow, ncolumn;// 通过sqlite3_get_table函数查询记录是否存在sprintf(sqlstr, "select * from user where name = '%s' and passwd = '%s'", msg->name, msg->data);if (sqlite3_get_table(my_db, sqlstr, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK){printf("error : %s\n", errmsg);}// 通过nrow参数判断是否能够查询到疾记录,如果值为0,则查询不到,如果值为非0,则查询到if (nrow == 0){strcpy(msg->data, "user or passwd ereror");printf("[do_login_send]msg.type = %d\n", msg->type);printf("[do_login_send]msg.name = %s\n", msg->name);printf("[do_login_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}else{strncpy(msg->data, "OK", 256);printf("[do_login_send]msg.type = %d\n", msg->type);printf("[do_login_send]msg.name = %s\n", msg->name);printf("[do_login_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 1;}
}
void do_quit(msg_t *msg, int acceptfd, sqlite3 *my_db)
{exit(-1);
}

client.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define S 4
#define H 5
#define E 6
#define DATABASE "test.db"
#define FILEPATH "./dict.txt"
typedef struct _MSG
{int type;char name[256];char data[128];
} msg_t;
void print_menu();
int login_user(msg_t *msg, int sockfd, sqlite3 *my_db);
void exit_system(msg_t *msg, int sockfd);
int regist_user(msg_t *msg, int sockfd);
int check_user(msg_t msg, int sockfd);
int search_world(msg_t *msg, int sockfd, sqlite3 *my_db);
int exit_search(msg_t *msg, int sockfd);
void query_menu();
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <ip> <port>\n", argv[1]);exit(-1);}// 创建套接字sqlite3 *my_db;if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)){printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}int sockfd;if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0))){perror("socket error");exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len = sizeof(serveraddr);serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));int choose = 0;msg_t msg;if (-1 == connect(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("connect error");exit(-1);}printf("连接服务器成功...\n");
NEXT2:while (1){print_menu();printf("请输入您的选择(1-3):");scanf("%d", &choose);switch (choose){case R:regist_user(&msg, sockfd);break;case L:if (login_user(&msg, sockfd, my_db) == 1){goto NEXT;}break;case Q:close(sockfd);// system("clear");printf("欢迎下次使用基于TCP的在线词典系统...\n");exit(0);}}
NEXT:while (1){// system("clear");query_menu();printf("请输入您的选择(4-6):");scanf("%d", &choose);switch (choose){case S:search_world(&msg, sockfd, my_db);break;case H:break;case E:goto NEXT2;break;}}return 0;
}
void print_menu()
{printf("-------------------------------------\n");printf("|  1.regist     2.login     3.quit  |\n");printf("-------------------------------------\n");return;
}
void query_menu()
{printf("-------------------------------------\n");printf("|  4.search    5.history    6.quit  |\n");printf("-------------------------------------\n");return;
}
void exit_system(msg_t *msg, int sockfd)
{system("clear");msg->type = Q;if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}close(sockfd);printf("欢迎下次使用基于TCP的在线词典系统...\n");exit(-1);
}
int regist_user(msg_t *msg, int sockfd)
{memset(msg, 0, sizeof(msg_t));msg->type = R;printf("[注册]请输入用户名:");scanf("%s", msg->name);printf("[注册]请输入密码:");scanf("%s", msg->data);// printf("[regist_user]msg.type = %d\n", msg->type);// printf("[regist_user]msg.name = %s\n", msg->name);// printf("[regist_user]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}// printf("[regist_send]msg.type = %d\n", msg->type);// printf("[regist_send]msg.name = %s\n", msg->name);// printf("[regist_send]msg.data = %s\n", msg->data);memset(msg, 0, sizeof(msg));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}// printf("[regist_recv]msg.type = %d\n", msg->type);// printf("[regist_recv]msg.name = %s\n", msg->name);// printf("[regist_recv]msg.data = %s\n", msg->data);if (strcmp(msg->data, "OK") == 0){printf("注册成功...\n");return 1;}printf("用户名已存在,注册失败...\n");return 0;
}
int login_user(msg_t *msg, int sockfd, sqlite3 *my_db)
{memset(msg, 0, sizeof(msg_t));msg->type = L;printf("[登录]请输入用户名:");scanf("%s", msg->name);printf("[登录]请输入密码:");scanf("%s", msg->data);// printf("[login_user]msg.type = %d\n", msg->type);// printf("[login_user]msg.name = %s\n", msg->name);// printf("[login_user]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");return -1;}// printf("[login_user_send]msg.type = %d\n", msg->type);// printf("[login_user_send]msg.name = %s\n", msg->name);// printf("[login_user_send]msg.data = %s\n", msg->data);// memset(msg, 0, sizeof(msg_t));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");return -1;}// printf("[login_user_recv]msg.type = %d\n", msg->type);// printf("[login_user_recv]msg.name = %s\n", msg->name);// printf("[login_user_recv]msg.data = %s\n", msg->data);if (strcmp(msg->data, "OK") == 0){printf("登录成功...\n");return 1;}printf("用户名或密码错误...\n");return 0;
}
// int exit_search(msg_t *msg, int sockfd)
// {
//     return 0;
// }
int search_world(msg_t *msg, int sockfd, sqlite3 *my_db)
{// msg->type = S;while (1){memset(msg, 0, sizeof(msg_t));msg->type = S;printf("[查询]请输入要查询的单词(按#退出):");scanf("%s", msg->name);if (msg->name[strlen(msg->name) - 1] == '\n'){msg->name[strlen(msg->name) - 1] = '\0';}// printf("[scanf]msg->name = %s\n", msg->name);if (strcmp(msg->name, "#") == 0){printf("你主动退出了查单词功能...\n");break;}// printf("[do_search_send]msg.type = %d\n", msg->type);// printf("[do_search_send]msg.name = %s\n", msg->name);// printf("[do_search_send]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}memset(msg, 0, sizeof(msg));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}// printf("[do_search_recv]msg.type = %d\n", msg->type);// printf("[do_search_recv]msg.name = %s\n", msg->name);// printf("[do_search_recv]msg.data = %s\n", msg->data);if (strncmp(msg->name, "OK", 3) == 0){printf("[*****解释*****]:%s", msg->data);}else if (strncmp(msg->name, "NO_WORLD", 8) == 0){printf("[*****没有此单词*****]...\n");}}return 0;
}int check_user(msg_t msg, int sockfd)
{// printf("[check_user_send]msg.type = %d\n", msg.type);// printf("[check_user_send]msg.name = %s\n", msg.name);// printf("[check_user_send]msg.data = %s\n", msg.data);if (-1 == send(sockfd, &msg, sizeof(msg), 0)){perror("send error");exit(-1);}memset(&msg, 0, sizeof(msg));if (-1 == recv(sockfd, &msg, sizeof(msg), 0)){perror("recv error");exit(-1);}// printf("[check_user_recv]msg.type = %d\n", msg.type);// printf("[check_user_recv]msg.name = %s\n", msg.name);// printf("[check_user_recv]msg.data = %s\n", msg.data);if (strcmp(msg.data, "user already exit,regist fail") == 0){return -1;}else{return 0;}
}

结果图

3.5 完成记录查询功能(history)

service.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define S 4
#define H 5
#define E 6
#define DATABASE "test.db"
#define FILEPATH "./dict.txt"
typedef struct _MSG
{int type;char name[256];char data[128];
} msg_t;
void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db);
void do_quit(msg_t *msg, int acceptfd, sqlite3 *my_db);
int do_login(msg_t *msg, int acceptfd, sqlite3 *my_db);
int do_search(msg_t *msg, int acceptfd, sqlite3 *my_db, FILE *fp);
void getdata(char *data);
int history_callback(void *arg, int f_num, char **f_value, char **f_name);
void do_history(msg_t *msg, int acceptfd, sqlite3 *my_db);
int flafs = 0; // 全局变量 使得系统只有在第一次查询时 打开一次文件,第二次不用再打开
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <port> <ip>\n", argv[0]);exit(-1);}// 创建数据库sqlite3 *my_db;if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)){printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}FILE *fp; // 传入do_search();// 创建套接字int sockfd;struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("sockfd error");exit(-1);}// 填充服务器网络信息结构体serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);memset(&clientaddr, 0, sizeof(clientaddr));// 绑定if (-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("bind error");exit(-1);}// 监听printf("%d\n", sockfd);if (listen(sockfd, 5) < 0){perror("fail to listen");exit(-1);}int acceptfd;msg_t msg;while (1){acceptfd = 0;printf("阻塞等待客户端连接...\n");if (-1 == (acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len))){perror("accept errror");exit(-1);}printf("111111111\n");printf("客户端[%s][%d]连接成功...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));pid_t pid;pid = fork();if (pid == -1){perror("fork error");exit(-1);}else if (pid == 0){while (1){if (-1 == recv(acceptfd, &msg, sizeof(msg), 0)){perror("recv error");exit(-1);}printf("[main]msg_type = %d\n", msg.type);printf("[main]msg.name = %s\n", msg.name);printf("[main]msg.data = %s\n", msg.data);switch (msg.type){case R:do_regist(&msg, acceptfd, my_db);break;case L:do_login(&msg, acceptfd, my_db);break;case Q:printf("客户端[%s][%d]退出了...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));do_quit(&msg, acceptfd, my_db);break;case S:do_search(&msg, acceptfd, my_db, fp);break;case H:do_history(&msg, acceptfd, my_db);break;case E:break;}}// 子进程}else{// 父进程close(acceptfd);wait(NULL);}}return 0;
}
void getdata(char *data)
{time_t t;struct tm *tp;time(&t);tp = localtime(&t);sprintf(data, "%d-%d-%d %d:%d:%d", 1900 + tp->tm_year, 1 + tp->tm_mon, tp->tm_mday,tp->tm_hour, tp->tm_min, tp->tm_sec);
}
void do_history(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char databuff[128] = {0};getdata(databuff);printf("[do_history]msg.type = %d\n", msg->type);printf("[do_history]msg.name = %s\n", msg->name);printf("[do_history]msg.data = %s\n", msg->data);msg->type = H;char sqlbuff[512] = {0};sprintf(sqlbuff, "select * from record where  name='%s'", msg->name);if (sqlite3_exec(my_db, sqlbuff, history_callback, (void *)&acceptfd, NULL) != SQLITE_OK){printf("do_history sqlite3_exec error");}strcpy(msg->data, "***OVER***");send(acceptfd, msg, sizeof(msg_t), 0);return;
}
int history_callback(void *arg, int f_num, char **f_value, char **f_name)
{int acceptfd_1;msg_t msg;acceptfd_1 = *(int *)arg;sprintf(msg.data, "%s:%s", f_value[0], f_value[2]);send(acceptfd_1, &msg, sizeof(msg_t), 0);return 0;
}int do_search(msg_t *msg, int acceptfd, sqlite3 *my_db, FILE *fp)
{char buff[256] = {0};char databuff[128] = {0};getdata(databuff);printf("要查询的单词为:%s\n", msg->data);char sqlbuff[512] = {0};sprintf(sqlbuff, "insert into record values('%s','%s','%s')", databuff, msg->name, msg->data);printf("sqlbuff = %s\n", sqlbuff);if (sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL) != SQLITE_OK){printf("do_search sqlite3_exec error\n");return -1;}int word_len = 0;char *p = NULL;word_len = strlen(msg->data);printf("要查询的单词%s的长度%d\n", msg->data, word_len);// if (flafs == 0)// {// printf("第一次查询,单词文件打开中...\n");if (NULL == (fp = fopen(FILEPATH, "r"))){printf("[第一次]打开单词文件失败...\n");strcpy(msg->data, "open error or EOF");if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}}p = NULL;fgets(buff, sizeof(buff), fp);while (strncmp(msg->data, buff, word_len) != 0){if (fgets(buff, sizeof(buff), fp) == NULL){strcpy(msg->data, "NO_WORLD");// printf("11111111111111111\n");printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}}printf("[strncmp]msg.data = %s\n", msg->data);printf("[strncmp]buff=%s\n", buff);p = buff;p += word_len;if (*p != ' '){// printf("22222222222\n");strcpy(msg->data, "NO_WORLD");printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}while (*p == ' '){p++;}strcpy(msg->data, p);printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}fclose(fp);return 1;
}void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char sqlstr[512] = {0};char *errmsg;printf("[msg]msg.type = %d\n", msg->type);printf("[msg]msg.name = %s\n", msg->name);printf("[msg]msg.data = %s\n", msg->data);sprintf(sqlstr, "insert into user values('%s','%s')", msg->name, msg->data);printf("[do_regist]sqlstr = %s\n", sqlstr);if (sqlite3_exec(my_db, sqlstr, NULL, NULL, &errmsg) != SQLITE_OK){printf("errmsg = %s\n", errmsg);strcpy(msg->data, "user already exit,regist fail");}else{strcpy(msg->data, "OK");}printf("[do_regist_send]msg.type = %d\n", msg->type);printf("[do_regist_send]msg.name = %s\n", msg->name);printf("[do_regist_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return;
}
// int callback(void *arg, int ncolumn, char **f_value, char **f_name)
// {
//     int i = 0;
//     int flag = 0;
//     msg_t *msg_callback = (msg_t *)arg;
//     printf("[msg_callbackmsg_callback.type = %d\n", msg_callback->type);
//     printf("[msg_callback]msg_callback.name = %s\n", msg_callback->name);
//     printf("[msg_callback]msg_callback.data = %s\n", msg_callback->data);
//     if (0 == flag)
//     {
//         // 先打印字段名
//         for (i = 0; i < ncolumn; i++)
//         {
//             // strcpy(msg_callback->data, "user or passwd ereror");
//             printf("\n");
//         }
//         flag = 1;
//     }
//     // 再打印字段的值
//     for (i = 0; i < ncolumn; i++)
//     {
//         if ((f_value[i] != msg_callback->name) || (f_value[i] != msg_callback->data))
//         {
//             strcpy(msg_callback->data, "user or passwd ereror");
//         }
//         else
//         {
//             strcpy(msg_callback->data, "OK");
//         }
//     }
//     return 0; // 这里的回调函数要求必须有返回值 如果没有会报错 query aborted
// }int do_login(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char sqlstr[512] = {0};printf("[msg]msg.type = %d\n", msg->type);printf("[msg]msg.name = %s\n", msg->name);printf("[msg]msg.data = %s\n", msg->data);sprintf(sqlstr, "select * from user where name='%s' and passwd='%s'", msg->name, msg->data);printf("[do_login]sqlstr = %s\n", sqlstr);char *errmsg, **result;int nrow, ncolumn;// 通过sqlite3_get_table函数查询记录是否存在sprintf(sqlstr, "select * from user where name = '%s' and passwd = '%s'", msg->name, msg->data);if (sqlite3_get_table(my_db, sqlstr, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK){printf("error : %s\n", errmsg);}// 通过nrow参数判断是否能够查询到疾记录,如果值为0,则查询不到,如果值为非0,则查询到if (nrow == 0){strcpy(msg->data, "user or passwd ereror");printf("[do_login_send]msg.type = %d\n", msg->type);printf("[do_login_send]msg.name = %s\n", msg->name);printf("[do_login_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}else{strncpy(msg->data, "OK", 256);printf("[do_login_send]msg.type = %d\n", msg->type);printf("[do_login_send]msg.name = %s\n", msg->name);printf("[do_login_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 1;}
}
void do_quit(msg_t *msg, int acceptfd, sqlite3 *my_db)
{exit(-1);
}

client.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define S 4
#define H 5
#define E 6
#define DATABASE "test.db"
#define FILEPATH "./dict.txt"
typedef struct _MSG
{int type;char name[256];char data[128];
} msg_t;
void print_menu();
int login_user(msg_t *msg, int sockfd, sqlite3 *my_db);
void exit_system(msg_t *msg, int sockfd);
int regist_user(msg_t *msg, int sockfd);
int check_user(msg_t msg, int sockfd);
int search_world(msg_t *msg, int sockfd, sqlite3 *my_db);
int exit_search(msg_t *msg, int sockfd);
void query_menu();
int printf_history(msg_t *msg, int sockfd, sqlite3 *my_db);
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <ip> <port>\n", argv[1]);exit(-1);}// 创建套接字sqlite3 *my_db;if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)){printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}int sockfd;if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0))){perror("socket error");exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len = sizeof(serveraddr);serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));int choose = 0;msg_t msg;if (-1 == connect(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("connect error");exit(-1);}printf("连接服务器成功...\n");
NEXT2:while (1){print_menu();printf("请输入您的选择(1-3):");scanf("%d", &choose);switch (choose){case R:regist_user(&msg, sockfd);break;case L:if (login_user(&msg, sockfd, my_db) == 1){goto NEXT;}break;case Q:close(sockfd);// system("clear");printf("欢迎下次使用基于TCP的在线词典系统...\n");exit(0);}}
NEXT:while (1){// system("clear");query_menu();printf("请输入您的选择(4-6):");scanf("%d", &choose);switch (choose){case S:search_world(&msg, sockfd, my_db);break;case H:printf_history(&msg, sockfd, my_db);break;case E:goto NEXT2;break;}}return 0;
}
void print_menu()
{printf("-------------------------------------\n");printf("|  1.regist     2.login     3.quit  |\n");printf("-------------------------------------\n");return;
}
void query_menu()
{printf("-------------------------------------\n");printf("|  4.search    5.history    6.quit  |\n");printf("-------------------------------------\n");return;
}
void exit_system(msg_t *msg, int sockfd)
{system("clear");msg->type = Q;if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}close(sockfd);printf("欢迎下次使用基于TCP的在线词典系统...\n");exit(-1);
}int printf_history(msg_t *msg, int sockfd, sqlite3 *my_db)
{// memset(msg, 0, sizeof(msg_t));// printf("[printf_history]msg.type = %d\n", msg->type);// printf("[printf_history]msg.name = %s\n", msg->name); // 单词// printf("[printf_history]msg.data = %s\n", msg->data); // OKmsg->type = H;if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");return -1;}printf("<---历史记录如下--->\n");while (1){if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}if (strcmp(msg->data, "***OVER***") == 0){break;}printf("%s\n", msg->data);}return 0;
}
int regist_user(msg_t *msg, int sockfd)
{memset(msg, 0, sizeof(msg_t));msg->type = R;printf("[注册]请输入用户名:");scanf("%s", msg->name);printf("[注册]请输入密码:");scanf("%s", msg->data);// printf("[regist_user]msg.type = %d\n", msg->type);// printf("[regist_user]msg.name = %s\n", msg->name);// printf("[regist_user]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}// printf("[regist_send]msg.type = %d\n", msg->type);// printf("[regist_send]msg.name = %s\n", msg->name);// printf("[regist_send]msg.data = %s\n", msg->data);memset(msg, 0, sizeof(msg));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}// printf("[regist_recv]msg.type = %d\n", msg->type);// printf("[regist_recv]msg.name = %s\n", msg->name);// printf("[regist_recv]msg.data = %s\n", msg->data);if (strcmp(msg->data, "OK") == 0){printf("注册成功...\n");return 1;}printf("用户名已存在,注册失败...\n");return 0;
}
int login_user(msg_t *msg, int sockfd, sqlite3 *my_db)
{memset(msg, 0, sizeof(msg_t));msg->type = L;printf("[登录]请输入用户名:");scanf("%s", msg->name);printf("[登录]请输入密码:");scanf("%s", msg->data);// printf("[login_user]msg.type = %d\n", msg->type);// printf("[login_user]msg.name = %s\n", msg->name);// printf("[login_user]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");return -1;}// printf("[login_user_send]msg.type = %d\n", msg->type);// printf("[login_user_send]msg.name = %s\n", msg->name);// printf("[login_user_send]msg.data = %s\n", msg->data);// memset(msg, 0, sizeof(msg_t));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");return -1;}// printf("[login_user_recv]msg.type = %d\n", msg->type);// printf("[login_user_recv]msg.name = %s\n", msg->name);// printf("[login_user_recv]msg.data = %s\n", msg->data);if (strcmp(msg->data, "OK") == 0){printf("登录成功...\n");return 1;}printf("用户名或密码错误...\n");return 0;
}
// int exit_search(msg_t *msg, int sockfd)
// {
//     return 0;
// }
int search_world(msg_t *msg, int sockfd, sqlite3 *my_db)
{// msg->type = S;while (1){// memset(msg, 0, sizeof(msg_t));msg->type = S;printf("[查询]请输入要查询的单词(按#退出):");scanf("%s", msg->data);if (msg->data[strlen(msg->data) - 1] == '\n'){msg->data[strlen(msg->data) - 1] = '\0';}// printf("[scanf]msg->name = %s\n", msg->name);if (strcmp(msg->data, "#") == 0){printf("你主动退出了查单词功能...\n");break;}// printf("[do_search_send]msg.type = %d\n", msg->type);// printf("[do_search_send]msg.name = %s\n", msg->name);// printf("[do_search_send]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}memset(msg, 0, sizeof(msg));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}// printf("[do_search_recv]msg.type = %d\n", msg->type);// printf("[do_search_recv]msg.name = %s\n", msg->name);// printf("[do_search_recv]msg.data = %s\n", msg->data);if (strncmp(msg->data, "NO_WORLD", 8) == 0){printf("[*****没有此单词*****]...\n");// return 0;}else{printf("[*****解释*****]:%s", msg->data);}}return 0;
}int check_user(msg_t msg, int sockfd)
{// printf("[check_user_send]msg.type = %d\n", msg.type);// printf("[check_user_send]msg.name = %s\n", msg.name);// printf("[check_user_send]msg.data = %s\n", msg.data);if (-1 == send(sockfd, &msg, sizeof(msg), 0)){perror("send error");exit(-1);}memset(&msg, 0, sizeof(msg));if (-1 == recv(sockfd, &msg, sizeof(msg), 0)){perror("recv error");exit(-1);}// printf("[check_user_recv]msg.type = %d\n", msg.type);// printf("[check_user_recv]msg.name = %s\n", msg.name);// printf("[check_user_recv]msg.data = %s\n", msg.data);if (strcmp(msg.data, "user already exit,regist fail") == 0){return -1;}else{return 0;}
}

3.5通过select实现以上全部功能(多路IO复用)

service.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define S 4
#define H 5
#define E 6
#define DATABASE "test.db"
#define FILEPATH "./dict.txt"
typedef struct _MSG
{int type;char name[256];char data[128];
} msg_t;
void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db);          // 处理注册信息的函数
int do_login(msg_t *msg, int acceptfd, sqlite3 *my_db);            // 处理登录请求的函数
int do_search(msg_t *msg, int acceptfd, sqlite3 *my_db, FILE *fp); // 处理查单词的函数
void getdata(char *data);
int history_callback(void *arg, int f_num, char **f_value, char **f_name); // 历史记录查询回调函数 显示指定用户的所有历史查询记录
void do_history(msg_t *msg, int acceptfd, sqlite3 *my_db);
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <port> <ip>\n", argv[0]);exit(-1);}// 打开数据库 需要自己提前创建好.db结尾的数据库文件// 终端执行sqlite3 test.db// CREATE TABLE user(name TEXT PRIMARY KEY,passwd TEXT);sqlite3 *my_db;                                  // 数据库句柄if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)) // 打开数据库{printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}FILE *fp; // FILE *指针 对应打开文件// 创建套接字int sockfd;struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){perror("sockfd error");exit(-1);}// 填充服务器网络信息结构体serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));serveraddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t serveraddr_len = sizeof(serveraddr);struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);memset(&clientaddr, 0, sizeof(clientaddr));// 绑定if (-1 == bind(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("bind error");exit(-1);}// 监听printf("%d\n", sockfd);if (listen(sockfd, 5) < 0){perror("fail to listen");exit(-1);}int max_fd = 0; // 用来记录最大的文件描述符int acceptfd;msg_t msg;fd_set readfds; // 母本 监听集合FD_ZERO(&readfds);fd_set readfds_temp; // 副本 用于给select擦除用FD_ZERO(&readfds_temp);// 将sockfd放入监听集合FD_SET(sockfd, &readfds);max_fd = max_fd > sockfd ? max_fd : sockfd;printf("max_fd = %d\n", max_fd);int ret;int i;int recvbyte = 0;while (1){readfds_temp = readfds;if (-1 == (ret = select(max_fd + 1, &readfds_temp, NULL, NULL, NULL))) // select阻塞{perror("select error");return -1;}if (FD_ISSET(sockfd, &readfds_temp)) // 判断是否有客户端要连接{if (-1 == (acceptfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_len))){perror("accpet error");return -1;}printf("*****客户端[%s][%d]连接成功...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));FD_SET(acceptfd, &readfds);printf("%d\n", acceptfd);max_fd = max_fd > acceptfd ? max_fd : acceptfd;}for (i = 5; i < max_fd + 1 && ret != 0; i++) // 检测客户端,检查是哪一个客户端发送的消息{if (FD_ISSET(i, &readfds_temp)){if (-1 == (recvbyte = recv(i, &msg, sizeof(msg_t), 0))){perror("recv error");return -1;}else if (recvbyte == 0){close(i);FD_CLR(i, &readfds);if (i == max_fd){--max_fd;}printf("客户端退出了...\n");}else{switch (msg.type){case R:do_regist(&msg, i, my_db);break;case L:do_login(&msg, i, my_db);break;case Q:printf("客户端[%s][%d]退出了...\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));break;case S:do_search(&msg, i, my_db, fp);break;case H:do_history(&msg, i, my_db);break;case E:break;}}}}}return 0;
}
void getdata(char *data) // 获取系统时间函数
{time_t t;struct tm *tp;time(&t);tp = localtime(&t);sprintf(data, "%d-%d-%d %d:%d:%d", 1900 + tp->tm_year, 1 + tp->tm_mon, tp->tm_mday,tp->tm_hour, tp->tm_min, tp->tm_sec);
}
void do_history(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char databuff[128] = {0};getdata(databuff);printf("[do_history]msg.type = %d\n", msg->type);printf("[do_history]msg.name = %s\n", msg->name);printf("[do_history]msg.data = %s\n", msg->data);msg->type = H;char sqlbuff[512] = {0};sprintf(sqlbuff, "select * from record where  name='%s'", msg->name);if (sqlite3_exec(my_db, sqlbuff, history_callback, (void *)&acceptfd, NULL) != SQLITE_OK){printf("do_history sqlite3_exec error");}strcpy(msg->data, "***OVER***");send(acceptfd, msg, sizeof(msg_t), 0);return;
}
int history_callback(void *arg, int f_num, char **f_value, char **f_name)
{int acceptfd_1;msg_t msg;acceptfd_1 = *(int *)arg;sprintf(msg.data, "%s:%s", f_value[0], f_value[2]);send(acceptfd_1, &msg, sizeof(msg_t), 0);return 0;
}
int do_search(msg_t *msg, int acceptfd, sqlite3 *my_db, FILE *fp)
{if (NULL == (fp = fopen(FILEPATH, "r"))){printf("[第一次]打开单词文件失败...\n");strcpy(msg->data, "open error or EOF");if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}}char buff[256] = {0};char databuff[128] = {0};getdata(databuff);printf("要查询的单词为:%s\n", msg->data);char sqlbuff[512] = {0};sprintf(sqlbuff, "insert into record values('%s','%s','%s')", databuff, msg->name, msg->data);printf("sqlbuff = %s\n", sqlbuff);if (sqlite3_exec(my_db, sqlbuff, NULL, NULL, NULL) != SQLITE_OK){printf("do_search sqlite3_exec error\n");return -1;}int word_len = 0;char *p;p = NULL;word_len = strlen(msg->data);printf("要查询的单词%s的长度%d\n", msg->data, word_len);while (fgets(buff, sizeof(buff), fp) != NULL){p = buff;p += word_len;if (strncmp(msg->data, buff, word_len) == 0 && (*p == ' ')) // 相同字母{while (p++){if (*p != ' '){break;}} // 指向解释strcpy(msg->data, p);printf("[do_search2]msg.type = %d\n", msg->type);printf("[do_search2]msg.name = %s\n", msg->name);printf("[do_search2]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");return -1;}fclose(fp);return 1;}else{continue;}}strcpy(msg->data, "NO_WORLD");printf("[do_search]msg.type = %d\n", msg->type);printf("[do_search]msg.name = %s\n", msg->name);printf("[do_search]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}fclose(fp);return 0;
}void do_regist(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char sqlstr[512] = {0};char *errmsg;printf("[msg]msg.type = %d\n", msg->type);printf("[msg]msg.name = %s\n", msg->name);printf("[msg]msg.data = %s\n", msg->data);sprintf(sqlstr, "insert into user values('%s','%s')", msg->name, msg->data);printf("[do_regist]sqlstr = %s\n", sqlstr);if (sqlite3_exec(my_db, sqlstr, NULL, NULL, &errmsg) != SQLITE_OK){printf("errmsg = %s\n", errmsg);strcpy(msg->data, "user already exit,regist fail");}else{strcpy(msg->data, "OK");}printf("[do_regist_send]msg.type = %d\n", msg->type);printf("[do_regist_send]msg.name = %s\n", msg->name);printf("[do_regist_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return;
}int do_login(msg_t *msg, int acceptfd, sqlite3 *my_db)
{char sqlstr[512] = {0};printf("[msg]msg.type = %d\n", msg->type);printf("[msg]msg.name = %s\n", msg->name);printf("[msg]msg.data = %s\n", msg->data);sprintf(sqlstr, "select * from user where name='%s' and passwd='%s'", msg->name, msg->data);printf("[do_login]sqlstr = %s\n", sqlstr);char *errmsg, **result;int nrow, ncolumn;// 通过sqlite3_get_table函数查询记录是否存在sprintf(sqlstr, "select * from user where name = '%s' and passwd = '%s'", msg->name, msg->data);if (sqlite3_get_table(my_db, sqlstr, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK){printf("error : %s\n", errmsg);}// 通过nrow参数判断是否能够查询到疾记录,如果值为0,则查询不到,如果值为非0,则查询到if (nrow == 0){strcpy(msg->data, "user or passwd ereror");printf("[do_login_send]msg.type = %d\n", msg->type);printf("[do_login_send]msg.name = %s\n", msg->name);printf("[do_login_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 0;}else{strncpy(msg->data, "OK", 256);printf("[do_login_send]msg.type = %d\n", msg->type);printf("[do_login_send]msg.name = %s\n", msg->name);printf("[do_login_send]msg.data = %s\n", msg->data);if (-1 == send(acceptfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}return 1;}
}

client.c

#include <head.h>
#include <sqlite3.h> //sqlite3
#define R 1
#define L 2
#define Q 3
#define S 4
#define H 5
#define E 6
#define DATABASE "test.db"
#define FILEPATH "./dict.txt"
typedef struct _MSG
{int type;char name[256];char data[128];
} msg_t;
void print_menu();
int login_user(msg_t *msg, int sockfd, sqlite3 *my_db);
void exit_system(msg_t *msg, int sockfd);
int regist_user(msg_t *msg, int sockfd);
int check_user(msg_t msg, int sockfd);
int search_world(msg_t *msg, int sockfd, sqlite3 *my_db);
int exit_search(msg_t *msg, int sockfd);
void query_menu();
int printf_history(msg_t *msg, int sockfd, sqlite3 *my_db);
int main(int argc, const char *argv[])
{// 入参合理性检查if (3 != argc){printf("usage error:%s <ip> <port>\n", argv[1]);exit(-1);}// 创建套接字sqlite3 *my_db;if (SQLITE_OK != sqlite3_open(DATABASE, &my_db)){printf("sqlite3 open error:%s\n", sqlite3_errmsg(my_db));exit(-1);}int sockfd;if (-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0))){perror("socket error");exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len = sizeof(serveraddr);serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = inet_addr(argv[1]);serveraddr.sin_port = htons(atoi(argv[2]));int choose = 0;msg_t msg;if (-1 == connect(sockfd, (struct sockaddr *)&serveraddr, serveraddr_len)){perror("connect error");exit(-1);}printf("连接服务器成功...\n");
NEXT2:while (1){print_menu();printf("请输入您的选择(1-3):");scanf("%d", &choose);switch (choose){case R:regist_user(&msg, sockfd);break;case L:if (login_user(&msg, sockfd, my_db) == 1){goto NEXT;}break;case Q:// exit_system(&msg, sockfd);close(sockfd);system("clear");printf("欢迎下次使用基于TCP的在线词典系统...\n");exit(0);}}
NEXT:while (1){// system("clear");query_menu();printf("请输入您的选择(4-6):");scanf("%d", &choose);switch (choose){case S:search_world(&msg, sockfd, my_db);break;case H:printf_history(&msg, sockfd, my_db);break;case E:goto NEXT2;break;}}return 0;
}
void print_menu()
{printf("-------------------------------------\n");printf("|  1.regist     2.login     3.quit  |\n");printf("-------------------------------------\n");return;
}
void query_menu()
{printf("-------------------------------------\n");printf("|  4.search    5.history    6.quit  |\n");printf("-------------------------------------\n");return;
}
void exit_system(msg_t *msg, int sockfd)
{system("clear");msg->type = Q;if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}close(sockfd);printf("欢迎下次使用基于TCP的在线词典系统...\n");exit(-1);
}int printf_history(msg_t *msg, int sockfd, sqlite3 *my_db)
{// memset(msg, 0, sizeof(msg_t));// printf("[printf_history]msg.type = %d\n", msg->type);// printf("[printf_history]msg.name = %s\n", msg->name); // 单词// printf("[printf_history]msg.data = %s\n", msg->data); // OKmsg->type = H;if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");return -1;}printf("<---历史记录如下--->\n");while (1){if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}if (strcmp(msg->data, "***OVER***") == 0){break;}printf("%s\n", msg->data);}return 0;
}
int regist_user(msg_t *msg, int sockfd)
{memset(msg, 0, sizeof(msg_t));msg->type = R;printf("[注册]请输入用户名:");scanf("%s", msg->name);printf("[注册]请输入密码:");scanf("%s", msg->data);// printf("[regist_user]msg.type = %d\n", msg->type);// printf("[regist_user]msg.name = %s\n", msg->name);// printf("[regist_user]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}// printf("[regist_send]msg.type = %d\n", msg->type);// printf("[regist_send]msg.name = %s\n", msg->name);// printf("[regist_send]msg.data = %s\n", msg->data);memset(msg, 0, sizeof(msg));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}// printf("[regist_recv]msg.type = %d\n", msg->type);// printf("[regist_recv]msg.name = %s\n", msg->name);// printf("[regist_recv]msg.data = %s\n", msg->data);if (strcmp(msg->data, "OK") == 0){printf("注册成功...\n");return 1;}printf("用户名已存在,注册失败...\n");return 0;
}
int login_user(msg_t *msg, int sockfd, sqlite3 *my_db)
{memset(msg, 0, sizeof(msg_t));msg->type = L;printf("[登录]请输入用户名:");scanf("%s", msg->name);printf("[登录]请输入密码:");scanf("%s", msg->data);// printf("[login_user]msg.type = %d\n", msg->type);// printf("[login_user]msg.name = %s\n", msg->name);// printf("[login_user]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");return -1;}// printf("[login_user_send]msg.type = %d\n", msg->type);// printf("[login_user_send]msg.name = %s\n", msg->name);// printf("[login_user_send]msg.data = %s\n", msg->data);// memset(msg, 0, sizeof(msg_t));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");return -1;}// printf("[login_user_recv]msg.type = %d\n", msg->type);// printf("[login_user_recv]msg.name = %s\n", msg->name);// printf("[login_user_recv]msg.data = %s\n", msg->data);if (strcmp(msg->data, "OK") == 0){printf("登录成功...\n");return 1;}printf("用户名或密码错误...\n");return 0;
}
// int exit_search(msg_t *msg, int sockfd)
// {
//     return 0;
// }
int search_world(msg_t *msg, int sockfd, sqlite3 *my_db)
{// msg->type = S;while (1){// memset(msg, 0, sizeof(msg_t));msg->type = S;printf("[查询]请输入要查询的单词(按#退出):");scanf("%s", msg->data);if (msg->data[strlen(msg->data) - 1] == '\n'){msg->data[strlen(msg->data) - 1] = '\0';}// printf("[scanf]msg->name = %s\n", msg->name);if (strcmp(msg->data, "#") == 0){printf("你主动退出了查单词功能...\n");break;}// printf("[do_search_send]msg.type = %d\n", msg->type);// printf("[do_search_send]msg.name = %s\n", msg->name);// printf("[do_search_send]msg.data = %s\n", msg->data);if (-1 == send(sockfd, msg, sizeof(msg_t), 0)){perror("send error");exit(-1);}memset(msg, 0, sizeof(msg));if (-1 == recv(sockfd, msg, sizeof(msg_t), 0)){perror("recv error");exit(-1);}// printf("[do_search_recv]msg.type = %d\n", msg->type);// printf("[do_search_recv]msg.name = %s\n", msg->name);// printf("[do_search_recv]msg.data = %s\n", msg->data);if (strncmp(msg->data, "NO_WORLD", 8) == 0){printf("[*****没有此单词*****]...\n");// return 0;}else{printf("[*****解释*****]:%s", msg->data);}}return 0;
}int check_user(msg_t msg, int sockfd)
{// printf("[check_user_send]msg.type = %d\n", msg.type);// printf("[check_user_send]msg.name = %s\n", msg.name);// printf("[check_user_send]msg.data = %s\n", msg.data);if (-1 == send(sockfd, &msg, sizeof(msg), 0)){perror("send error");exit(-1);}memset(&msg, 0, sizeof(msg));if (-1 == recv(sockfd, &msg, sizeof(msg), 0)){perror("recv error");exit(-1);}// printf("[check_user_recv]msg.type = %d\n", msg.type);// printf("[check_user_recv]msg.name = %s\n", msg.name);// printf("[check_user_recv]msg.data = %s\n", msg.data);if (strcmp(msg.data, "user already exit,regist fail") == 0){return -1;}else{return 0;}
}

需提前安装sqlite3数据库,安装教程参考以下文章

Linux 基于sqlite3数据库的学生管理系统-CSDN博客文章浏览阅读204次。sqlite官网:www.sqlite.org 学生管理系统增删改查https://blog.csdn.net/CSDN_DU666666/article/details/139999025?spm=1001.2014.3001.5502然后执行

gcc service.c -lsqlite3 -o service

gcc client.c -lsqlite3 -o client

./service 192.168.250.100 8888

./client 192.168.250.100 8888

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/376248.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PTX入门教程与实战

PTX入门教程 官方文档的目录结构 1 PTX指令 官方文档链接 1.1 指令形式 指令的操作数个数从0-4不等&#xff0c;其中d代表的是目的操作数&#xff0c;a,b,c是源操作数 p opcode;p opcode a;p opcode d, a;p opcode d, a, b;p opcode d, a, b, c;2 编程模型 2.…

FullCalendar的使用,react日历组件

1.下载 yarn add fullcalendar/core fullcalendar/react fullcalendar/daygrid 2.运行 import React from react; import FullCalendar from "fullcalendar/react"; import dayGridPlugin from "fullcalendar/daygrid";const ExperimentalSchedule () …

13--memcache与redis

前言&#xff1a;数据库读取速度较慢一直是无法解决的问题&#xff0c;大型网站应对的方式主要是使用缓存服务器来缓解这种情况&#xff0c;减少数据库访问次数&#xff0c;以提高动态Web等应用的速度、提高可扩展性。 1、简介 Memcached/redis是高性能的分布式内存缓存服务器…

paddlepaddle2.6,paddleorc2.8,cuda12,cudnn,nccl,python10环境

1.安装英伟达显卡驱动 首先需要到NAVIDIA官网去查自己的电脑是不是支持GPU运算。 网址是&#xff1a;CUDA GPUs | NVIDIA Developer。打开后的界面大致如下&#xff0c;只要里边有对应的型号就可以用GPU运算&#xff0c;并且每一款设备都列出来相关的计算能力&#xff08;Compu…

C语言 | Leetcode C语言题解之第230题二叉搜索树中第K小的元素

题目&#xff1a; 题解&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/int search_num(struct TreeNode* root, int k, int *result, int num) {if(num k 1){retu…

计算机的错误计算(二十九)

摘要 &#xff08;1&#xff09;讨论近似值的错误数字个数。有时&#xff0c;遇到数字9或0, 不太好确认近似值的错误数字个数。&#xff08;2&#xff09;并进一步解释确认计算机的错误计算&#xff08;二十八&#xff09;中一个函数值的错误数字个数。 理论上&#xff0c;我…

Java数据结构-二叉树

树型结构 概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成的一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上叶朝下的。 树具有以下特点&#xff1a; 有一个特殊结点&…

javaweb个人主页设计(html+css+js)

目录 1 前言和要求 1.1 前言 1.2 设计要求 2 预览 2.1 主页页面 2.2 个人简介 2.3 个人爱好 2.4 个人成绩有代码&#xff0c;但是图片已省略&#xff0c;可以根据自己情况添加 2.5 收藏夹 3 代码实现 3.1 主页 3.2 个人简介 3.3 个人爱好 3.4 个人成绩&#xff…

CSS技巧专栏:一日一例 1.纯CSS实现 会讨好的热情按钮 特效

题外话: 从今天开始,我准备开设一个新的专栏,专门写 使用CSS实现各种酷炫按钮的方法,本专栏目前准备写40篇左右,大概会完成如下按钮效果: 今天,我来介绍第一个按钮的实现方法:会讨好的热情按钮。为什么我给它起这样的名字呢?你看它像不像一个不停摇尾巴的小黄?当你鼠…

SvANet:微小医学目标分割网络,增强早期疾病检测

SvANet&#xff1a;微小医学目标分割网络&#xff0c;增强早期疾病检测 提出背景前人工作医学对象分割微小医学对象分割注意力机制 SvANet 结构图SvANet 解法拆解解法逻辑链 论文&#xff1a;SvANet: A Scale-variant Attention-based Network for Small Medical Object Segmen…

中职网络安全B模块渗透测试server2003

通过本地PC中渗透测试平台Kali对服务器场景Windows进⾏系统服务及版本扫描渗透测 试&#xff0c;并将该操作显示结果中Telnet服务对应的端⼝号作为FLAG提交 使用nmap扫描发现目标靶机开放端口232疑似telnet直接进行连接测试成功 Flag&#xff1a;232 通过本地PC中渗透测试平台…

【Lora模型推荐】Stable Diffusion创作具有玉石翡翠质感的图标设计

站长素材AI教程是站长之家旗下AI绘图教程平台 海量AI免费教程&#xff0c;每日更新干货内容 想要深入学习更多AI绘图教程&#xff0c;请访问站长素材AI教程网&#xff1a; AI教程_深度学习入门指南 - 站长素材 (chinaz.com) logo版权归各公司所有&#xff01;本笔记仅供AIGC…

基于stm32+小程序开发智能家居门禁系统-硬件-软件实现

视频演示&#xff1a; 基于stm32智能家居门禁系统小程序开发项目 视频还有添加删除卡号&#xff0c;添加删除指纹&#xff0c;关闭继电器电源等没有演示。 代码Git&#xff1a; https://github.com/Abear6666/stm32lock 总体功能&#xff1a; 本门禁系统主要解锁功能分别为卡…

android13 设置左右分屏修改为单屏幕,应用分屏改为单屏

总纲 android13 rom 开发总纲说明 目录 1.前言 2.系统设置实现分析 3. 设置修改 4.编译与验证 5.猜测 6.彩蛋 1.前言 android13中,系统设置变成,左边是一级菜单,右侧是二级菜单, 这样跟我们以前android7/8/9的布局是不一样的,我们需要将它修改为一级菜单,点进去…

mysql 5.7.44 32位 zip安装

前言 因为研究别人代码&#xff0c;他使用了5.7的 32位 mysql &#xff0c;同时最新的 8.4 64位 mysql 不能用官方lib连接。所以安装这个版本使用&#xff0c;期间有些坑&#xff0c;在这里记录一下。 下载路径 mysql官方路径&#xff1a;https://downloads.mysql.com/archi…

Unity如何查找两个transform最近的公共parent

查找两个子对象最近的父对象 一、问题背景二、解决方案思路核心算法代码 三、总结 一、问题背景 最近看到个关于Unity的问题&#xff1a;在Hierarchy面板中的游戏对象&#xff0c;给定两个子物体transform对象&#xff0c;如何查找这两个transform最近的公共父级parent。感觉挺…

从 ArcMap 迁移到 ArcGIS Pro

许多 ArcMap 用户正在因 ArcGIS Pro 所具有的现代 GIS 桌面工作流优势而向其迁移。 ArcGIS Pro 与其余 ArcGIS 平台紧密集成&#xff0c;使您可以更有效地共享和使用内容。 它还将 2D 和 3D 组合到一个应用程序中&#xff0c;使您可以在同一工程中使用多个地图和多个布局。 Arc…

Linux桌面溯源

X窗口系统(X Window System) Linux起源于X窗口系统&#xff08;X Window System&#xff09;&#xff0c;亦即常说的X11&#xff0c;因其版本止于11之故。 X窗口系统&#xff08;X Window System&#xff0c;也常称为X11或X&#xff09;是一种以位图方式显示的软件窗口系统。…

保姆级教你如何在大学期间获得自己的一项个人软著(1)

注册与实名认证 1. 注册与实名认证 已注册和实名认证 or 直接使用组织账号 进行软著申请的&#xff0c;可以跳过这部分 1.1 注册 登录中国版权保护中心 中国版权登记业务平台 点击右上角的用户中心 点击立即注册 选择个人身份进行注册 返回登记页面中国版权登记业务平台…

【教程】Hexo 部署到 Github Page 后,自定义域名失效的问题

目录 前言&问题描述解决方案细节 前言&问题描述 近期给 Github Page 上托管的静态网站映射了自定义域名&#xff08;aiproducthome.top&#xff09;&#xff0c;之后发现每次更新并部署 hexo 到 Github Page &#xff08;hexo d&#xff09;后就会出现自定义域名失效的…