基于数据库 Sqlite3 的 root 管理系统
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; // 账号匹配密码不正确smy_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还是用户{// 判断用户还是rootsprintf(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的操作影响到1my_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__);elseprintf("用户进入查询界面%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的操作影响到1my_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;}// 服务器发来标志位,判断账号是否存在为1if (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)//判断是用户还是rootmy_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 cleanall: $(TARGET)$(TARGET): $(OBJ)$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)%.o: %.c$(CC) $(CFLAGS) -c $< -o $@clean:rm -f $(OBJ) $(TARGET)
相关文章:
基于数据库 Sqlite3 的 root 管理系统
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_…...

Hadoop 之 Hive 4.0.0-alpha-2 搭建(八)
Hadoop 之 Hive 搭建与使用 一.Hive 简介二.Hive 搭建1.下载2.安装1.解压并配置 HIVE2.修改 hive-site.xml3.修改 hadoop 的 core-site.xml4.启动 三.Hive 测试1.基础测试2.建库建表3.Java 连接测试1.Pom依赖2.Yarm 配置文件3.启动类4.配置类5.测试类 一.Hive 简介 Hive 是基于…...

vue3常用API之学习笔记
目录 一、setup函数 vue2与vue3变量区别 二、生命周期 三、reactive方法 四、ref方法 1、简介 2、使用 3、ref与reactive 4、获取标签元素或组件 五、toRef 1、简介 2、ref与toRef的区别 六、toRefs 七、shallowReactive 浅reactive 1、简介 2、shallowreactiv…...
Python 程序设计入门(005)—— 字符串操作
Python 程序设计入门(005)—— 字符串操作 目录 Python 程序设计入门(005)—— 字符串操作一、字符串切片与连接1、切片的索引方式2、切片操作的基本表达式3、 切片操作举例4、字符串连接 二、字符串替换:replace() 方…...

怎样将项目jar包放到服务器上
目录 1、在配置文件中配置账号密码 2.在父级的pom里面,加上这个标签 3. deploy部署 4. 注:这两个id得匹配上(原因:有的人会只有上传到测试包的权限,id对应,拥有账号密码的才能有权限) 5.子项…...

ruby调试
如果下载 ruby-debug-ide gem install ruby-debug-ide vscode 下载 ruby扩展 1, ruby 2,修改launch.json...

【云原生】使用kubeadm搭建K8S
目录 一、Kubeadm搭建K8S1.1环境准备1.2所有节点安装docker1.3所有节点安装kubeadm,kubelet和kubectl1.4部署K8S集群1.5所有节点部署网络插件flannel 二、部署 Dashboard 一、Kubeadm搭建K8S 1.1环境准备 服务器IP配置master(2C/4G,cpu核心…...

HCIE-Datacom真题和机构资料
通过认证验证的能力 具备坚实的企业网络跨场景融合解决方案理论知识,能够使用华为数通产品及解决方案进行企业园区网络、广域互联网络及广域承载网络的规划、建设、维护及优化,能够胜任企业网络全场景专家岗位(包括客户经理、项目经理、售前…...

轮足机器人硬件总结
简介 本文主要根据“轮腿机器人Hyun”总结的硬件部分。 轮腿机器人Hyun开源地址:https://github.com/HuGuoXuang/Hyun 1 电源部分 1.1 78M05 78M05是一款三端稳压器芯片,它可以将输入电压稳定输出为5V直流电压. 1.2 AMS1117-3.3 AMS1117-3.3是一种输…...

Flowable-网关-排他网关
目录 定义图形标记XML内容示例视频教程 定义 排他网关,也叫异或(XOR)网关,是 BPMN 中使用的最常见的网关之一,用来在流转中实 现发散分支决策。排他网关需要和条件顺序流搭配使用,当流程执行到排他网关&am…...
GET 和 POST 的区别
GET 和 POST 的区别(流利说) 从 http 协议的角度来说,GET 和 POST 它们都只是请求行中的第一个单词,除了语义不同,其实没有本质的区别。 之所以在实际开发中会产生各种区别,主要是因为浏览器的默认行为造成…...

FFmpeg中硬解码后深度学习模型的图像处理dnn_processing(一)
ffmpeg 硬件解码 ffmpeg硬件解码可以使用最新的vulkan来做,基本上来说,不挑操作系统是比较重要的,如果直接使用cuda也是非常好的选择。 AVPixelFormat sourcepf AV_PIX_FMT_NV12;// AV_PIX_FMT_NV12;// AV_PIX_FMT_YUV420P;AVPixelFormat d…...

计及需求响应和电能交互的多主体综合能源系统主从博弈优化调度策略(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
local-path-provisioner的使用(hostPath、local、local-path-provisioner三者对比)
前言 环境:k8s 1.22.17 、centos7.9 有时候,为了使用本地服务器上的磁盘存储资源,我们会使用hostPath这种方式来为k8s提供本地存储,本篇就来对比一下hostPath、local这两种使用本地服务器储存的方案,从而引出第三种lo…...

命令行快捷键Mac Iterm2
原文:Jump forwards, backwards and delete a word in iTerm2 on Mac OS iTerm2并不允许你使用 ⌥← 或 ⌥→ 来跳过单词。 你也不能使用 ⌥backspace 来删除整个单词。 下面是在Mac OS上如何配置iTerm2以便能做到这一点的方法。 退格键 首先,你需要将你的左侧 ⌥…...

无涯教程-Lua - Modules(模块)
模块就像可以使用 require 加载的库,并且具有包含Table的单个全局名称,该模块可以包含许多函数和变量。 Lua 模块 其中一些模块示例如下。 -- Assuming we have a module printFormatter -- Also printFormatter has a funtion simpleFormat(arg) -- …...

url重定向
不安全的url跳转 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。 如果后端采用了前端传进来的(可能是用户传参,或者之前预埋在前端页面的url地址)参数作为了跳转的目的地,而又没有做判断的话 就可能发生"跳错对象"的问题。 url跳转比较直接的危害是…...
Linux 查看IP地址、子网掩码和网关的配置信息
使用以下命令来查看IP地址、子网掩码和网关的配置信息: 1,使用ifconfig命令: ifconfig 在输出中,找到你正在使用的网络接口的配置信息。你将看到类似以下的内容: eth0: flags4163<UP,BROADCAST,RUNNING,MULTICA…...
token
token验证流程: ①客户端使用用户名和密码请求登录。 ②服务端收到请求,验证用户名和密码。 ③验证成功后,服务端会生成一个token,然后把这个token发送给客户端。 ④客户端收到token后把它存储起来,可以放在cookie…...

利用awk筛选给定时间范围内的日志
文章目录 筛选给定时间范围内的日志时间时间戳什么是时间戳? 系统时间 筛选日志时间示例简单示例mktime()函数是什么 进阶示例 筛选给定时间范围内的日志 时间 时间的表示方法: 时间戳系统时间(年月日时间) 时间戳 什么是时间…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...

如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...