基于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
相关文章:
基于TCP的在线词典系统(分阶段实现)(阻塞io和多路io复用(select)实现)
1.功能说明 一共四个功能: 注册 登录 查询单词 查询历史记录 单词和解释保存在文件中,单词和解释只占一行, 一行最多300个字节,单词和解释之间至少有一个空格。 2.功能演示 3、分阶段完成各个功能 3.1 完成服务器和客户端的连接 servic…...

设置DepthBufferBits和设置DepthStencilFormat的区别
1)设置DepthBufferBits和设置DepthStencilFormat的区别 2)Unity打包exe后,游戏内拉不起Steam的内购 3)Unity 2022以上Profiler.FlushMemoryCounters耗时要怎么关掉 4)用GoodSky资产包如何实现昼夜播发不同音乐功能 这是…...
MySQL零散拾遗
mysql中大小写敏感吗? MySQL数据库默认情况下是不区分大小写的,这意味着在查询时,字段名和值的大小写不会影响结果。然而,这种默认行为可能会根据操作系统和配置的不同而有所变化。 在某些操作系统上,比如Linux&…...

kali安装vulhub遇到的问题及解决方法(docker及docker镜像源更换)
kali安装vulhub: 提示:项目地址 https://github.com/vulhub/vulhub 项目安装: git clone https://github.com/vulhub/vulhub.git 安装docker 提示:普通用户请使用sudo: 首先安装 https 协议、CA 证书 apt-get in…...

开源数字人项目Hallo
硬件条件: gpu最低12G 软件: cuda需支持 Python选择3.10吧,我的版本3.11 源码: GitHub - fudan-generative-vision/hallo: Hallo: Hierarchical Audio-Driven Visual Synthesis for Portrait Image Animation models文件&…...
Linux 命令集
修改主机名/关机/重启 1)hostnamectl 命令 $ hostnamectl # 查看操作系统信息(内核、操作系统发行版本、主机名等) $ hostnamectl set-hostname redhatu8 # 修改主机名2)shutdown 关机 $ shutdown -h now # 马上关机3&#…...

QML 鼠标和键盘事件
学习目标:Qml 鼠标和键盘事件 学习内容 1、QML 鼠标事件处理QML 直接提供 MouseArea 来捕获鼠标事件,该操作必须配合Rectangle 获取指定区域内的鼠标事件, 2、QML 键盘事件处理,并且获取对OML直接通过键盘事件 Keys 监控键盘任意按键应的消…...

WPF引入多个控件库使用
目的 设计开发时有的控件库的一部分符合我们想要的UI样式,另一部分来自另一个控件库,想把两种库的样式做一个整合在同一个控件资源上。单纯通过引用的方式会导致原有样式被覆盖。这里通过设置全局样式的方式来实现。 1.安装控件库nuget包:H…...

【Linux】1w详解如何实现一个简单的shell
目录 实现思路 1. 交互 获取命令行 2. 子串分割 解析命令行 3. 指令的判断 内建命令 4. 普通命令的执行 补充:vim 文本替换 整体代码 重点思考 1.getenv和putenv是什么意思 2.代码extern char **environ; 3.内建命令是什么 4.lastcode WEXITSTATUS(sta…...

单目测距 单目相机测距 图片像素坐标转实际坐标的一种转换方案
需要相机位置固定 原图 红色的点是我们标注的像素点,这些红色的点我们知道它的像素坐标,以及以右下角相机位置为原点的x y 实际坐标数值 通过转换,可以得到整个图片内部其余像素点的实际坐标, 这些红色的点是通过转换关系生成的&…...

ensp防火墙综合实验作业+实验报告
实验目的要求及拓扑图: 我的拓扑: 更改防火墙和交换机: [USG6000V1-GigabitEthernet0/0/0]ip address 192.168.110.5 24 [USG6000V1-GigabitEthernet0/0/0]service-manage all permit [Huawei]vlan batch 10 20 [Huawei]int g0/0/2 [Huawei-…...

【大模型LLM面试合集】大语言模型基础_Word2Vec
Word2Vec 文章来源:Word2Vec详解 - 知乎 (zhihu.com) 1.Word2Vec概述 Word2Vec是google在2013年推出的一个NLP工具,它的特点是能够将单词转化为向量来表示,这样词与词之间就可以定量的去度量他们之间的关系,挖掘词之间的联系。 …...
图论基础概念(详细讲解)
今天,我们讲解一下图论的概念,首先我们知道图是一个什么东西。 图你可以理解成一个网络系统,两个节点之间可能会有边,边链接两个节点,可能是有向(就比如说a只能往b,或者b只能往c),可能是无向&a…...
未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序报错的解决办法
今天在免费云服务器,三丰云上运行c#或python程序,都提示:未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序,PHP程序就直接乱码,odbc_connect(): SQL error: [Microsoft][ODBC ���&…...
《从零开始学习Linux》——开篇
前言 近日笔者新开专栏,《从零开始学习Linux》,Linux水深而且大,学了一圈之后,有懂得有不懂的,一直没有机会整体的全部重新捋一遍,本专栏的目的是,带着大家包括我自己重新学习Linux一遍这些知识…...

3D工艺大师快速生成装配动画,驱动汽车工业装配流程革新
在现代制造业的一般生产流程中,车间装配环节是产品由蓝图迈向市场前至关重要的一道工序。随着产品结构的日益复杂化和个性化需求的不断增长,车间装配工作面临着前所未有的挑战。高精密度的装配要求、错综复杂的组件关系以及频繁变更的生产计划࿰…...

gateway
gateway核心概念 1. 路由(route) 路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组Filter组成。如果断言为真,则说明请求的URL 和 配置的路由匹配。 2. 断言(predicates) 断言函数允许开发者去定义匹配Htt…...

第一个ffmpeg程序
在进行使用ffmpeg进行编写程序时,首先要记得进行注册设备(avdevice_register_all ),程序运行时,只需要注册一次就可以 avdevice_register_all 是 FFmpeg 多媒体处理库中的一个函数,其作用是注册所有可用的音…...

论文翻译:Large Language Models for Education: A Survey and Outlook
https://arxiv.org/abs/2403.18105 目录 教育领域的大型语言模型:一项调查和展望摘要1. 引言2. 教育应用中的LLM2.1 概述2.2 学习辅助2.2.1 问题解决(QS) 2.2.2 错误纠正(EC)2.2.3 困惑助手(CH)…...
python为什么慢?(自用)
《Cython系列》1. Cython 是什么?为什么要有 Cython?为什么我们要用 Cython? - 古明地盆 - 博客园 (cnblogs.com) 古明地盆的主页 - 博客园 (cnblogs.com) 我原本认为,python慢的原因是“逐行解释程序并执行”,那么我…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...