功能介绍

员工管理系统(服务器和客户端)实现功能如下:

1.有管理员和普通员工二种账号

2.管理员可以添加新员工

3.管理员可以删除员工

4.管理员可以修改员工信息

5.管理员可以查看所有用户的操作历史

6.普通员工可以更改自己的账号,查看个人信息,个人的操作记录

7.员工信息包括编号(唯一值)、账号的类型(普通员工、管理员)、名字、密码、年龄、手机号、地址、工作岗位、入职时间、等级和工资

8.操作历史包括时间、操作的账户名、操作内容

9.使用sqlite3保存员工信息和操作历史

10.使用socket完成客户端和服务器TCP协议的通讯

服务器代码

#include "common.h"
void handler(int sig);                                                  //回收僵尸进程
void rcv_cli_msg(struct cli *arg);                                      //处理客户端的请求
void database_init();                                                   //数据库初始化
int process_user_or_admin_login_request(struct cli *cliInfo, MSG *msg); //普通员工和管理员登录
int process_admin_adduser_request(struct cli *cliInfo, MSG *msg);       //管理员添加新员工
int process_admin_query_request(struct cli *cliInfo, MSG *msg);         //管理员查询员工信息
int process_admin_deluser_request(struct cli *cliInfo, MSG *msg);       //管理员删除员工信息
int process_admin_modify_request(struct cli *cliInfo, MSG *msg);        //管理员修改员工信息
void history_time(struct cli *cliInfo, MSG *msg, char *c);              //操作记录保存到数据库
void process_admin_history_request(struct cli *cliInfo, MSG *msg);      //普通员工查看操作记录
void process_user_query_request(struct cli *cliInfo, MSG *msg);         //普通员工查看自己的个人信息
void process_user_history_request(struct cli *cliInfo, MSG *msg);       //普通员工查看个人操作记录
void process_user_modify_request(struct cli *cliInfo, MSG *msg);        //普通员工修改自己的密码int main(int argc, const char *argv[])
{//初始化数据库database_init();sighandler_t s = signal(17, handler);if (SIG_ERR == s){ERR_MSG("signal");return -1;}//打开数据库sqlite3 *db = NULL;if (sqlite3_open("./staff.db", &db) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_open:%s\n", __LINE__, sqlite3_errmsg(db));return -1;}//创建套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if (sfd < 0){ERR_MSG("socket");return -1;}//允许端口快速重用int reuse = 1;if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){ERR_MSG("setsockopt");return -1;}//填充地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(PORT);sin.sin_addr.s_addr = inet_addr(IP);//绑定端口if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin))){ERR_MSG("bind");return -1;}//设置为被动监听状态if (listen(sfd, 10)){ERR_MSG("listen");return -1;}//客户端地址信息结构体struct sockaddr_in cin;socklen_t addrlen = sizeof(cin);int newfd = 0;struct cli cliInfo;cliInfo.db = db;pid_t pid;printf("服务器启动成功\n");while (1){newfd = accept(sfd, (struct sockaddr *)&cin, &addrlen);if (newfd < 0){ERR_MSG("accept");return -1;}printf("[%s : %d] newfd = %d 连接成功\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);cliInfo.newfd = newfd;cliInfo.cin = cin;//创建线程客户端和服务器通讯pid = fork();if (pid > 0){close(newfd);}else if (0 == pid){close(sfd);rcv_cli_msg(&cliInfo);return 0;}}return 0;
}
void handler(int sig) //回收僵尸进程
{while (waitpid(-1, NULL, WNOHANG) > 0);
}
void database_init()
{//判断数据库文件是否存在if (access("./staff.db", F_OK) == 0){return;}//不存在创建数据库sqlite3 *db = NULL;if (sqlite3_open("./staff.db", &db) != SQLITE_OK){printf("errmsg:%s\n", sqlite3_errmsg(db));fprintf(stderr, "__%d__ sqlite3_open failed\n", __LINE__);exit(0);}//创建信息表格和历史记录表格char sql[256] = "CREATE TABLE `staff` ( `no` int, `usertype` int, `name` char, `passwd` char, `age` int, `phone` char, `addr` char, `work` char, `date` char, `level` int, `salary` double, PRIMARY KEY(`no`));";char *errmsg = NULL;if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);exit(0);}strcpy(sql, "CREATE TABLE `history` ( `time` char, `name` char, `log` char )");if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);exit(0);}//添加管理员admin的账号信息strcpy(sql, "insert into staff values (1000,0,'admin','admin',0,'0','0','0','2022-10-29',0,1);");if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);exit(0);}//关闭数据库sqlite3_close(db);return;
}void rcv_cli_msg(struct cli *arg)
{printf("创建新进程成功\n");int newfd = arg->newfd;struct sockaddr_in cin = arg->cin;MSG msg;while (1){memset(&msg, 0, sizeof(msg));//接收客户端的请求,判断指向的功能函数ssize_t res = recv(newfd, &msg, sizeof(msg), 0);if (res < 0){ERR_MSG("recv");break;}else if (0 == res){printf("[%s : %d] newfd = %d 断开连接\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);break;}switch (msg.msgtype){case USER_LOGIN:case ADMIN_LOGIN:process_user_or_admin_login_request(arg, &msg);break;case USER_MODIFY:process_user_modify_request(arg, &msg);break;case USER_QUERY:process_user_query_request(arg, &msg);break;case ADMIN_MODIFY:process_admin_modify_request(arg, &msg);break;case ADMIN_ADDUSER:process_admin_adduser_request(arg, &msg);break;case ADMIN_DELUSER:process_admin_deluser_request(arg, &msg);break;case ADMIN_QUERY:process_admin_query_request(arg, &msg);break;case ADMIN_HISTORY:process_admin_history_request(arg, &msg);break;case USER_HISTORY:process_user_history_request(arg, &msg);break;default:break;}}close(newfd);
}int process_user_or_admin_login_request(struct cli *cliInfo, MSG *msg)
{//验证用户名密码char sql[128] = "select * from staff where name=";char **pres = NULL; //存储查询结果的首地址int row, column;   //查询结果的行列数char *errmsg = NULL;sprintf(sql, "%s'%s'", sql, msg->username);if (sqlite3_get_table(cliInfo->db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);return -1;}msg->flags = 0;// column == 0,数据库差不多,用户不存在if (column == 0){printf("[%s]账号不存在\n", msg->username);sprintf(msg->recvmsg, "[%s]账号不存在\n", msg->username);}//和数据库密码不相等,密码不正确else if (strcmp(pres[column + 3], msg->passwd)){printf("[%s]密码不正确\n", msg->username);sprintf(msg->recvmsg, "[%s]密码不正确\n", msg->username);}else{//登录成功if (*pres[column + 1] == msg->usertype + 48) //从数据库获取的是字符'1',客户端的usertype和数据库相同{//填充个人的信息msg->info.no = atoi(pres[column]);msg->info.usertype = atoi(pres[column + 1]);strcpy(msg->info.name, pres[column + 2]);strcpy(msg->info.passwd, pres[column + 3]);msg->info.age = atoi(pres[column + 4]);strcpy(msg->info.phone, pres[column + 5]);strcpy(msg->info.addr, pres[column + 6]);strcpy(msg->info.work, pres[column + 7]);strcpy(msg->info.date, pres[column + 8]);msg->info.level = atoi(pres[column + 9]);msg->info.salary = atoi(pres[column + 10]);printf("[%s]登录成功\n", msg->username);sprintf(msg->recvmsg, "[%s]登录成功", msg->username);msg->flags = 1;history_time(cliInfo, msg, msg->recvmsg); //记录账号登录成功}else if (*pres[column + 1] == USER + 48){printf("[%s]此账号不是管理员用户\n", msg->username);sprintf(msg->recvmsg, "[%s]此账号不是管理员用户\n", msg->username);}else if (*pres[column + 1] == ADMIN + 48){printf("[%s]此账号不是普通用户\n", msg->username);sprintf(msg->recvmsg, "[%s]此账号不是普通用户\n", msg->username);}}if (send(cliInfo->newfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");}//释放获取到的空间sqlite3_free_table(pres);pres = NULL;return 0;
}int process_admin_adduser_request(struct cli *cliInfo, MSG *msg)
{if (ADMIN_ADDUSER == msg->msgtype) //修改信息也会调用此函数,放在修改调用时打印提示printf("管理员[%s]请求添加员工信息\n", msg->username);char sql[512] = "";sprintf(sql, "%s(%d,%d,'%s','%s',%d,'%s','%s','%s','%s',%d,%lf)", "insert into staff values ", msg->info.no, msg->info.usertype, msg->info.name, msg->info.passwd, msg->info.age, msg->info.phone, msg->info.addr, msg->info.work, msg->info.date, msg->info.level, msg->info.salary);sprintf(msg->recvmsg, "ID[%d]添加新员工成功", msg->info.no);msg->flags = 1;char *errmsg = NULL;if (sqlite3_exec(cliInfo->db, sql, NULL, NULL, &errmsg) != SQLITE_OK){if (sqlite3_errcode(cliInfo->db) == 19) //主键重复,ID重复{sprintf(msg->recvmsg, "[%d]ID编号重复\n", msg->info.no);msg->flags = 0;}else{sprintf(msg->recvmsg, "[%d]注册失败\n", msg->info.no);msg->flags = 0;fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);}}if (ADMIN_ADDUSER == msg->msgtype){history_time(cliInfo, msg, msg->recvmsg);if (send(cliInfo->newfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");}}return 0;
}int process_admin_query_request(struct cli *cliInfo, MSG *msg)
{char m[256] = "";char sql[256] = "";char sql_t[150] = "";char **pres = NULL; //存储查询结果的首地址int row, column;    //查询结果的行列数char *errmsg = NULL;if (msg->flags == 0) //管理员查询所有员工信息{sprintf(m, "管理员[%s]请求查询所有员工信息", msg->username);}else if (msg->flags == 1) //管理员按照id查询员工信息{sprintf(sql_t, "where no=%d", atoi(msg->recvmsg));sprintf(m, "管理员[%s]请求查询ID[%d]员工信息\n", msg->username, atoi(msg->recvmsg));}else if (msg->flags == 2) //管理员按照名字查询员工信息{sprintf(sql_t, "where name='%s'", msg->recvmsg);sprintf(m, "管理员[%s]请求查询ID[%s]员工信息\n", msg->username, msg->recvmsg);}else if (msg->flags == 3) //普通用户查询个人信息{sprintf(sql_t, "where no=%d", atoi(msg->recvmsg));sprintf(m, "普通员工[%s]请求查询员工个人信息", msg->username);}printf("%s\n", m);history_time(cliInfo, msg, m);sprintf(sql, "select * from staff %s", sql_t);//查询信息if (sqlite3_get_table(cliInfo->db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);return -1;}if (row == 0){msg->flags = 0;}//发送有多少行sprintf(msg->recvmsg, "%d", row);if (send(cliInfo->newfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");return -1;}int i, j;for (i = column, j = 0; j < row; j++) //循环发送数据给客户端{msg->info.no = atoi(pres[i++]);msg->info.usertype = atoi(pres[i++]);strcpy(msg->info.name, pres[i++]);strcpy(msg->info.passwd, pres[i++]);msg->info.age = atoi(pres[i++]);strcpy(msg->info.phone, pres[i++]);strcpy(msg->info.addr, pres[i++]);strcpy(msg->info.work, pres[i++]);strcpy(msg->info.date, pres[i++]);msg->info.level = atoi(pres[i++]);msg->info.salary = atoi(pres[i++]);sprintf(msg->recvmsg, "%d", row);if (send(cliInfo->newfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");return -1;}}sqlite3_free_table(pres);return 0;
}
int process_admin_deluser_request(struct cli *cliInfo, MSG *msg)
{char buf[128];char m[256];strcpy(buf, msg->recvmsg); //保存删除的用户信息,方便存储操作内容和打印提示消息if (ADMIN_DELUSER == msg->msgtype){sprintf(m, "管理员[%s]请求删除ID:[%s]员工信息", msg->username, msg->recvmsg);printf("%s\n", m);history_time(cliInfo, msg, m);}//判断是否存在此用户idchar sql[128] = "select * from staff where no=";char **pres = NULL; //存储查询结果的首地址int row, column;  //查询结果的行列数char *errmsg = NULL;sprintf(sql, "%s %d", sql, atoi(msg->recvmsg));if (sqlite3_get_table(cliInfo->db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);return -1;}//用户不存在if (column == 0){printf("ID:[%s]删除失败,用户不存在\n", buf);sprintf(msg->recvmsg, "ID:[%s]删除失败,用户不存在", buf);msg->flags = 0;}else{sprintf(sql, "%s %d", "delete from staff where no= ", atoi(msg->recvmsg));if (sqlite3_exec(cliInfo->db, sql, NULL, NULL, &errmsg) != SQLITE_OK){msg->flags = 0;fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);}sprintf(msg->recvmsg, "ID:[%s]删除成功", buf);msg->flags = 1;}if (ADMIN_DELUSER == msg->msgtype){if (send(cliInfo->newfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");}}return column ? 0 : -1;
}
int process_admin_modify_request(struct cli *cliInfo, MSG *msg)
{//修改直接调用的删除和插入char t[128] = "";char m[256] = "";strcpy(t, msg->recvmsg); //保存修改的IDsprintf(m, "管理员[%s]修改ID[%s]员工信息\n", msg->username, msg->recvmsg);printf("%s\n", m);if (process_admin_deluser_request(cliInfo, msg) == 0){process_admin_adduser_request(cliInfo, msg);if (msg->flags == 0){sprintf(msg->recvmsg, "ID[%s]信息修改失败\n", t);}else if (msg->flags == 1){sprintf(msg->recvmsg, "ID[%s]信息修改成功\n", t);}}else{msg->flags = 0;sprintf(msg->recvmsg, "ID[%s]员工不存在,修改失败\n", t);}if (send(cliInfo->newfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");}history_time(cliInfo, msg, m);return 0;
}void history_time(struct cli *cliInfo, MSG *msg, char *c)
{char *errmsg = NULL;char sql[256] = "";time_t t;struct tm *info = NULL;t = time(NULL);info = localtime(&t);sprintf(sql, "insert into history values ('%d-%02d-%02d %02d:%02d:%02d','%s','%s')",info->tm_year + 1900, info->tm_mon + 1, info->tm_mday,info->tm_hour, info->tm_min, info->tm_sec, msg->username, c); //拼接数据库指令if (sqlite3_exec(cliInfo->db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);}
}void process_admin_history_request(struct cli *cliInfo, MSG *msg)
{char m[128] = "";sprintf(m, "管理员[%s]请求查询历史记录", msg->username);history_time(cliInfo, msg, m);char sql[128] = "";char sql_t[64] = "";char **pres_t = NULL; //存储查询结果的首地址int row, column;     //查询结果的行列数char *errmsg = NULL;if (ADMIN_HISTORY != msg->msgtype) //管理员查询所有的员工的历史记录,普通员工只能查询自己的历史记录sprintf(sql_t, "where name='%s'", msg->username);sprintf(sql, "select * from history %s", sql_t);//查询信息if (sqlite3_get_table(cliInfo->db, sql, &pres_t, &row, &column, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);return;}//发送有多少行sprintf(msg->recvmsg, "%d", (row + 1) * column);if (send(cliInfo->newfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");return;}int i;for (i = 0; i < (row + 1) * column; i++){strcpy(msg->recvmsg, pres_t[i]);if (send(cliInfo->newfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");return;}}sqlite3_free_table(pres_t);
}
void process_user_query_request(struct cli *cliInfo, MSG *msg)
{process_admin_query_request(cliInfo, msg); //调用管理员查询函数,函数有判断
}
void process_user_history_request(struct cli *cliInfo, MSG *msg)
{process_admin_history_request(cliInfo, msg); //调用管理员查询历史操作函数,函数有判断
}
void process_user_modify_request(struct cli *cliInfo, MSG *msg)
{char *errmsg = NULL;char sql[256] = "";printf("普通员工[%s]请求修改密码\n", msg->username);sprintf(sql, "update staff set passwd='%s' where no=%d", msg->recvmsg, msg->info.no);if (sqlite3_exec(cliInfo->db, sql, NULL, NULL, &errmsg) != SQLITE_OK){fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);}sprintf(msg->recvmsg, "普通员工[%s]密码修改成功", msg->username);history_time(cliInfo, msg, msg->recvmsg);if (send(cliInfo->newfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");return;}
}

客户端代码

#include "common.h"
void menu(int t);                                 //打印的选项菜单
void admin_or_user_login(int sockfd, MSG *msg);   //普通员工和管理员登录
void admin_menu(int sockfd, MSG *msg);            //管理员成功登录系统
void user_menu(int sockfd, MSG *msg);             //普通员工成功登录系统
void do_admin_adduser(int sockfd, MSG *msg);      //管理员添加新员工
void do_admin_query(int sockfd, MSG *msg);        //管理员查询员工信息
void do_admin_deluser(int sockfd, MSG *msg);      //管理员删除员工信息
void do_admin_modification(int sockfd, MSG *msg); //管理员修改员工信息
void do_admin_history(int sockfd, MSG *msg);      //管理员查看操作记录
void do_user_history(int sockfd, MSG *msg);       //普通员工查看操作记录
void do_user_query(int sockfd, MSG *msg);         //普通员工查看自己的个人信息
void do_user_modification(int sockfd, MSG *msg);  //普通员工修改自己的密码
int main(int argc, char const *argv[])
{//创建流式套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if (sfd < 0){ERR_MSG("socket");return -1;}printf("创建套接字成功\n");//填充要连接的服务器的地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(PORT);sin.sin_addr.s_addr = inet_addr(IP);//连接服务器 connectif (connect(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0){ERR_MSG("connect");return -1;}int which;MSG msg;system("clear");while (1){menu(1);scanf("%d", &which);while (getchar() != 10);switch (which){case 1:msg.msgtype = ADMIN_LOGIN;msg.usertype = ADMIN;admin_or_user_login(sfd, &msg);case 2:msg.msgtype = USER_LOGIN;msg.usertype = USER;admin_or_user_login(sfd, &msg);break;case 0:exit(0);default:printf("输入错误,请重新输入\n");break;}}return 0;
}
void menu(int t)
{if (t == 1){printf("****************************************\n");printf("***********欢迎使用员工管理系统**********\n");printf("\t1.管理员登录 2.员工登录 0.退出\n");printf("****************************************\n");printf("请选择>>>");}else if (t == 2){printf("****************************************\n");printf("1.添加新的员工 2.修改员工信息 3.删除员工信息 \n4.查看员工信息 5.查看历史记录 0.退出\n");printf("****************************************\n");printf("请选择>>>");}else if (t == 3){printf("****************************************\n");printf("1.查询信息 2.修改密码 3.查看历史记录 0.退出\n");printf("****************************************\n");printf("请选择>>>");}
}
void admin_or_user_login(int sockfd, MSG *msg)
{do{printf("请输入用户名>>>");fgets(msg->username, sizeof(msg->username), stdin);msg->username[strlen(msg->username) - 1] = 0;printf("请输入密码>>>");fgets(msg->passwd, sizeof(msg->passwd), stdin);msg->passwd[strlen(msg->passwd) - 1] = 0;if (send(sockfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");}int res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}printf("%s\n", msg->recvmsg);} while (msg->flags != 1);if (msg->usertype == 0){admin_menu(sockfd, msg);}else if (msg->usertype == 1){user_menu(sockfd, msg);}elseprintf("服务器错误\n");
}
void admin_menu(int sockfd, MSG *msg)
{/*printf("(%d,%d,'%s','%s',%d,'%s','%s','%s','%s',%d,%lf)\n", msg->info.no, msg->info.usertype, msg->info.name, msg->info.passwd, msg->info.age, msg->info.phone, msg->info.addr, msg->info.work, msg->info.date, msg->info.level, msg->info.salary);*/printf("亲爱的[%s]管理员,欢迎您登陆员工管理系统!\n", msg->username);int which;while (1){menu(2);scanf("%d", &which);while (getchar() != 10);switch (which){case 1:do_admin_adduser(sockfd, msg);break;case 2:do_admin_modification(sockfd, msg);break;case 3:do_admin_deluser(sockfd, msg);break;case 4:do_admin_query(sockfd, msg);break;case 5:do_admin_history(sockfd, msg);break;case 0:exit(0);break;default:printf("输入错误请重新输出\n");break;}}
}
void user_menu(int sockfd, MSG *msg)
{printf("亲爱的[%s]用户,欢迎您登陆员工管理系统!\n", msg->username);int which;while (1){menu(3);scanf("%d", &which);while (getchar() != 10);switch (which){case 1:do_user_query(sockfd, msg);break;case 2:do_user_modification(sockfd, msg);break;case 3:do_user_history(sockfd, msg);break;case 0:exit(0);break;default:printf("输入错误,请重新输入\n");break;}}
}
void do_admin_adduser(int sockfd, MSG *msg)
{staff_info_t info_t = msg->info; //保存自己的个人信息msg->msgtype = ADMIN_ADDUSER;printf("请输入员工ID>>>");while (scanf("%d", &msg->info.no) == 0){printf("请输入正确的数字\n");printf("请重新输入员工ID>>>");while (getchar() != 10);}while (getchar() != 10);printf("请输入是否是管理员(0管理员,1非管理员)>>>");while (scanf("%d", &msg->info.usertype) == 0){printf("请输入正确的数字\n");printf("请重新输入是否是管理员(0管理员,1非管理员)>>>");while (getchar() != 10);}while (getchar() != 10);printf("请输入姓名>>>");fgets(msg->info.name, sizeof(msg->info.name), stdin);msg->info.name[strlen(msg->info.name) - 1] = 0;printf("请输入密码>>>");fgets(msg->info.passwd, sizeof(msg->info.passwd), stdin);msg->info.passwd[strlen(msg->info.passwd) - 1] = 0;printf("请输入年龄>>>");while (scanf("%d", &msg->info.age) == 0){printf("请输入正确的数字\n");printf("请重新输入年龄>>>");while (getchar() != 10);}while (getchar() != 10);printf("请输入电话>>>");fgets(msg->info.phone, sizeof(msg->info.phone), stdin);msg->info.phone[strlen(msg->info.phone) - 1] = 0;printf("请输入地址>>>");fgets(msg->info.addr, sizeof(msg->info.addr), stdin);msg->info.addr[strlen(msg->info.addr) - 1] = 0;printf("请输入职位>>>");fgets(msg->info.work, sizeof(msg->info.work), stdin);msg->info.work[strlen(msg->info.work) - 1] = 0;printf("请输入入职时间(输入now当前时间)>>>");fgets(msg->info.date, sizeof(msg->info.date), stdin);msg->info.date[strlen(msg->info.date) - 1] = 0;if (!strcasecmp(msg->info.date, "now")){time_t t;struct tm *info = NULL;t = time(NULL);info = localtime(&t);sprintf(msg->info.date, "%d-%02d-%02d %02d:%02d:%02d",info->tm_year + 1900, info->tm_mon + 1, info->tm_mday,info->tm_hour, info->tm_min, info->tm_sec);}printf("请输入等级>>>");while (scanf("%d", &msg->info.level) == 0){printf("请输入正确的数字\n");printf("请重新输入等级>>>");while (getchar() != 10);}while (getchar() != 10);printf("请输入工资>>>");while (scanf("%lf", &msg->info.salary) == 0){printf("请输入正确的数字\n");printf("请重新输入工资>>>");while (getchar() != 10);}while (getchar() != 10);if (send(sockfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");}int res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}msg->info = info_t; //恢复自己的个人信息printf("%s\n", msg->recvmsg);
}
void do_admin_query(int sockfd, MSG *msg)
{int num;msg->msgtype = ADMIN_QUERY;int which;printf("*******************************************************\n");printf("1.查询所有员工信息 2.按照ID查询 3.按照名字查询 0.返回上一页\n");printf("*******************************************************\n");printf("请选择>>>");scanf("%d", &which);while (getchar() != 10);switch (which){case 1:msg->flags = 0;break;case 2:msg->flags = 1;printf("请输入ID>>>");fgets(msg->recvmsg, sizeof(msg->recvmsg), stdin);msg->recvmsg[strlen(msg->recvmsg) - 1] = 0;break;case 3:msg->flags = 2;printf("请输入名字>>>");fgets(msg->recvmsg, sizeof(msg->recvmsg), stdin);msg->recvmsg[strlen(msg->recvmsg) - 1] = 0;break;case 0:return;default:printf("输入错误\n");break;}if (send(sockfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");return;}int res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}num = atoi(msg->recvmsg);if (num == 0){printf("没有查询到此员工\n");return;}printf("员工编号\t权限\t姓名\t密码\t年龄\t电话\t地址\t职位\t入职年月\t等级\t工资\n");while (num--){res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}printf("%d\t%d\t%s\t%s\t%d\t%s\t%s\t%s\t%s\t%d\t%.2lf\n", msg->info.no, msg->info.usertype, msg->info.name, msg->info.passwd, msg->info.age, msg->info.phone, msg->info.addr, msg->info.work, msg->info.date, msg->info.level, msg->info.salary);}
}void do_admin_deluser(int sockfd, MSG *msg)
{char buf[16];msg->msgtype = ADMIN_DELUSER;printf("请输入要删除的用户id>>>");fgets(msg->recvmsg, sizeof(msg->recvmsg), stdin);msg->recvmsg[strlen(msg->recvmsg) - 1] = 0;if (atoi(msg->recvmsg) == msg->info.no){printf("不可以删除自己哦\n");return;}if (send(sockfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");return;}strcpy(buf, msg->recvmsg);int res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}printf("%s\n", msg->recvmsg);return;
}
void do_admin_modification(int sockfd, MSG *msg)
{staff_info_t info_t = msg->info; //保存自己的个人信息msg->msgtype = ADMIN_MODIFY;printf("请输入要修改的id>>>");fgets(msg->recvmsg, sizeof(msg->recvmsg), stdin);msg->recvmsg[strlen(msg->recvmsg) - 1] = 0;msg->info.no = atoi(msg->recvmsg);printf("请输入是否是管理员(0管理员,1非管理员)>>>");while (scanf("%d", &msg->info.usertype) == 0){printf("请输入正确的数字\n");printf("请重新输入是否是管理员(0管理员,1非管理员)>>>");while (getchar() != 10);}while (getchar() != 10);printf("请输入姓名>>>");fgets(msg->info.name, sizeof(msg->info.name), stdin);msg->info.name[strlen(msg->info.name) - 1] = 0;printf("请输入密码>>>");fgets(msg->info.passwd, sizeof(msg->info.passwd), stdin);msg->info.passwd[strlen(msg->info.passwd) - 1] = 0;printf("请输入年龄>>>");while (scanf("%d", &msg->info.age) == 0){printf("请输入正确的数字\n");printf("请重新输入年龄>>>");getchar();}while (getchar() != 10);printf("请输入电话>>>");fgets(msg->info.phone, sizeof(msg->info.phone), stdin);msg->info.phone[strlen(msg->info.phone) - 1] = 0;printf("请输入地址>>>");fgets(msg->info.addr, sizeof(msg->info.addr), stdin);msg->info.addr[strlen(msg->info.addr) - 1] = 0;printf("请输入职位>>>");fgets(msg->info.work, sizeof(msg->info.work), stdin);msg->info.work[strlen(msg->info.work) - 1] = 0;printf("请输入入职时间(输入now当前时间)>>>");fgets(msg->info.date, sizeof(msg->info.date), stdin);msg->info.date[strlen(msg->info.date) - 1] = 0;if (!strcasecmp(msg->info.date, "now")){time_t t;struct tm *info = NULL;t = time(NULL);info = localtime(&t);sprintf(msg->info.date, "%d-%02d-%02d %02d:%02d:%02d",info->tm_year + 1900, info->tm_mon + 1, info->tm_mday,info->tm_hour, info->tm_min, info->tm_sec);}printf("请输入等级>>>");while (scanf("%d", &msg->info.level) == 0){printf("请输入正确的数字\n");printf("请重新输入等级>>>");while (getchar() != 10);}while (getchar() != 10);printf("请输入工资>>>");while (scanf("%lf", &msg->info.salary) == 0){printf("请输入正确的数字\n");printf("请重新输入工资>>>");while (getchar() != 10);}while (getchar() != 10);if (send(sockfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");}int res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}msg->info = info_t; //恢复自己的个人信息printf("%s\n", msg->recvmsg);
}
void do_admin_history(int sockfd, MSG *msg)
{if (msg->msgtype != USER_HISTORY)msg->msgtype = ADMIN_HISTORY;if (send(sockfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");}int res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}int i = atoi(msg->recvmsg);int j = 0;for (j = 1; j <= i; j++){res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}printf("%s\t\t", msg->recvmsg);if (j % 3 == 0){printf("\n");}}
}
void do_user_query(int sockfd, MSG *msg)
{msg->msgtype = USER_QUERY;msg->flags = 3;sprintf(msg->recvmsg, "%d", msg->info.no);if (send(sockfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");return;}int res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}int num = atoi(msg->recvmsg);if (num == 0){printf("没有查询到此员工\n");return;}printf("员工编号\t权限\t姓名\t密码\t年龄\t电话\t地址\t职位\t入职年月\t等级\t工资\n");while (num--){res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}printf("%d\t%d\t%s\t%s\t%d\t%s\t%s\t%s\t%s\t%d\t%.2lf\n", msg->info.no, msg->info.usertype, msg->info.name, msg->info.passwd, msg->info.age, msg->info.phone, msg->info.addr, msg->info.work, msg->info.date, msg->info.level, msg->info.salary);}
}
void do_user_history(int sockfd, MSG *msg)
{msg->msgtype = USER_HISTORY;do_admin_history(sockfd, msg);
}
void do_user_modification(int sockfd, MSG *msg)
{msg->msgtype = USER_MODIFY;printf("请输入新的密码>>>");fgets(msg->recvmsg, sizeof(msg->recvmsg), stdin);msg->recvmsg[strlen(msg->recvmsg) - 1] = 0;if (send(sockfd, msg, sizeof(MSG), 0) < 0){ERR_MSG("send");return;}int res = recv(sockfd, msg, sizeof(MSG), 0);if (res < 0){ERR_MSG("recv");return;}printf("%s\n", msg->recvmsg);
}

公共头文件


#ifndef _COMMON_H_
#define _COMMON_H_
typedef void (*sighandler_t)(int);
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sqlite3.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sqlite3.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <pthread.h>#define PORT 8888
#define IP "192.168.161.100" //本机IP
//打印错误信息宏函数
#define ERR_MSG(msg)                                                               \do                                                                             \{                                                                              \fprintf(stderr, "行号%d 函数%s 文件名%s\n", __LINE__, __func__, __FILE__); \perror(msg);                                                               \} while (0)struct cli //客户端消息结构体,套接字,客户端ip,数据库指针
{int newfd;struct sockaddr_in cin;sqlite3 *db;
};#define USER_LOGIN 0x00000000   // login  登陆    0x00000001
#define USER_MODIFY 0x00000001  // user-modification  修改
#define USER_QUERY 0x00000002   // user-query   查询
#define USER_HISTORY 0x00000003 // 查看操作历史#define ADMIN_LOGIN 0x10000000   // login  登陆    0x00000001
#define ADMIN_MODIFY 0x10000001  // admin修改
#define ADMIN_ADDUSER 0x10000002 // admin添加
#define ADMIN_DELUSER 0x10000004 // admin删除
#define ADMIN_QUERY 0x10000008   // 查询
#define ADMIN_HISTORY 0x10000010 // 历史记录#define QUIT 0x11111111 //没有用到#define ADMIN 0 //管理员
#define USER 1  //用户#define NAMELEN 32
#define DATALEN 128/*员工基本信息*/
typedef struct staff_info
{int no;              //员工编号int usertype;        // ADMIN 1 USER 2char name[NAMELEN];  //姓名char passwd[8];      //密码int age;             // 年龄char phone[NAMELEN]; //电话char addr[DATALEN];  // 地址char work[DATALEN];  //职位char date[DATALEN];  //入职年月int level;           // 等级double salary;       // 工资
} staff_info_t;/*定义双方通信的结构体信息*/
typedef struct
{int msgtype;            //请求的消息类型int usertype;           // ADMIN 0    USER 1char username[NAMELEN]; //姓名char passwd[16];        //登陆密码char recvmsg[DATALEN];  //通信的消息int flags;              //标志位 1成功0失败    0全部员工信息  1id查询   2姓名查询  3普通用户查询staff_info_t info;      //员工信息
} MSG;
#endif

Makefile

all:gcc server.c -o server  -lsqlite3 -Wallgcc client.c -o client -Wallclean:rm server client

员工管理系统(服务器和客户端)相关推荐

  1. 考勤系统怎样登录服务器,ZKtime5.0考勤管理系统标准版客户端登录忘记登录密码...

     ZKtime5.0考勤管理系统标准版客户端登录忘记登录密码 2014-09-01 11:25:37 登录提示需要输入 以下是解决此问题的方法,希望大家记住.如果以后有碰到这样的情况,你就可以按照以下 ...

  2. 项目——员工管理系统

    开发环境:vmware ubuntu18.04 实现功能:基本功能包括管理者和普通员工用户的登录,管理者拥有操作所有员工信息的最高权限,可以进行增删改   查等操作,普通用户仅拥有查看.修改个人部分信 ...

  3. (附源码)ssm物流公司员工管理系统 毕业设计 261625

    基于ssm物流公司员工管理系统 摘  要 随着互联网大趋势的到来,社会的方方面面,各行各业都在考虑利用互联网作为媒介将自己的信息更及时有效地推广出去,而其中最好的方式就是建立网络管理系统,并对其进行信 ...

  4. 如何外网访问登录员工管理系统平台

    员工管理系统平台网站是企业常用办公工具之一,为了安全性和稳定性,一般都部署在公司内部内网web服务器上,在办公室内通过内网IP端口进行登录访问.那么,如何实现在外网或者在家也能访问公司内网的管理网站呢 ...

  5. 数据库服务器管理系统,数据库管理系统服务器

    数据库管理系统服务器 内容精选 换一换 业界对备份一致性的定义包括如下三类:不一致备份:备份的文件.磁盘不在同一个时间点.崩溃一致性备份:崩溃一致性备份会捕获备份时磁盘上已存在的数据,文件/磁盘数据在 ...

  6. 员工管理系统实现方案

    一.功能实现 1.实现管理员和普通用户的登录,并赋予不同的操作权限 2.管理员实现对员工数据的增加.删除.修改.查找 3.普通用户实现对自身数据的查找和维护 4.实现对历史操作的记录和删除 二.实现方 ...

  7. 基于javaweb的简单员工管理系统

    一.系统简介 本项目采用eclipse工具开发,jsp+servlet+jquery技术编写,数据库采用的是mysql,navicat开发工具. 系统一共分为1个角色分别是:员工 二.模块简介 员工 ...

  8. 计算机毕业设计之java+springboot基于vue的人事管理系统-员工管理系统

    计算机毕业设计之java+springboot基于vue的人事管理系统-员工管理系统 项目介绍 系统权限按管理员和员工这两类涉及用户划分. (a)管理员:管理员使用本系统涉到的功能主要有:首页,个人中 ...

  9. Java-SpringBoot:员工管理系统

    Java:SpringBoot-员工管理系统 参考的代码和资源链接:https://blog.csdn.net/qq_45173404/article/details/108934414?spm=10 ...

最新文章

  1. 20110625 AD下DFS实现冗余文件服务器,加密软件等
  2. linux 观察应用使用内存的情况,Linux学习笔记:free和top命令查看系统内存使用情况...
  3. 精益软件过程中七大浪费的应对之道
  4. linux隐写文件剥离,杂项的基本解题思路(1)——文件操作隐写、图片隐写
  5. centos 修改密码_openstack Train版部署——基于centos系统(四)
  6. 【Flink】Flink的窗口触发器 PurgingTrigger
  7. php mysql计算距离_php mysql 计算经纬之间距离 范围内筛选
  8. 机器学习的几个误区-转载
  9. Python MySQL操作
  10. 栈溢出学习(四)之Hijack GOT
  11. android 倒影图片的生成
  12. 代码打字速度_使用VueJS创建打字速度效果
  13. 关于学术道德,我们应该遵循的规范
  14. 全球及中国不锈钢市场投资前景与发展走势研究报告2022版
  15. Java new Date() 获取的时间不正确 【已解决】
  16. 推荐5款让你相见恨晚的神级软件,把把直击心灵
  17. 基于QQ云输入法,用python实现的输入法(demo 版)
  18. Day1-JSP的入门了解以及环境的配置Tomcat的注意点和一些常见问题的解决方案(适宜JSPServlet的初学者的学习)
  19. 2021年全球硫酸镍收入大约2184.2百万美元,预计2028年达到2715.2百万美元
  20. 腾讯QQ2007 beta1┊解决Windows Vista下QQ基本的兼容性问题┊纯净绿色特别版

热门文章

  1. 200多程序员报名杨超越编程大赛 直男及肥宅更喜欢杨超越??
  2. 谷歌浏览器 F12或右键检查 开发者工具DevTool打开慢问题
  3. 2021年中国消费贷款现状分析:消费贷款余额达54.88万亿元,同比增长10.73%[图]
  4. 【算法百题之四十】整数转罗马数字
  5. R学习之统计实验(四)--蒲丰投针(R语言编程)-----数模
  6. KubeSphere 内置的 Prometheus 通过 remote write 至 Thanos 存更长期数据
  7. SAP R/3 财务基本概念及集成性浅释 —— 主数据篇
  8. 简述关系数据库的数据完整性规则_认识关系数据库的完整性规则
  9. Web Framworks 的决斗
  10. vue-chartjs画渐变色