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

news2024/11/16 16:20:19

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); // OK
    msg->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); // OK
    msg->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); // OK
    msg->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.coloradmin.cn/o/1924310.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WAF基础介绍

WAF 一、WAF是什么&#xff1f;WAF能够做什么 二 waf的部署三、WAF的工作原理 一、WAF是什么&#xff1f; WAF的全称是&#xff08;Web Application Firewall&#xff09;即Web应用防火墙&#xff0c;简称WAF。 国际上公认的一种说法是&#xff1a;Web应用防火墙是通过执行一…

电表及销售统计Python应用及win程序2

接着上一篇给代码添加了表格功能&#xff0c;方便更好的处理数据。 import json import os from datetime import datetime from tkinter import * from tkinter import messagebox from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.figure …

JAVA设计模式>>结构型>>适配器模式

本文介绍23种设计模式中结构型模式的适配器模式 目录 1. 适配器模式 1.1 基本介绍 1.2 工作原理 1.3 适配器模式的注意事项和细节 1.4 类适配器模式 1.4.1 类适配器模式介绍 1.4.2 应用实例 1.4.3 注意事项和细节 1.5 对象适配器模式 1.5.1 基本介绍 1.5.2 …

visual studio 2019版下载以及与UE4虚幻引擎配置(过程记录)(官网无法下载visual studio 2019安装包)

一、概述 由于需要使用到UE4虚幻引擎&#xff0c;我使用的版本是4.27版本的&#xff0c;其官方默认的visual studio版本是2019版本的&#xff0c;相应的版本对应关系可以通过下面的官方网站对应关系查询。https://docs.unrealengine.com/4.27/zh-CN/ProductionPipelines/Develo…

java实现资产管理系统图形化用户界面

创建一个&#x1f495;资产管理系统的GUI&#xff08;图形用户界面&#xff09;❤️画面通常需要使用Java的Swing或者JavaFX库。下面我将提供一个简单的资产管理系统GUI的示例代码&#xff0c;使用Java Swing库来实现。这个示例将包括一个主窗口&#xff0c;一个表格来显示资产…

捷配笔记-如何设计PCB板布线满足生产标准?

PCB板布线是铺设连接各种设备与通电信号的路径的过程。PCB板布线是铺设连接各种设备与通电信号的路径的过程。 在PCB设计中&#xff0c;布线是完成产品设计的重要步骤。可以说&#xff0c;之前的准备工作已经为它做好了。在整个PCB设计中&#xff0c;布线设计过程具有最高的极限…

Web浏览器通过串口读取RFID卡号js JavaScript

本示例使用的读卡器&#xff1a;USB转RS232COM虚拟串口RFID读卡器主动读卡Web浏览器Andro、Linux-淘宝网 (taobao.com) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"…

翁恺-C语言程序设计-05-3. 求a的连续和

05-3. 求a的连续和 输入两个整数a和n&#xff0c;a的范围是[0,9]&#xff0c;n的范围是[1,8]&#xff0c;求数列之和S aaaaaa…aaa…a&#xff08;n个a&#xff09;。如a为2、n为8时输出的是222222…22222222的和。 输入格式&#xff1a; 输入在一行中给出两个整数&#xf…

深入了解 MySQL 的 EXPLAIN 命令

一、什么是 EXPLAIN 命令&#xff1f; EXPLAIN 命令用于显示 MySQL 如何执行某个 SQL 语句&#xff0c;尤其是 SELECT 语句。通过 EXPLAIN 命令&#xff0c;可以看到查询在实际执行前的执行计划&#xff0c;这对于优化查询性能至关重要。 二、EXPLAIN 的基本用法 要使用 EXP…

【算法篇】KMP算法,一种高效的字符串匹配算法

我们今天了解一个字符串匹配算法-KMP算法&#xff0c;内容难度相对来说较高&#xff0c;建议先收藏再细品&#xff01;&#xff01;&#xff01; KMP算法的基本概念 KMP算法是一种高效的字符串匹配算法&#xff0c;由D.E.Knuth&#xff0c;J.H.Morris和V.R.Pratt提出的&#…

Cxx Primer-CP-2

开篇第一句话足见作者的高屋建瓴&#xff1a;类型决定程序中数据和操作的意义。随后列举了简单语句i i j;的意义取决于i和j的类型。若它们都是整形&#xff0c;则为通常的算术意义。若它们都为字符串型&#xff0c;则为进行拼接操作。若为用户自定义的class类型&#xff0c;则…

《Linux系统编程篇》Visual Studio Code配置下载,中文配置,连接远程ssh ——基础篇

引言 vscode绝对值得推荐&#xff0c;非常好用&#xff0c;如果你能体会其中的奥妙的话。 工欲善其事&#xff0c;必先利其器 ——孔子 文章目录 引言下载VS Code配置VS Code中文扩展连接服务器 连接服务器测试确定服务器的IP地址VS code 配置ssh信息选择连接到主机选择这个添…

K8s学习笔记1-搭建k8s集群

本次使用kubeadm方式&#xff0c;部署1.23.17版本 安装包百度云盘地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1UrIotP253DoyDIYB7G1C0Q 提取码&#xff1a;8q6a 集群所需虚拟机环境 主机名称IP资源harbor10.0.0.2301c2gmaster10.0.0.2312c4gworker110.0.0…

全新UI自助图文打印系统源码(含前端小程序源码 PHP后端 数据库)

最新自助图文打印系统和证件照云打印小程序源码PHP后端&#xff0c;为用户用户自助打印的服务&#xff0c;包括但不限于文档、图片、表格等多种格式的文件。此外&#xff0c;它们还提供了诸如美颜、换装、文档打印等功能&#xff0c;以及后台管理系统&#xff0c;方便管理员对打…

7.13 专题训练DP

P1255 数楼梯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) ac代码 #include<bits/stdc.h> using namespace std; typedef long long ll; #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) const ll mod 1e97;int main() {IOS;int n;cin>>n;int a[…

面向对象与C++进阶—并发与多线程篇

文章目录 18. 并发与多线程篇说在前面(1).线程和进程(2).并发和并行(3).thread(C11)#1.thread库与thread类#2.join和detach方法#3.id类和get_id方法#4.this_thread和系列操作 (4).原子操作#1.为什么是原子?#2.为什么需要原子操作&#xff1f;#3.atomic库 (5).竞态条件(6).线程…

7-1、2、3 IPFS介绍使用及浏览器交互(react+区块链实战)

7-1、2、3 IPFS介绍使用及浏览器交互&#xff08;react区块链实战&#xff09; 7-1 ipfs介绍7-2 IPFS-desktop使用7-3 reactipfs-api浏览器和ipfs交互 7-1 ipfs介绍 IPFS区块链上的文件系统 https://ipfs.io/ 这个网站本身是需要科学上网的 Ipfs是点对点的分布式系统 无限…

TEB局部路径规划算法代码及原理解读

TEB(Timed Elastic Band) 是一个基于图优化的局部路径规划算法&#xff0c;具有较好的动态避障能力&#xff0c;在ROS1/ROS2的导航框架中均被采用。该图优化以g2o优化框架实现&#xff0c;以机器人在各个离散时刻的位姿和离散时刻之间的时间间隔为顶点&#xff0c;约束其中的加…

IEEE(常用)参考文献引用格式详解 | LaTeX参考文献规范(IEEE Trans、Conf、Arxiv)

IEEE参考文献引用格式注意事项 期刊已正式出版&#xff08;有期卷号&#xff09;录用后在线访问即Early access&#xff08;无期卷号&#xff09; Arxiv论文会议论文IEEE缩写进阶其他 IEEE论文投稿前的参考文献格式检查&#xff01;&#xff08;如果一些细节你采用别的形式&…

UE4 解决创建布料报错:三角形退化

**【问题】**创建创建布料时报错&#xff1a;三角形退化 【方法】 1.要重新绑定&#xff1a;导入到ue4为静态网格体&#xff0c;勾选“移除退化”&#xff0c;再导出fbx&#xff0c;再重新绑定 2.不用重新绑定&#xff1a;使用排除法&#xff08;费时&#xff09;&#xff0c…