基于数据库 Sqlite3 的 root 管理系统

本文提供了一个使用epoll和sqlite3的多线程服务器实现,包括服务器端的套接字监听、红黑树管理、事件处理等功能。客户端部分实现了登陆验证、信息查询和修改等操作。代码中包含了服务器和客户端的交互逻辑,以及错误处理和资源管理。
摘要由CSDN通过智能技术生成

1.服务器

1.1服务器函数入口

#include "server.h"

int main(int argc, char const *argv[])
{

    char buf[128] = {0};
    char buf_ID[256] = {0};
    // 接收报错信息判断
    sqlite3 *db;
    // 创建员工信息的表格,存在则打开
    db = Sqlite_Create();
    if (db == NULL)
    {
        printf("sqlite_create=NULL\n");
        return 0;
    }

    // 服务器 套接字->端口重启->绑定->监听
    int sock_fd = sock_listen();
    if (!sock_fd)
    {
        printf("流程出现故障%d\n", __LINE__);
        return 0;
    }
    // 创建红黑树根节点
    //  创建一个epoll句柄/红黑树根节点
    epfd = epoll_create(10);

    if (epfd < 0)
    {
        printf("epoll_create on_success _%d_", __LINE__);
        return 0;
    }
    // 添加监听连接事件到红黑树节点中
    add_epoll(epfd, sock_fd);

    // 到此,以上流程全部正确走完
    // 客户端信息结构体的大小
    socklen_t addrlen = sizeof(my_cin);

    /*********与客户端互动区域_begin*********/
    // 存储连接的所有客户端描述符
    // str_newfd *arr_newfd;

    // arr_newfd->len
    // 新连接的客户端返回的描述符
    int newfd = -1;
    // 最下的客户端描述符

    int midfd = -1;
    ser_cli my_ser_cli;
    str_staff my_str_staff;

    while (1)
    {

        // ret返回就绪事件的个数,并将就绪的事件放入到
        // events这个结构体中,参3表示最多放入10个事件,
        // 参4的-1表示不关心是否超时
        int ret = epoll_wait(epfd, events, 10, -1);
        if (ret < 0 || ret > 10)
        {
            printf("epoll_wait on_success:%d\n", __LINE__);
            return 0;
        }
        /****走到这里,表示有事件准备就绪****/
        for (int i = 0; i < ret; i++)
        {
            
            // 客户端连接事件发生
            if (events[i].data.fd == sock_fd)
            {
                newfd = accept(sock_fd, (struct sockaddr *)&my_cin, &addrlen);
                if (newfd < 0)
                {
                    ERR_MSG("accept");
                    return -1;
                }
                if (add_epoll(epfd, newfd) < 0)
                {
                    printf("add_epoll errno%d\n", __LINE__);
                    return 0;
                }
                printf("newfd=%d连接成功\n", newfd);
                // 判断新描述符的大小,放入到顺序表中
                //  pai_arr_newfd(arr_newfd,newfd);
            }
            else
            {
                ser_cli my_ser_cli;
                str_staff my_str_staff;
                // 创建一个线程
                pthread_t tid;
                my_ser_cli.fd = events[i].data.fd;
                // 接收客户端数据,进入账号密码的判断,是root还是普通
                // 接收服务器的信息
                int ser_fd=my_ser_cli.fd;
                if (recv(my_ser_cli.fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
                {
                    printf("接收失败%d\n", __LINE__);
                    return 0;
                }
                if (my_ser_cli.CLI_SELECT == 3) // 用户选择退出
                {
                    
                    quit(my_ser_cli);
                }
                // 往下走说明是用户和root登陆
                // 当事件发生以后移除文件描述符
                my_ser_cli.events_i = i;
                my_ser_cli.db = db;
                my_ser_cli.fd = ser_fd;
                if (pthread_create(&tid, NULL, callBack, (void *)&my_ser_cli) != 0)
                {
                    printf("%ld线程创建失败%d\n", tid, __LINE__);
                    return 0;
                }
                remove_fd(&my_ser_cli);//账号下线,清楚其存在
            }
        }
    }
    /*********与客户端互动区域_end*********/
    // 释放资源
    return 0;
}

1.2服务器运行代码

#include "server.h"
int flag = 0;
int fd_flag = 0;
// 创建数据库并打开数据表
sqlite3 *Sqlite_Create(void)
{
    /*表格信息: 1.主键(int id),用于判断该账号是用户还是管理员
                 2.员工姓名(char name)
                 2.员工工号(int jobnumner)
                 3.员工年龄(int age)
                 4.当前薪资(float wage)
                 5.岗位名称(char post)
                 6.手机号(int phone )
                 7.入职时间 (char time)精确到日
                 8.是否在线 (state int) 1表示在线 0不在线*/
    // 存储SQL的报错信息
    char *errmsg = NULL;
    // 创建并打开数据库
    sqlite3 *db = NULL;
    if (sqlite3_open("./staff.db", &db) != SQLITE_OK)
    {
        printf("sqlite3_open errno %d\n", __LINE__);
        return NULL;
    }
    debuf_db = db;
    // 组装SQL语句创建数据表
    char sql[528] = "create table if not exists staff(id int,name char,jobnumber int,age int,wage float,post char,phone int,time char,state int,pass_w int);";
    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
        fprintf(stderr, "__%d__ sqlite3_exec: %s\n", __LINE__, errmsg);
        return NULL;
    }
    return db;
}

// 服务器 套接字->端口重启->绑定->监听
int sock_listen(void)
{
    // 一.创建套接字1.AF_INET默认为ip(7)协议 2.SOCK_STREAM默认为TCP
    // 3.0表示使用type对应的默认协议
    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0)
    {
        ERR_MSG("socket");
        goto OUT1;
    }

    // 端口快速启用
    int resue = 1;
    if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &resue, sizeof(resue)) < 0)
    {
        ERR_MSG("setsockopt");
        return -1;
    }
    // 填充服务器信息结构体
    my_ser.sin_family = AF_INET;            // IPv4协议指向填充
    my_ser.sin_port = htons(PORT);          // 将端口转换成网络字节
    my_ser.sin_addr.s_addr = inet_addr(IP); // IP地址转换成网络字节序
    // 绑定服务器的IP和端口
    if (bind(sock_fd, (struct sockaddr *)&my_ser, sizeof(my_ser)) < 0)
    {
        ERR_MSG("bind");
        goto OUT2;
    }
    // 将套接字设置为被动监听,最多监听128个
    if (listen(sock_fd, 128) < 0)
    {
        ERR_MSG("listen");
        goto OUT2;
    }
    return sock_fd;
OUT2:
    close(sock_fd);
OUT1:
    return 0;
}
// 红黑树监听事件信息的添加
int add_epoll(int epfd, int fd)
{
    // 将套接字的信息存入到event结构体中,为事件放入红黑树中做准备
    event.events = EPOLLIN; // 关注可读事件,套接字有数据可读时触发
    event.data.fd = fd;
    // 将event存放到套接字信息放入到红黑树中
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event) < 0)
    {
        printf("epoll_ctl on_success _%d_", __LINE__);
        return 0;
    }
    return 1;
}
int remove_epoll(int epfd, int fd)
{
    // 将套接字的信息存入到event结构体中,为事件放入红黑树中做准备
    event.data.fd = fd;
    // 将event存放到套接字信息放入到红黑树中

    if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0)
    {
        ERR_MSG("epoll_ctl");
        return 0;
    }
    return 1;
}
// 客户端的描述符在顺序表中添加后的排序
//  void paixu_arr_newfd(str_newfd *arr_newfd,int newfd)
//  {
//      int i,j,count;
//      arr_newfd->arr[arr_newfd->len].fd=newfd;
//      arr_newfd->len++;
//      for(i=1;i<=arr_newfd->len;i++)
//      {
//          count=0;
//          for(j=0;j<arr_newfd.)
//      }
//  }
// 资源的释放函数

// 创建一个线程处理客户端交互
void *callBack(void *arg)
{
    // 组装SQL语句
    char sql[256] = "";
    char **pres = NULL;
    int row, column;
    char *errmsg;
    int jobnumber, pass_w;
    ser_cli *my_ser_cli = (ser_cli *)arg;
    char debug[128] = "kkk";
    ser_cli my_ser_cli_C = *my_ser_cli;
    // 判断账号是否存在
    sprintf(sql, "select * from staff where jobnumber=%d;", my_ser_cli->staff_information.jobnumber);
    // printf("%s%d\n", debug,__LINE__);
    if (sqlite3_get_table(my_ser_cli->db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
    {
        printf("get_table_jobnumber error%s %d\n", errmsg, __LINE__);
        return 0;
    }
    else
    {
        if (row == 0)
        {
            // 账号不存在
            my_ser_cli->cli_n_p = 1; // 该位写1账号不存在
            my_ser_cli_C = *my_ser_cli;
            send(my_ser_cli->fd, &my_ser_cli_C, sizeof(my_ser_cli_C), 0);

            return 0;
        }
        // 判断密码是否与账号匹配
        sprintf(sql, "select * from staff where jobnumber=%d and pass_w=%d;", my_ser_cli->staff_information.jobnumber, my_ser_cli->staff_information.pass_w);
        if (sqlite3_get_table(my_ser_cli->db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
        {
            printf("get_table_pass_w error %d\n", __LINE__);
            return 0;
        }
        else
        {
            if (row == 0)
            {
                // 账号错误
                my_ser_cli->cli_n_p = 2; // 账号匹配密码不正确s
                my_ser_cli_C = *my_ser_cli;
                printf("密码不正确\n");
                send(my_ser_cli->fd, &my_ser_cli_C, sizeof(my_ser_cli_C), 0);
                return 0;
            }
            else // 判断是root还是用户
            {
                // 判断用户还是root
                sprintf(sql, "select * from staff where id=%d;", my_ser_cli->staff_information.key);
                if (sqlite3_get_table(my_ser_cli->db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
                {
                    printf("get_table_pass_w error %d\n", __LINE__);
                    return 0;
                }
                else

                {

                    if (row == 0 && my_ser_cli->CLI_SELECT == 1) // 管理员进错到用户
                    {

                        my_ser_cli->cli_n_p = 3; // 管理员进错到用户
                        my_ser_cli_C = *my_ser_cli;
                        send(my_ser_cli->fd, &my_ser_cli_C, sizeof(my_ser_cli_C), 0);
                        return 0;
                    }
                    else if (row == 0 && my_ser_cli->CLI_SELECT == 2) // 用户不能访问管理
                    {

                        my_ser_cli->cli_n_p = 4; // 用户不能访问管理
                        my_ser_cli_C = *my_ser_cli;
                        send(my_ser_cli->fd, &my_ser_cli_C, sizeof(my_ser_cli_C), 0);
                        return 0;
                    }
                    if (remove_epoll(epfd, my_ser_cli->fd) == 0)
                    {
                        printf("remove_epoll errno%d\n", __LINE__);
                        my_ser_cli->cli_n_p = 1; // 用户不能访问管理
                        my_ser_cli_C = *my_ser_cli;
                        send(my_ser_cli->fd, &my_ser_cli_C, sizeof(my_ser_cli_C), 0);
                        return 0;
                    }
                    // 走到这里,表示均匹配成功
                    my_ser_cli->cli_n_p = 5;
                    // 将员工号存到数组里,用于历史记录查询
                    add_jobnumber_A(my_ser_cli);
                    my_ser_cli_C = *my_ser_cli;
                    if(add_fd(my_ser_cli)==0)//判断账号是否重复登陆
                    {
                        //表示账号属于重复登陆
                        my_ser_cli_C.flag=0;//告诉客户端重复登陆
                        send(my_ser_cli->fd, &my_ser_cli_C, sizeof(my_ser_cli_C), 0);
                        return 0;
                    }
                    my_ser_cli_C.flag=1;//告诉客户端没有重复登陆
                    printf("%d %d\n",my_ser_cli_C.flag,__LINE__);
                    send(my_ser_cli->fd, &my_ser_cli_C, sizeof(my_ser_cli_C), 0);//走到这里,表示客户端连接成功
                    while (1)
                    {

                        switch (my_ser_cli->CLI_SELECT)
                        {
                        case 1: // 控制管理员界面
                            if (root_ui(my_ser_cli) == 0)
                            {
                                pthread_detach(tid);
                                return 0;
                            }
                            break;
                        case 2: // 员工管理员界面
                            if (user_ui(my_ser_cli) == 0)
                            {
                                return 0;
                            }
                            break;
                        default:
                            break;
                        }
                    }
                }
            }
        }
        return 0;
    }

    return 0;
}
// 员工历史记录添加
int add_jobnumber_A(ser_cli *my_ser_cli_H)
{
    // 重新保存
    ser_cli my_ser_cli = *my_ser_cli_H;
    jobnumber_A[0].flag = flag++; // 存放下一次新的工号存储位置
    printf("flag=%d\n", flag);
    // 判断该账号是否以及存在于数组
    for (int i = 0; i < 10; i++)
    {
        if (jobnumber_A[i].staff_information.jobnumber == my_ser_cli.staff_information.jobnumber) // 已经在数组中
        {
            return 0; // 不做添加
        }
    }
    // 走到这里表示该账号不存在数组中,添加
    jobnumber_A[jobnumber_A[0].flag].staff_information.jobnumber = my_ser_cli.staff_information.jobnumber;
}
int root_ui(ser_cli *my_ser_cli)
{
    char sql[528] = "";
    ser_cli my_ser_cli_ui;
    ser_cli my_ser_cli_ui_1; // 除case1以外使用的
    str_staff my_str_staff;
    // my_ser_cli_ui.staff_information = my_str_staff;
    my_ser_cli_ui.fd = my_ser_cli->fd;
    printf("\n管理%d进入root界面%d\n", my_ser_cli->staff_information.jobnumber, __LINE__);
    char **pres = NULL;
    int row, column;
    char *errmsg;
    int jobnumber, pass_w;
    // 接收管理员操作指令码
    while (1)
    {
        my_ser_cli_ui.staff_information.jobnumber = 0;
        if (recv(my_ser_cli->fd, &my_ser_cli_ui, sizeof(my_ser_cli_ui), 0) < 0)
        {

            ERR_MSG("recv");
            return 0;
        }
        my_ser_cli_ui_1 = my_ser_cli_ui; // 备份,防止2345的操作影响到1
        my_ser_cli_ui_1.db = my_ser_cli->db;
        my_ser_cli_ui_1.fd = my_ser_cli->fd;
        switch (my_ser_cli_ui.CLI_SELECT_H)
        {
        case 1: // 添加员工信息
                // 判断账号是否存在
            sprintf(sql, "select * from staff where jobnumber=%d;", my_ser_cli_ui.staff_information.jobnumber);
            // printf("%s%d\n", debug,__LINE__);
            if (sqlite3_get_table(my_ser_cli->db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
            {
                printf("get_table_jobnumber error%s %d\n", errmsg, __LINE__);
                return 0;
            }
            if (row != 0) // 表示工号已经存在
            {
                my_ser_cli_ui.CLI_SELECT = 1;
                if (send(my_ser_cli->fd, &my_ser_cli_ui, sizeof(my_ser_cli_ui), 0) < 0)
                {
                    ERR_MSG("recv");
                    return 0;
                }
                return 0;
            }
            if (my_ser_cli->staff_information.jobnumber)
            {
                sprintf(sql, "insert into staff values (%d, '%s', %d, %d, %f, '%s', %d, '%s', %d, %d);", my_ser_cli_ui.staff_information.key,
                        my_ser_cli_ui.staff_information.name, my_ser_cli_ui.staff_information.jobnumber, my_ser_cli_ui.staff_information.age, my_ser_cli_ui.staff_information.wage,
                        my_ser_cli_ui.staff_information.post, my_ser_cli_ui.staff_information.phone, my_ser_cli_ui.staff_information.time, my_ser_cli_ui.staff_information.state,
                        my_ser_cli_ui.staff_information.pass_w);
                if (sqlite3_exec(my_ser_cli->db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    fprintf(stderr, "__%d__ sqlite3_exec: %s\n", __LINE__, errmsg);
                    return 0;
                }

                // 告诉客户端注册完毕
                if (send(my_ser_cli->fd, &my_ser_cli_ui, sizeof(my_ser_cli_ui), 0) < 0)
                {
                    ERR_MSG("recv");
                    return 0;
                }
            }
            break;

        case 2:
            root_xiugai_ser(&my_ser_cli_ui_1); // 修改员工信息
            break;
        case 3:
            root_chaxun_user(&my_ser_cli_ui_1); // 查询员工信息
            break;
        case 4:
            root_lishi_user(&my_ser_cli_ui_1); // 发送历史查询记录
            break;
        case 5:
            printf("管理系统退出成功\n");
            return 0;
            break;
        default:
            printf("输入错误,请重新输入\n");
            return 0;
            break;
        }
    }
}
// 服务器向root发送历史记录表
int root_lishi_user(ser_cli *my_ser_cli_H)
{
    printf("root调用历史信息表\n");
    char **pres = NULL;
    int row, column;
    char *errmsg = NULL;
    int jobnumber, pass_w;
    char sql[528] = "";
    int index = 10;
    printf("flag_A=%d\n", flag);
    for (int i = 0; i < flag; i++)
    {
        // 将存在的所有放到数组里面
        memset(sql, '0', sizeof(sql));
        sprintf(sql, "select * from staff where jobnumber=%d;", jobnumber_A[i].staff_information.jobnumber);
        if (sqlite3_get_table(my_ser_cli_H->db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
        {
            printf("get_table_jobnumber error%s %d\n", errmsg, __LINE__);
            return 0;
        }
        if (row == 0) // 表示没有找到,向服务器发送信息
        {
            printf("出现错误 工号不存在%d\n", __LINE__);
        }
        else
        {
            // 走到这里表示工号存在,将员工信息填充发送带客户端
            // 发送

            jobnumber_A[i].staff_information.key = atoi(pres[index++]);
            strcpy(jobnumber_A[i].staff_information.name, pres[index++]);
            jobnumber_A[i].staff_information.jobnumber = atoi(pres[index++]);
            jobnumber_A[i].staff_information.age = atoi(pres[index++]);
            jobnumber_A[i].staff_information.wage = atof(pres[index++]);
            strcpy(jobnumber_A[i].staff_information.post, pres[index++]);
            jobnumber_A[i].staff_information.phone = atoi(pres[index++]);
            strcpy(jobnumber_A[i].staff_information.time, pres[index++]);
            jobnumber_A[i].staff_information.state = atoi(pres[index++]);
            jobnumber_A[i].staff_information.pass_w = atoi(pres[index++]);
        }
        if (send(my_ser_cli_H->fd, jobnumber_A, sizeof(*(jobnumber_A)), 0) < 0)
        {
            ERR_MSG("recv");
            return 0;
        }
        printf("历史记录表成功发送\n");
    }
}
int root_chaxun_user(ser_cli *my_ser_cli_H)
{
    if (my_ser_cli_H->staff_information.key == 1)
        printf("root进入查询界面%d\n", __LINE__);
    else
        printf("用户进入查询界面%d\n", __LINE__);
    ser_cli my_ser_cli = *my_ser_cli_H;
    char **pres = NULL;
    int row, column;
    char *errmsg = NULL;
    int jobnumber, pass_w;
    char sql[528] = "";
    // printf("SELETC=%d line:%d\n", my_ser_cli.CLI_SELECT, __LINE__);
    switch (my_ser_cli.CLI_SELECT)
    {
    case 1:
        // 进入按员工号查找
        sprintf(sql, "select * from staff where jobnumber=%d;", my_ser_cli.staff_information.jobnumber);
        if (sqlite3_get_table(my_ser_cli.db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
        {
            printf("get_table_jobnumber error%s %d\n", errmsg, __LINE__);
            return 0;
        }
        if (row == 0) // 表示没有找到,向服务器发送信息
        {
            printf("debuf%d\n", __LINE__);
            my_ser_cli.CLI_SELECT = 2; // 0是修改,2是不存在
            if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
            {
                ERR_MSG("recv");
                return 0;
            }
        }
        else
        {
            // 走到这里表示工号存在,将员工信息填充发送带客户端
            // 发送

            int index = 10;

            my_ser_cli.staff_information.key = atoi(pres[index++]);
            strcpy(my_ser_cli.staff_information.name, pres[index++]);
            my_ser_cli.staff_information.jobnumber = atoi(pres[index++]);
            my_ser_cli.staff_information.age = atoi(pres[index++]);
            my_ser_cli.staff_information.wage = atof(pres[index++]);
            strcpy(my_ser_cli.staff_information.post, pres[index++]);
            my_ser_cli.staff_information.phone = atoi(pres[index++]);
            strcpy(my_ser_cli.staff_information.time, pres[index++]);
            my_ser_cli.staff_information.state = atoi(pres[index++]);
            my_ser_cli.staff_information.pass_w = atoi(pres[index++]);

            my_ser_cli.CLI_SELECT = 0; // 0是查询成功
            if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
            {
                ERR_MSG("recv");
                return 0;
            }
        }
        break;
    case 2:
        printf("进入按手机号查询");
        sprintf(sql, "select * from staff where phone=%d;", my_ser_cli.staff_information.phone);
        if (sqlite3_get_table(my_ser_cli.db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
        {
            printf("get_table_jobnumber error%s %d\n", errmsg, __LINE__);
            return 0;
        }
        if (row == 0) // 表示没有找到,向服务器发送信息
        {
            my_ser_cli.CLI_SELECT = 2; // 0是修改,2是不存在
            if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
            {
                ERR_MSG("recv");
                return 0;
            }
        }
        else
        {
            // 进入这表示手机存在,填充信息
            int index = 10;

            my_ser_cli.staff_information.key = atoi(pres[index++]);
            strcpy(my_ser_cli.staff_information.name, pres[index++]);
            my_ser_cli.staff_information.jobnumber = atoi(pres[index++]);
            my_ser_cli.staff_information.age = atoi(pres[index++]);
            my_ser_cli.staff_information.wage = atof(pres[index++]);
            strcpy(my_ser_cli.staff_information.post, pres[index++]);
            my_ser_cli.staff_information.phone = atoi(pres[index++]);
            strcpy(my_ser_cli.staff_information.time, pres[index++]);
            my_ser_cli.staff_information.state = atoi(pres[index++]);
            my_ser_cli.staff_information.pass_w = atoi(pres[index++]);

            my_ser_cli.CLI_SELECT = 0; // 0是查询成功
            if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
            {
                ERR_MSG("recv");
                return 0;
            }
        }
        break;
    default:
        printf("未定义指令码%d %d\n", my_ser_cli.CLI_SELECT, __LINE__);
        return 0;
        break;
    }
}
int root_xiugai_ser(ser_cli *my_ser_cli_H)
{

    printf("进入修改界面%d\n", __LINE__);
    ser_cli my_ser_cli = *my_ser_cli_H;
    char **pres = NULL;
    int row, column;
    char *errmsg = NULL;
    int jobnumber, pass_w;
    char sql[528] = "";
    char buf[128] = ""; // 辨别是员工号还是手机号
    int key = -1;       // 判断是否修改成功,跳出Switch时,值不为0,则修改成功
    // 判断是根据<1>员工号还是<2>手机号码查找
    switch (my_ser_cli.CLI_SELECT)
    {
    case 1:

        sprintf(sql, "select * from staff where jobnumber=%d;", my_ser_cli.staff_information.jobnumber);
        if (sqlite3_get_table(my_ser_cli.db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
        {
            printf("debuf%d\n", __LINE__);
            printf("get_table_jobnumber error%s %d\n", errmsg, __LINE__);
            return 0;
        }
        if (row == 0) // 表示没有找到,向服务器发送信息
        {
            printf("debuf%d\n", __LINE__);
            my_ser_cli.CLI_SELECT = 2; // 0是修改,2是不存在
            if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
            {
                ERR_MSG("recv");
                return 0;
            }
        }
        else // 走到这里,表示根据员工号找到对应的员工信息
        {
            key = 1;

            // 根据flag判断修改什么
            switch (my_ser_cli.flag)
            {
            case 1:

                sprintf(sql, "update staff set name='%s' where jobnumber=%d;", my_ser_cli.staff_information.name, my_ser_cli.staff_information.jobnumber);

                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);
                    key = 0;
                }
                break;
            case 2:
                sprintf(sql, "update staff set age=%d where jobnumber=%d;", my_ser_cli.staff_information.age, my_ser_cli.staff_information.jobnumber);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);

                    key = 0;
                }
                break;
            case 3:
                sprintf(sql, "update staff set wage=%f where jobnumber=%d;", my_ser_cli.staff_information.wage, my_ser_cli.staff_information.jobnumber);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);

                    key = 0;
                }
                break;
            case 4:
                sprintf(sql, "update staff set post='%s' where jobnumber=%d;", my_ser_cli.staff_information.post, my_ser_cli.staff_information.jobnumber);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);

                    key = 0;
                }
                break;
            case 5:
                printf("update staff set phone=%d where jobnumber=%d;", my_ser_cli.staff_information.phone, my_ser_cli.staff_information.jobnumber);
                sprintf(sql, "update staff set phone=%d where jobnumber=%d;", my_ser_cli.staff_information.phone, my_ser_cli.staff_information.jobnumber);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);

                    key = 0;
                }
                break;
            case 6:
                sprintf(sql, "update staff set time='%s' where jobnumber=%d;", my_ser_cli.staff_information.time, my_ser_cli.staff_information.jobnumber);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);

                    key = 0;
                }
                break;
            case 7:
                printf("1111111\n");
                printf("update staff set pass_w=%d where jobnumber=%d\n;", my_ser_cli.staff_information.pass_w, my_ser_cli.staff_information.jobnumber);
                sprintf(sql, "update staff set pass_w=%d where jobnumber=%d;", my_ser_cli.staff_information.pass_w, my_ser_cli.staff_information.jobnumber);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    key = 0;
                    printf("debuf%d\n", __LINE__);
                }
                break;
            }
            if (key) // 如果为假,表示失败,发送失败给客户端
            {
                my_ser_cli.CLI_SELECT = 0; // 0是修改,其他是失败
                if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
                {
                    ERR_MSG("recv");
                    return 0;
                }
                return 1;
            }
        }
        break;
    case 2:
        // 因为1个变量不能存放判断的手机号和要修改的手机号,因此将判断的手机放到key变量中
        sprintf(sql, "select * from staff where phone=%d;", my_ser_cli.staff_information.key);
        if (sqlite3_get_table(my_ser_cli.db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
        {
            printf("get_table_jobnumber error%s %d\n", errmsg, __LINE__);
            return 0;
        }
        if (row == 0) // 表示没有找到,向服务器发送信息
        {
            my_ser_cli.CLI_SELECT = 2; // 0是修改,2是不存在
            if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
            {
                ERR_MSG("recv");
                return 0;
            }
        }
        else // 走到这里,表示根据员工号找到对应的员工信息
        {

            key = 1;
            // 根据flag判断修改什么
            switch (my_ser_cli.flag)
            {
            case 1:

                sprintf(sql, "update staff set name='%s' where id=%d;", my_ser_cli.staff_information.name, my_ser_cli.staff_information.key);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    key = 0;
                    printf("debuf%d\n", __LINE__);
                }
                break;
            case 2:
                sprintf(sql, "update staff set age=%d where phone=%d;", my_ser_cli.staff_information.age, my_ser_cli.staff_information.key);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);
                    key = 0;
                }
                break;
            case 3:
                sprintf(sql, "update staff set wage=%f where phone=%d;", my_ser_cli.staff_information.wage, my_ser_cli.staff_information.key);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);
                    key = 0;
                }
                break;
            case 4:
                sprintf(sql, "update staff set post='%s' where phone=%d;", my_ser_cli.staff_information.post, my_ser_cli.staff_information.key);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);
                    key = 0;
                }
                printf("手机号查找成功 %d\n", __LINE__);
                break;
            case 5:
                sprintf(sql, "update staff set phone=%d where phone=%d;", my_ser_cli.staff_information.phone, my_ser_cli.staff_information.key);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);
                    key = 0;
                }
                break;
            case 6:
                sprintf(sql, "update staff set time='%s' where phone=%d;", my_ser_cli.staff_information.time, my_ser_cli.staff_information.key);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);
                    key = 0;
                }
                break;
            case 7:
                sprintf(sql, "update staff set pass_w=%d where phone=%d;", my_ser_cli.staff_information.pass_w, my_ser_cli.staff_information.key);
                if (sqlite3_exec(my_ser_cli.db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
                {
                    printf("debuf%d\n", __LINE__);
                    key = 0;
                }
                break;
            }
            if (key) // 如果为假,表示失败,发送失败给客户端
            {
                my_ser_cli.CLI_SELECT = 0; // 0是修改成功 1是修改失败
                if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
                {
                    ERR_MSG("recv");
                    return 0;
                }
                printf("root修改信息成功 %d\n", __LINE__);
                return 1;
            }
            break;
        }
    default:
        printf("未定义指令码%d %d\n", my_ser_cli.CLI_SELECT, __LINE__);
        return 0;
        break;
    }
    return 1;
}
int user_ui(ser_cli *my_ser_cli)
{
    char sql[528] = "";
    ser_cli my_ser_cli_ui;
    ser_cli my_ser_cli_ui_1; // 除case1以外使用的
    my_ser_cli_ui_1.fd = my_ser_cli->fd;
    str_staff my_str_staff;
    // my_ser_cli_ui.staff_information = my_str_staff;
    my_ser_cli_ui.fd = my_ser_cli->fd;
    printf("用户%d进入用户界面\n", my_ser_cli->staff_information.jobnumber);
    char **pres = NULL;
    int row, column;
    char *errmsg;
    int jobnumber, pass_w;
    // 接收管理员操作指令码
    while (1)
    {
        my_ser_cli_ui.staff_information.jobnumber = 0;
        if (recv(my_ser_cli->fd, &my_ser_cli_ui, sizeof(my_ser_cli_ui), 0) < 0)
        {

            ERR_MSG("recv");
            return 0;
        }
        my_ser_cli_ui_1 = my_ser_cli_ui; // 备份,防止2345的操作影响到1
        my_ser_cli_ui_1.db = my_ser_cli->db;
        my_ser_cli_ui_1.fd = my_ser_cli->fd;
        switch (my_ser_cli_ui.CLI_SELECT_H)
        {
        case 1: // 查询个人信息
            root_chaxun_user(&my_ser_cli_ui_1);
            break;
        case 2: // 修改个人信息
            root_xiugai_ser(&my_ser_cli_ui_1);
            break;
        case 3: // 退出管理系统
            return 0;
            break;
        default:
            printf("输入错误,请重新输入\n");
            return 0;
            break;
        }
    }
}
int quit(ser_cli my_ser_cli)
{
    printf("客户端%d退出\n", my_ser_cli.fd);
    remove_epoll(epfd, my_ser_cli.fd);
    close(my_ser_cli.fd);
    return 0;
}
int add_fd(ser_cli *my_ser_cli_H)
{
    ser_cli my_ser_cli = *my_ser_cli_H;
    // 用户登录后添加账号信息到数组中,判断是否在线
    for (int i = 0; i < 10; i++)
    {
        if (my_ser_cli.staff_information.jobnumber == fd_A[i]) // 表示账号在线,不能重复登陆
        {
            printf("账号%d重复登陆 line:%d\n", my_ser_cli.staff_information.jobnumber, __LINE__);
            return 0;
        }
    }
    if (flag == 10) // 重置
        flag = 0;
    fd_A[flag++] = my_ser_cli.staff_information.jobnumber;
    return 1;
}
int remove_fd(ser_cli *my_ser_cli_H)
{
    ser_cli my_ser_cli = *my_ser_cli_H;
    for (int i = 0; i < 10; i++)
    {
        if (my_ser_cli.staff_information.jobnumber == fd_A[i]) // 找到下线账号
        {
            fd_A[i] = 0; // 将账号信息删除
            flag--;
            printf("账号%d下线 line:%d\n", my_ser_cli.staff_information.jobnumber, __LINE__);
            return 0;
        }
    }
}

1.3服务器头文件

#ifndef __CLIENT_H__
#define __CLIENT_H__
/******头文件区域*******/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <sqlite3.h>
#include <pthread.h>
/******引用区域*******/
// 创建数据库并打开数据表
sqlite3 * Sqlite_Create(void);
// 服务器 套接字->端口重启->绑定->监听
int sock_listen(void);
// 红黑树监听事件信息的添加
int add_epoll(int epfd, int fd);
int remove_epoll(int epfd,int fd);
//添加线程管理交互界面
void *callBack(void *arg);

#define DEBUG_LINE printf("Debug line:%d\n",__LINE__)
// 错误码
#define ERR_MSG(msg)                           \
    do                                         \
    {                                          \
        fprintf(stderr, "line:%d ", __LINE__); \
        perror(msg);                           \
    } while (0)

#define PORT 6666            // 服务器端口
#define IP "192.168.250.100" // 服务器IP地址
#define MAX 10   //顺序表最大容量
// 信息结构体,因为使用IPv4,因此使用sockaddr_in填充bind的第二个参数
struct sockaddr_in my_ser; // 服务器信息结构体
struct sockaddr_in my_cin; // 保存客户端信息结构体
// 员工信息结构体
typedef struct staff
{
    int key;       // 判断是用户还是管理员 1是管理 2是用户
    char name[128];     // 员工姓名
    int jobnumber; // 员工工号
    int age;       // 员工年龄
    float wage;    // 当前的薪资
    char post[128];     // 岗位名称
    int phone;     // 手机号
    char time[128];     // 精确到日,入职时间
    int state;     // 是否在线 1表示在线
    int pass_w;    // 密码
} str_staff;
// 服务器与客户端通信的结构体
typedef struct info
{
    int fd;//客户端的描述符
    int CLI_SELECT;                // 登陆时选择的操作 1管理员登陆,2是用户登陆 3是退出
    int CLI_SELECT_H;  //登陆后选择的操作 1.添加员工信息 2.修改员工记录 3.查询员工记 4.查询历史 5,退出管理
    int events_i;       //保存红黑树数组的下标
    int cli_n_p; //高账号密码权力的匹配程度,1表示账号不存在2表示密码不正确3表示不是特权4表示不是用户5均成功
    int flag;//进入2级界面选项后,传递的自定义标志位
    sqlite3 *db;  
    str_staff staff_information; // 员工信息结构体
} ser_cli;
//客户端发送信息
int ser_cli_tongxing(ser_cli * my_str_staff,int sock_fd);
int root_ui(ser_cli *my_str_staff);
int user_ui(ser_cli *my_ser_staff);
//添加员工信息
ser_cli *add_root_and_user(ser_cli *my_ser_cli_ui);
//修改员工信息
int root_xiugai_ser(ser_cli *my_ser_cli_ui_1);
//root查询到员工信息
int root_chaxun_user(ser_cli *my_str_staff); 
//添加员工信息到数组中
int add_jobnumber_A(ser_cli *my_ser_cli_H);
//root查询历史信息
int root_lishi_user(ser_cli *my_ser_cli_H);
//判断账号是否重复登陆
int add_fd(ser_cli *my_ser_cli_H);
int remove_fd(ser_cli *my_ser_cli_H);
//退出函数
int quit(ser_cli my_ser_cli);
typedef struct newfd
{
    int fd;
}my_fd;
typedef struct fd_1
{
    my_fd arr[MAX];
    int len;
}str_newfd;
// 保存就绪事件的信息,用于移植到红黑树中
struct epoll_event event;
// 存放就绪事件描述符的数组
sqlite3 * debuf_db;
struct epoll_event events[10];
pthread_t tid;
int fd_A[10];
ser_cli jobnumber_A[10];
int epfd ;//红黑树根节点
#endif

2.客户端代码

2.1客户端函数入口

#include "client.h"
int main(int argc, char const *argv[])
{
    // 创建套接字
    int cfd = socket(AF_INET, SOCK_STREAM, 0);
    if (cfd < 0)
    {
        ERR_MSG("socket");
        goto OUT1;
    }
    // 连接服务器
    // 1.填充服务器的信息
    my_ser.sin_family = AF_INET;
    my_ser.sin_port = htons(PORT);
    my_ser.sin_addr.s_addr = inet_addr(IP);
    // 连接
    if (connect(cfd, (struct sockaddr *)&my_ser, sizeof(my_ser)) < 0)
    {
        ERR_MSG("connet");
        goto OUT2;
    }
    printf("connect server success cfd=%d %d\n",cfd,__LINE__);
    // 用户的选择
    int key = -1;
    ser_cli my_ser_cli; //通信结构体
    str_staff my_str_staff; //员工信息
    while (1)
    {
        printf("<*************************> 1\n");
        printf("<********1.管理员登陆******> 1\n");
        printf("<********2.用户登陆*******> 1\n");
        printf("<********3.退出***********> 1\n");
        printf("<************************> 1\n");
        printf("\n请选择你要进行的操作:");

        scanf("%d", &key);
        switch (key)
        {
        case 1:
            // 改变对应的结构体信息
            my_ser_cli.CLI_SELECT = 1;
            my_ser_cli.staff_information = my_str_staff;
            my_ser_cli.fd=cfd;
            my_ser_cli.staff_information.key=1;
            if(ser_cli_tongxing(&my_ser_cli,cfd)==1)
            {
                //返回值为1表示管理员验证成功
                //进入管理员控制界面
                my_ser_cli.fd=cfd;
                root_ui(&my_ser_cli);
            }
            break;
        case 2:
            // 改变对应的结构体信息
            my_ser_cli.CLI_SELECT = 2;
            my_ser_cli.staff_information = my_str_staff;
            my_ser_cli.staff_information.key=2;
            my_ser_cli.fd=cfd;
            if(ser_cli_tongxing(&my_ser_cli,cfd)==1)
            {
                //表示用户登陆成功,进入用户控制界面
                user_ui(&my_ser_cli);
            }
            break;
        case 3:
            // 改变对应的结构体信息
            my_ser_cli.CLI_SELECT = 3;
            if (send(cfd,&my_ser_cli, sizeof(my_str_staff), 0) < 0)
            {
                ERR_MSG("send");
            }
            close(cfd);
            printf("退出成功\n");
            exit(1);
            break;
        default:
            printf("输入错误,请重新输入:\n");
            break;
        }
    }
    // 关闭套接字
    close(cfd);
    return 0;
OUT2:
    close(cfd);
OUT1:
    return cfd;
    return 0;
}

2.2客户端执行代码

#include "client.h"

int ser_cli_tongxing(ser_cli *my_str_staff, int sock_fd)
{

    ser_cli my_str_staff_1;
    my_str_staff_1.CLI_SELECT = my_str_staff->CLI_SELECT;
    my_str_staff_1.staff_information = my_str_staff->staff_information;
    int jobnumber = 0;
    int pass_w = 0;
OUT1:
    printf("输入你的工号:");
    scanf("%d", &jobnumber);
    user_jobnumber=jobnumber;
    if (jobnumber == 0)
    {
        printf("输入失败,请重新输入%d\n", __LINE__);
        goto OUT1;
    }
    while (getchar() != 10)
        ;
    my_str_staff_1.staff_information.jobnumber = jobnumber;
OUT2:
    printf("输入你的密码:");
    scanf("%d", &pass_w);
    if (jobnumber == 0)
    {
        printf("输入失败,请重新输入%d\n", __LINE__);
        goto OUT2;
    }
    while (getchar() != 10)
        ;
    my_str_staff_1.staff_information.pass_w = pass_w;
    // printf("jobnumber=%d\n",my_str_staff_1.staff_information.jobnumber);
    // 账号密码输入完毕,请求服务器登陆
    // printf("pass_w=%d\n",my_str_staff_1.staff_information.pass_w);
    send(sock_fd, &my_str_staff_1, sizeof(my_str_staff_1), 0);
    // 接收信息
    if (recv(sock_fd, &my_str_staff_1, sizeof(my_str_staff_1), 0) < 0)
    {
        ERR_MSG("recv");
        return 0;
    }
    printf("my_str_staff_1.cli_n_p==%d\n", my_str_staff_1.cli_n_p);
    // 根据接收到的信息判断
    if (my_str_staff_1.cli_n_p == 1)
    {
        printf("工号不正确,请重新输入\n");
        return 0;
    }
    else if (my_str_staff_1.cli_n_p == 2)
    {
        printf("密码不正确,请重新输入\n");
        return 0;
    }
    else if (my_str_staff_1.cli_n_p == 3)
    {
        printf("请从管理员模式登陆\n");
        return 0;
    }
    else if (my_str_staff_1.cli_n_p == 4)
    {
        printf("员工不得访问root权限\n");
        return 0;
    }
    else if (my_str_staff_1.cli_n_p == 5)
    {
        if(my_str_staff_1.flag==0)//表示账号重复登陆了
        {
            printf("你的账号正在登陆中\n");
            exit(1);
        }
        printf("登陆成功 %d\n",__LINE__);
        return 1;
    }
    printf("接收错误\n");
    return 0;
}

// 管理员控制界面
int root_ui(ser_cli *my_str_staff)
{
    int key = -1;
    while (1)
    {
        printf("<****************************> 1\n");
        printf("<*********管理操作系统********> 1\n");
        printf("<********1.添加员工信息*******> 1\n");
        printf("<********2.修改员工信息*******> 1\n"); // 两种方式 工号 手机号
        printf("<********3.查询员工信息*******> 1\n"); // 两种方式 工号 手机号
        printf("<********4.查询历史记录*******> 1\n");
        printf("<********5.退出管理系统*******> 1\n");
        printf("<****************************> 1\n");
        printf("\n请选择你要进行的操作:");
        scanf("%d", &key);
        switch (key)
        {
        case 1:
            add_root_and_user(my_str_staff);
            break;
        case 2:
            root_xiugai_user(my_str_staff); // 修改员工信息
            break;
        case 3:
            chaxun_user(my_str_staff); //root界面和用户界面均能掉
            break;
        case 4:
            root_chaxun_lishi(my_str_staff);
            break;
        case 5:
            my_str_staff->CLI_SELECT_H = 5;
            if (send(my_str_staff->fd, my_str_staff, sizeof(*(my_str_staff)), 0) < 0)
            {
                ERR_MSG("send");
                return 0;
            }
            printf("管理系统退出成功\n");
            close(my_str_staff->fd);
            exit(1);
            break;
        default:
            printf("输入错误,请重新输入\n");
            break;
        }
    }
}
// 进入用户控制界面
int user_ui(ser_cli *my_str_staff)
{
    int key = -1;

    while (1)
    {

        printf("<****************************> 1\n");
        printf("<*********员工操作系统********> 1\n");
        printf("<********1.查询个人信息*******> 1\n");
        printf("<********2.修改个人信息*******> 1\n");
        printf("<********3.退出管理系统*******> 1\n");
        printf("<****************************> 1\n");
        printf("\n请选择你要进行的操作:");
        scanf("%d", &key);
        switch (key)
        {
        case 1:
            user_chaxun(my_str_staff);
            break;
        case 2:
            user_xiugai(my_str_staff);
            break;
        case 3:
            printf("退出成功\n");
            exit(1);
            break;
        default:
            printf("输入错误,请重新输入%d\n", __LINE__);
            break;
        }
    }
}
//员工查询个人信息
int user_chaxun(ser_cli *my_ser_cli_H)
{
    printf("员工进入查询界面 line:%d\n",__LINE__);
    ser_cli my_ser_cli = *my_ser_cli_H;
    my_ser_cli.fd = my_ser_cli_H->fd;
    int key = -1;
    while (1)
    {
        printf("查询方式 1<工号> 2.退出查询\n");
        printf("请输入>>>>");
        scanf("%d", &key);
        switch (key)
        {
        case 1:
            my_ser_cli.CLI_SELECT = 1;//高速服务器按照工号查询
            my_ser_cli.CLI_SELECT_H=1;//二级界面选项,
            my_ser_cli.staff_information.jobnumber=user_jobnumber;
            /*输出查询信息*/
            root_chaxun_user(&my_ser_cli);
            break;
        case 2:
            printf("用户退出成功\n");
            return 0;
            break;
        default:
            printf("输入错误,重新输入%d\n", __LINE__);
            break;
        }
    }
    
}
//员工修改个人密码
int user_xiugai(ser_cli *my_ser_cli_H)
{
    ser_cli my_ser_cli=*my_ser_cli_H;
    printf("1<修改密码> 2<退出界面>\n");
    int key=-1;
    my_ser_cli.CLI_SELECT=1;//告诉服务按照员工号查询后修改
    my_ser_cli.CLI_SELECT_H=2;//引导服务器二级界面的选择
    my_ser_cli.flag=7;//引导服务器修改密码
    my_ser_cli.staff_information.jobnumber=user_jobnumber;
    int buf;
    printf("请输入>>>>");
    scanf("%d",&key);
    
    switch(key)
    {
        case 1:
            printf("修改后的密码>>:");
            scanf("%d",&buf);
            my_ser_cli.staff_information.pass_w=buf;
            xiugai_user_to_ser(&my_ser_cli,7);
            break;
        case 2:
            printf("用户退出成功\n");
            return 0;
            break;
    }
}
//root查询所有历史
int root_chaxun_lishi(ser_cli *my_ser_cli_H)
{
    // 重新保存
    printf("最多查询当前10位\n");
    ser_cli my_ser_cli = *my_ser_cli_H;
    ser_cli my_ser_cli_A[10];
    my_ser_cli.CLI_SELECT_H = 4; // 提示服务器进入哪一步
    if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
    {
        ERR_MSG("send");
        return 0;
    }
    //接收历史查询信息
    printf("size=%ld\n",sizeof(*(my_ser_cli_A)));
    if(recv(my_ser_cli_H->fd,my_ser_cli_A,sizeof(*(my_ser_cli_A)),0)<0)
    {
        ERR_MSG("send");
        return 0;
    }
    for(int i=0;i<my_ser_cli_A->flag+1;i++)
    {
        printf("1.<<<<工号:%d的信息>>>>>\n",my_ser_cli_A[i].staff_information.jobnumber);
        printf("id        = %d\n", my_ser_cli_A[i].staff_information.key);
        printf("name      = %s\n",my_ser_cli_A[i].staff_information.name);
        printf("jobnumber = %d\n", my_ser_cli_A[i].staff_information.jobnumber);
        printf("age       = %d\n", my_ser_cli_A[i].staff_information.age);
        printf("wage      = %2.f\n", my_ser_cli_A[i].staff_information.wage);
        printf("phone     = %d\n", my_ser_cli_A[i].staff_information.phone);
        printf("time      = %s\n", my_ser_cli_A[i].staff_information.time);
        printf("state     = %d\n", my_ser_cli_A[i].staff_information.state);
        printf("pass_w    = %d\n", my_ser_cli_A[i].staff_information.pass_w);
        printf("\n");
    }
    printf("查询成功 是否退出(Y/N)\n");
    char key;
    while(getchar()!=10);
    scanf("%c",&key);
    while(getchar()!=10);
    if(key=='y'||key=='Y')
    return 0;
    else
    {
        sleep(10);
    }
}
// 添加员工
ser_cli *add_root_and_user(ser_cli *my_ser_cli_ui)
{
    ser_cli my_ser_cli;
    my_ser_cli.fd = my_ser_cli_ui->fd;
    printf("是否为管理1<是> 2<不是>:");
    int key = -1;
    scanf("%d", &key);
    my_ser_cli.staff_information.key = key;
    while (getchar() != 10)
        ;
    printf("key=%d\n", my_ser_cli.staff_information.key);

    printf("输入员工姓名:");
    char name[128] = "";
    scanf("%s", name);
    printf("name=%s", name);
    strcpy(my_ser_cli.staff_information.name, name);
    while (getchar() != 10)
        ;
    printf("name=%s\n", my_ser_cli.staff_information.name);

    printf("输入员工工号:");
    key = -1;
    scanf("%d", &key);
    if (key == 0)
    {
        printf("工号不可为0\n");
    }
    my_ser_cli.staff_information.jobnumber = key;
    while (getchar() != 10)
        ;
    printf("jobnumber=%d\n", my_ser_cli.staff_information.jobnumber);

    printf("输入员工年龄:");
    key = -1;
    scanf("%d", &key);
    my_ser_cli.staff_information.age = key;
    while (getchar() != 10)
        ;

    printf("age=%d\n", my_ser_cli.staff_information.age);

    printf("输入员工薪资:");
    float wage = -1;
    scanf("%f", &wage);
    my_ser_cli.staff_information.wage = key;
    while (getchar() != 10)
        ;
    printf("wage=%f\n", my_ser_cli.staff_information.wage);

    printf("输入员工岗位:");
    char post[128] = "";
    scanf("%s", post);
    strcpy(my_ser_cli.staff_information.post, post);
    while (getchar() != 10)
        ;
    printf("post=%s\n", my_ser_cli.staff_information.post);

    printf("输入员工手机:");
    key = -1;
    scanf("%d", &key);
    my_ser_cli.staff_information.phone = key;
    while (getchar() != 10)
        ;
    printf("key=%d\n", my_ser_cli.staff_information.phone);

    printf("输入员工入职时间:");
    scanf("%s", post);
    strcpy(my_ser_cli.staff_information.time, post);
    printf("time=%s\n", my_ser_cli.staff_information.time);

    printf("输入员工密码:");
    key = -1;
    scanf("%d", &key);
    my_ser_cli.staff_information.pass_w = key;
    while (getchar() != 10)
        ;
    printf("pass_w=%d\n", my_ser_cli.staff_information.pass_w);
    my_ser_cli.staff_information.state = 0;
    my_ser_cli.CLI_SELECT_H = 1; // 添加员工信息指令码
    printf("state=%d\n", my_ser_cli.staff_information.state);
    printf("send fd =%d %d\n", my_ser_cli_ui->fd, __LINE__);
    if (send(my_ser_cli_ui->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
    {
        ERR_MSG("send");
        return 0;
    }
    // 接收消息是否添加成功
    my_ser_cli.CLI_SELECT = 0;
    if (recv(my_ser_cli_ui->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
    {
        ERR_MSG("recv");
        return 0;
    }
    // 服务器发来标志位,判断账号是否存在为1
    if (my_ser_cli.CLI_SELECT == 1)
    {
        printf("该工号已经存在 %d\n", __LINE__);
        return 0;
    }
    if (my_ser_cli.staff_information.jobnumber)
    {
        printf("员工添加信息成功 %d\n", __LINE__);
    }
}
// root修改员工信息,将修改的数据发送到服务器
int xiugai_user_to_ser(ser_cli *my_str_staff, int key)
{
    // 重新保存
    ser_cli my_ser_cli = *my_str_staff;
    my_ser_cli.CLI_SELECT_H = 2; // 提示服务器进入哪一步
    printf("key=%d\n", key);
   
    printf("pass_w=%d %d\n",my_ser_cli.staff_information.pass_w,__LINE__);
    if (send(my_str_staff->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
    {
        ERR_MSG("send");
        return 0;
    }
    // 接收消息是否修改成功,先改变为失败标志
    my_ser_cli.CLI_SELECT = 1;
    if (recv(my_str_staff->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
    {
        ERR_MSG("recv");
        return 0;
    }
    // 服务器发来标志,如果成功则将SELECT修改为0,否则提示其搜索失败
    if (my_ser_cli.CLI_SELECT != 0)
    {
        if (my_str_staff->CLI_SELECT == 1)
        {
            printf("按员工账号搜索失败\n");
        }
        if (my_str_staff->CLI_SELECT == 2)
        {
            printf("按手机号码搜索失败\n");
        }
        return 0;
    }
    else
    {
        printf("员工信息修改成功\n");
    }
    // 走到这里表示修改成功
    return 1;
}
// root修改员工信息
ser_cli *root_xiugai_user(ser_cli *my_str_staff)
{
    ser_cli my_ser_cli;
    my_ser_cli.fd = my_str_staff->fd;
    int key = -1;
    int key_flag;
    printf("只能修改用户信息\n");
    while (1)
    {
        key = -1;
        printf("1:按照员号修改 2:按照手机号码修改 3:退出\n");
        printf("*请输入你的查找方式*:");
        scanf("%d", &key);
        my_ser_cli.CLI_SELECT = key; // 1按照员工号 2按照手机号
        while (getchar() != 10)
            ;
        switch (key)
        {
        case 1:
            printf("输入员工工号:");
            key = -1;
            scanf("%d", &key);
            if (key == 0)
            {
                printf("工号不可为0\n");
            }
            my_ser_cli.staff_information.jobnumber = key;
            while (getchar() != 10)
                ;

            printf("1<姓名> 2<年龄> 3<薪水>n 4<岗位>  ");
            printf("5<手机号>  6<入职时间>   7<密码>\n");
            key = -1;
            printf("*请输入你想修改的信息*:");
            scanf("%d", &key);
            key_flag=key;
            my_ser_cli.flag=key_flag;
            switch (key)
            {
            case 1:
                printf("输入员工姓名:");
                char name[128] = "";
                scanf("%s", name);
                printf("name=%s", name);
                strcpy(my_ser_cli.staff_information.name, name);
                while (getchar() != 10)
                    ;
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 2:
                printf("输入员工年龄:");
                key = -1;
                scanf("%d", &key);
                my_ser_cli.staff_information.age = key;
                while (getchar() != 10)
                    ;

                printf("age=%d\n", my_ser_cli.staff_information.age);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 3:
                printf("输入员工薪资:");
                float wage = -1;
                scanf("%f", &wage);
                my_ser_cli.staff_information.wage = key;
                while (getchar() != 10)
                    ;
                printf("wage=%f\n", my_ser_cli.staff_information.wage);
                // 为服务器提供是修改哪一项
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 4:
                printf("输入员工岗位:");
                char post[128] = "";
                scanf("%s", post);
                strcpy(my_ser_cli.staff_information.post, post);
                while (getchar() != 10)
                    ;
                printf("post=%s\n", my_ser_cli.staff_information.post);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 5:
                printf("输入员工手机:");
                key = -1;
                scanf("%d", &key);
                my_ser_cli.staff_information.phone = key;
                while (getchar() != 10)
                    ;
                printf("key=%d\n", my_ser_cli.staff_information.phone);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 6:
                printf("输入员工入职时间:");
                scanf("%s", post);
                strcpy(my_ser_cli.staff_information.time, post);
                printf("time=%s\n", my_ser_cli.staff_information.time);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 7:
                printf("输入员工密码:");
                key = -1;
                scanf("%d", &key);
                my_ser_cli.staff_information.pass_w = key;
                while (getchar() != 10)
                    ;
                printf("pass_w=%d\n", my_ser_cli.staff_information.pass_w);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            default:
                printf("输入错误,重新输入\n");
                break;
            }
            break;
        case 2:
            my_ser_cli.CLI_SELECT = 2;
            printf("输入员工手机:");
            key = -1;
            scanf("%d", &key);
            my_ser_cli.staff_information.key = key; // 手机号用key暂时保存
            while (getchar() != 10)
                ;
            printf("key=%d\n", my_ser_cli.staff_information.key);

            printf("1<姓名> 2<年龄> 3<薪水>n 4<岗位>  ");
            printf("5<手机号>  6<入职时间>   7<密码>\n");
            printf("*请输入你想修改的信息*:");
            key = -1;
            scanf("%d", &key);
            key_flag=key;
            my_ser_cli.flag=key_flag;
            switch (key)
            {
            case 1:
                printf("输入员工姓名:");
                char name[128] = "";
                scanf("%s", name);
                printf("name=%s", name);
                strcpy(my_ser_cli.staff_information.name, name);
                while (getchar() != 10)
                    ;
                printf("name=%s\n", my_ser_cli.staff_information.name);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 2:
                printf("输入员工年龄:");
                key = -1;
                scanf("%d", &key);
                my_ser_cli.staff_information.age = key;
                while (getchar() != 10)
                    ;

                printf("age=%d\n", my_ser_cli.staff_information.age);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;

            case 3:
                printf("输入员工薪资:");
                float wage = -1;
                scanf("%f", &wage);
                my_ser_cli.staff_information.wage = wage;
                while (getchar() != 10)
                    ;
                printf("wage=%f\n", my_ser_cli.staff_information.wage);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }

                break;
            case 4:
                printf("输入员工岗位:");
                char post[128] = "";
                scanf("%s", post);
                strcpy(my_ser_cli.staff_information.post, post);
                while (getchar() != 10)
                    ;
                printf("post=%s\n", my_ser_cli.staff_information.post);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 5:
                printf("输入员工手机:");
                key = -1;
                scanf("%d", &key);
                my_ser_cli.staff_information.phone = key;
                while (getchar() != 10)
                    ;
                printf("key=%d\n", my_ser_cli.staff_information.phone);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 6:
                printf("输入员工入职时间:");
                scanf("%s", post);
                strcpy(my_ser_cli.staff_information.time, post);
                printf("time=%s\n", my_ser_cli.staff_information.time);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            case 7:
                printf("输入员工密码:");
                key = -1;
                scanf("%d", &key);
                my_ser_cli.staff_information.pass_w = key;
                while (getchar() != 10)
                    ;
                printf("pass_w=%d\n", my_ser_cli.staff_information.pass_w);
                if (xiugai_user_to_ser(&my_ser_cli, key) < 0)
                {
                    return 0;
                }
                break;
            default:
                printf("输入错误,重新输入%d\n", __LINE__);
                break;
            }
            break;
        case 3:
            printf("key=%d 退出修改%d\n", key, __LINE__);
            return 0;
            break;
        default:
            printf("输入错误,重新输入%d\n", __LINE__);
            break;
        }
    }
}
// root查询员工的信息选择
int chaxun_user(ser_cli *my_ser_cli_H)
{
    ser_cli my_ser_cli = *my_ser_cli_H;
    my_ser_cli.fd = my_ser_cli_H->fd;
    printf("root进入员工查询\n");
    int key = -1;
    while (1)
    {
        printf("查询方式 1<工号> 2.手机号 3.退出查询\n");
        printf("请输入>>>>");
        scanf("%d", &key);
        switch (key)
        {
        case 1:
            my_ser_cli.CLI_SELECT = 1;
            printf("<<<按照工号查询>>>\n");
            key = -1;
            scanf("%d", &key);
            if (key == 0)
            {
                printf("工号不可为0\n");
            }
            my_ser_cli.staff_information.jobnumber = key;
            while (getchar() != 10)
                ;
            printf("jobnumber=%d\n", my_ser_cli.staff_information.jobnumber);
            /*输出查询信息*/
            if(root_chaxun_user(&my_ser_cli)<0)
            {
                break;
            }
            break;
        case 2:
            printf("<<<按照手机号查询>>>\n");
            my_ser_cli.CLI_SELECT = 2;
            printf("输入员工手机:");
            key = -1;
            scanf("%d", &key);
            my_ser_cli.staff_information.phone = key; // 手机号用key暂时保存
            while (getchar() != 10)
                ;
            printf("key=%d\n", my_ser_cli.staff_information.key);
            /*输出查询信息*/
            if(root_chaxun_user(&my_ser_cli)<0)
            {
                break;
            }
            break;
        case 3:
            printf("<<<退出成功>>>\n");
            return 0;
            break;
        default:
            printf("输入错误,重新输入%d\n", __LINE__);
            break;
        }
    }
}
//root查询的功能
int root_chaxun_user(ser_cli *my_ser_cli_H)
{
    //按照SELECT的值判断根据什么查找
    // 重新保存
    ser_cli my_ser_cli = *my_ser_cli_H;
    if(my_ser_cli.staff_information.key==1)//判断是用户还是root
    my_ser_cli.CLI_SELECT_H = 3; // 提示服务器进入哪一步
    else if(my_ser_cli.staff_information.key==2)//员工
    my_ser_cli.CLI_SELECT_H=1;
    if (send(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
    {
        ERR_MSG("send");
        return 0;
    }
    // 接收消息是否查询成功,先改变为失败标志
    my_ser_cli.CLI_SELECT = 1;
    if (recv(my_ser_cli_H->fd, &my_ser_cli, sizeof(my_ser_cli), 0) < 0)
    {
        ERR_MSG("recv");
        return 0;
    }
    // 服务器发来标志,如果成功则将SELECT修改为0,否则提示其搜索失败
    if (my_ser_cli.CLI_SELECT != 0)
    {
        if (my_ser_cli_H->CLI_SELECT == 1)
        {
            printf("按员工账号查找失败\n");
        }
        if (my_ser_cli_H->CLI_SELECT == 2)
        {
            printf("按手机号码查找失败\n");
        }
        return 0;
    }
    if(my_ser_cli.CLI_SELECT==0)
    {
        //先打印查询成功的信息
        printf("id        = %d\n", my_ser_cli.staff_information.key);
        printf("name      = %s\n",my_ser_cli.staff_information.name);
        printf("jobnumber = %d\n", my_ser_cli.staff_information.jobnumber);
        printf("age       = %d\n", my_ser_cli.staff_information.age);
        printf("wage      = %2.f\n", my_ser_cli.staff_information.wage);
        printf("phone     = %d\n", my_ser_cli.staff_information.phone);
        printf("time      = %s\n", my_ser_cli.staff_information.time);
        printf("state     = %d\n", my_ser_cli.staff_information.state);
        printf("pass_w    = %d\n", my_ser_cli.staff_information.pass_w);
        printf("<<<<<<员工信息查找成功>>>>>\n");
    }
    // 走到这里表示修改成功
    return 1;
}

2.3客户端头文件

#ifndef __CLIENT_H__
#define __CLIENT_H__
/******头文件区域*******/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/epoll.h>
#include <sqlite3.h>
#include <pthread.h>
/******引用区域*******/
// 创建数据库并打开数据表
sqlite3 * Sqlite_Create(void);
// 服务器 套接字->端口重启->绑定->监听
int sock_listen(void);
// 红黑树监听事件信息的添加
int add_epoll(int epfd, int fd);
//添加线程管理交互界面
void *callBack(void *arg);

#define DEBUG_LINE printf("Debug line:%d\n",__LINE__)
// 错误码
#define ERR_MSG(msg)                           \
    do                                         \
    {                                          \
        fprintf(stderr, "line:%d ", __LINE__); \
        perror(msg);                           \
    } while (0)

#define PORT 6666            // 服务器端口
#define IP "192.168.250.100" // 服务器IP地址
#define MAX 10   //顺序表最大容量
// 信息结构体,因为使用IPv4,因此使用sockaddr_in填充bind的第二个参数
struct sockaddr_in my_ser; // 服务器信息结构体
struct sockaddr_in my_cin; // 保存客户端信息结构体
// 员工信息结构体
typedef struct staff
{
    int key;       // 判断是用户还是管理员 1是管理 2是用户
    char name[128];     // 员工姓名
    int jobnumber; // 员工工号
    int age;       // 员工年龄
    float wage;    // 当前的薪资
    char post[128];     // 岗位名称
    int phone;     // 手机号
    char time[128];     // 精确到日,入职时间
    int state;     // 是否在线 1表示在线
    int pass_w;    // 密码
} str_staff;
// 服务器与客户端通信的结构体
typedef struct info
{
    int fd;//客户端的描述符
    int CLI_SELECT;                // 登陆时选择的操作 1管理员登陆,2是用户登陆 3是退出
    int CLI_SELECT_H;  //登陆后选择的操作 1.查询信息 2.修改密码 3.查询记录
    int events_i;       //保存红黑树数组的下标
    int cli_n_p; //高账号密码权力的匹配程度,1表示账号不存在2表示密码不正确3表示不是特权4表示不是用户5均成功
    int flag;//进入2级界面选项后,传递的自定义标志位
    sqlite3 *db; 
    str_staff staff_information; // 员工信息结构体
} ser_cli;
//客户端发送信息
int ser_cli_tongxing(ser_cli * my_str_staff,int sock_fd);
int root_ui(ser_cli *my_str_staff);
int user_ui(ser_cli *my_ser_staff);
//添加员工信息
ser_cli *add_root_and_user(ser_cli *my_ser_cli_ui);
//修改员工信息
ser_cli *root_xiugai_user(ser_cli *my_str_staff);
//修改员工信息后与服务器通信
int xiugai_user_to_ser(ser_cli *my_str_staff,int key);
//root查询员工信息
int chaxun_user(ser_cli * my_str_staff);
int root_chaxun_user(ser_cli *my_str_staff); //输出查询到的结果
//root查询历史表
int root_chaxun_lishi(ser_cli *my_ser_cli_H);
//用户查询个人信息
int user_chaxun(ser_cli *my_ser_cli_H);
//用户修改个人密码
int user_xiugai(ser_cli *my_ser_cli_H);
typedef struct newfd
{
    int fd;
}my_fd;
typedef struct fd_1
{
    my_fd arr[MAX];
    int len;
}str_newfd;
// 保存就绪事件的信息,用于移植到红黑树中
struct epoll_event event;
// 存放就绪事件描述符的数组
struct epoll_event events[10];
int user_jobnumber;//保存客户顿的user工号
#endif

3.Makefile

CC = gcc
CFLAGS = -Wextra
LDFLAGS = -lsqlite3 -pthread
SRC = $(wildcard *.c)
OBJ = $(patsubst %.c, %.o, $(SRC))
TARGET = program

.PHONY: all clean

all: $(TARGET)

$(TARGET): $(OBJ)
	$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	rm -f $(OBJ) $(TARGET)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值