项目要求
1)服务器负责管理所有员工表单(以数据库形式),其他客户端可通过网络连接服务器来查询员工表单。
2)需要账号密码登陆,其中需要区分管理员账号还是普通用户账号。
3)管理员账号可以查看、修改、添加、删除员工信息,同时具有查询历史记录功能,管理员要负责管理所有的普通用户。
4)普通用户只能查询修改与本人有关的相关信息,其他员工信息不得查看修改。
5)服务器能同时相应多台客户端的请求功能。并发
1.服务器:
1)创建套接字
2)绑定ip和端口号
3)监听
4)等待客户端连接
2.客户端:
1)创建套接字
2)连接服务器
1)多线程
2)多进程
3)IO多路复用:select
编译数据库接口相关c文件需要链接库 -lsqlite3
/*员工基本信息*/
typedef struct staff_info{int no; //员工编号int usertype; //ADMIN 0 USER 1 char 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 1 char username[NAMELEN]; //姓名char passwd[8]; //登陆密码char recvmsg[DATALEN]; //通信的消息int flags; //标志位void *released;staff_info_t info; //员工信息
}MSG;
代码
头文件
#ifndef _COMMON_H_
#define _COMMON_H_#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include #define STAFF_DATABASE "staff_manage_system.db"#define USER_LOGIN 0x00000000 // login 登陆 0x00000001
#define USER_MODIFY 0x00000001 // user-modification 修改
#define USER_QUERY 0x00000002 // user-query 查询#define ADMIN_LOGIN 0x10000000 // login 登陆 0x00000001
#define ADMIN_MODIFY 0x10000001 // admin_modification 修改
#define ADMIN_ADDUSER 0x10000002 // admin_adduser 添加
#define ADMIN_DELUSER 0x10000004 // admin_deluser 删除
#define ADMIN_QUERY 0x10000008 //hitory_query 查找
#define ADMIN_HISTORY 0x10000010 //hitory_history 历史#define ADMIN_LIST 0x10000011 //列表#define QUIT 0x11111111#define ADMIN 0 //管理员
#define USER 1 //用户#define PASSLEN 8
#define NAMELEN 16
#define DATALEN 128/*员工基本信息*/
typedef struct staff_info
{int no; //员工编号int usertype; //ADMIN 1 USER 2 char name[NAMELEN]; //姓名char passwd[PASSLEN]; //密码int age; // 年龄char phone[NAMELEN]; //电话char addr[DATALEN]; // 地址char work[DATALEN]; //职位char date[DATALEN]; //入职年月int level; // 等级int salary; // 工资}staff_info_t;/*定义双方通信的结构体信息*/
typedef struct
{int msgtype; //请求的消息类型int usertype; //ADMIN 1 USER 2 char username[NAMELEN]; //姓名char passwd[PASSLEN]; //登陆密码char recvmsg[DATALEN]; //通信的消息int flags; //标志位staff_info_t info; //员工信息
}MSG;#define S_IP "10.0.12.9"
#define IP "192.168.250.100"
#define PORT "8888"char user_name[NAMELEN]; //姓名
char user_passwd[PASSLEN]; //登陆密码char history[DATALEN+100];#endif
服务端
...
客户端
#include "common.h"int do_login(int socketfd);/***************************************函数名:do_query*参 数:消息结构体*功 能:管理员查询****************************************/
void do_admin_query(int sockfd, MSG *msg)
{system("clear");memset(msg, 0, sizeof(MSG));msg->msgtype = ADMIN_QUERY;char name[NAMELEN] = "";printf("Please enter find no:");scanf("%s", name);while (getchar() != '\n');strcpy(msg->recvmsg, name);//发送查询请求if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("Sending the account to the server error\n");return;}//接受服务器响应while (1){recv(sockfd, msg, sizeof(MSG), 0);if (!strncmp(msg->recvmsg, "end", 3)){printf("find success\n");return;}if (!strncmp(msg->recvmsg, "no", 2)){printf("find error\n");return;}printf("----------------------------------\n");printf("staffno :%d\nusertype:%d\nname :%s\npasswd :%s\nage :%d\nphone :%s\naddr :%s\nwork :%s\ndate :%s\nlevel :%d\nsalary :%d\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("----------------------------------\n");}
}/***************************************函数名:admin_modification*参 数:消息结构体*功 能:管理员修改****************************************/
void do_admin_modification(int sockfd, MSG *msg) //管理员修改
{system("clear");memset(msg, 0, sizeof(MSG));msg->msgtype = ADMIN_MODIFY;int opt = 0;int tem;char str1[NAMELEN] = "";char str2[DATALEN] = "";char str3[PASSLEN] = "";printf("please enter user name:");scanf("%s",msg->username);printf("1:no\n2:usertype\n3:name\n4:passwd\n5:age\n6:phone\n7:addr\n8:work\n9:date\n10:level\n11:salary\nplease enter change option:");scanf("%d", &opt);while(getchar()!='\n');switch (opt){case 1:msg->flags = 1;printf("please enter no:");scanf("%d", &tem);msg->info.no = tem;break;case 2:msg->flags = 2;printf("please enter usertype:");scanf("%d", &tem);msg->info.usertype = tem;break;case 3:msg->flags = 3;printf("please enter name:");fgets(str1,NAMELEN,stdin);str1[strlen(str1)-1]='\0';strcpy(msg->info.name, str1);break;case 4:msg->flags = 4;printf("please enter passwd:");fgets(str3,PASSLEN,stdin);str3[strlen(str3)-1]='\0';strcpy(msg->info.passwd, str1);break;case 5:msg->flags = 5;printf("please enter age:");scanf("%d", &tem);msg->info.age = tem;break;case 6:msg->flags = 6;printf("please enter phone:");fgets(str1,NAMELEN,stdin);str1[strlen(str1)-1]='\0';strcpy(msg->info.phone, str1);break;case 7:msg->flags = 7;printf("please enter addr:");fgets(str2,DATALEN,stdin);str2[strlen(str2)-1]='\0';strcpy(msg->info.addr, str2);break;case 8:msg->flags = 8;printf("please enter work:");fgets(str2,DATALEN,stdin);str2[strlen(str2)-1]='\0';strcpy(msg->info.work, str2);break;case 9:msg->flags = 9;printf("please enter date:");fgets(str2,DATALEN,stdin);str2[strlen(str2)-1]='\0';strcpy(msg->info.date, str2);break;case 10:msg->flags = 10;printf("please enter level:");scanf("%d", &tem);msg->info.level = tem;break;case 11:msg->flags = 11;printf("please enter salary:");scanf("%d", &tem);msg->info.salary = tem;break;default:printf("enter error\n");return;}if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("Sending the account to the server error\n");return;}system("clear");recv(sockfd, msg, sizeof(MSG), 0);if (!strncmp(msg->recvmsg, "ok", 2)){printf("user change success\n");return;}else if(!strncmp(msg->recvmsg, "no", 2)){printf("user change error\n");return;}}/***************************************函数名:admin_adduser*参 数:消息结构体*功 能:管理员创建用户****************************************/
void do_admin_adduser(int sockfd, MSG *msg) //管理员添加用户
{system("clear");int tem;char str1[NAMELEN] = "";char str2[DATALEN] = "";char str3[PASSLEN] = "";memset(msg, 0, sizeof(MSG));msg->msgtype = ADMIN_ADDUSER;printf("please enter no:");scanf("%d", &tem);msg->info.no = tem;printf("please enter usertype:");scanf("%d", &tem);msg->info.usertype = tem;while (getchar() != '\n');printf("please enter name:");fgets(str1,NAMELEN,stdin);str1[strlen(str1)-1]='\0';strcpy(msg->info.name, str1);printf("please enter passwd:");fgets(str3,PASSLEN,stdin);str3[strlen(str3)-1]='\0';strcpy(msg->info.passwd, str3);printf("please enter age:");scanf("%d", &tem);msg->info.age = tem;while (getchar() != '\n');printf("please enter phone:");fgets(str1,NAMELEN,stdin);str1[strlen(str1)-1]='\0';strcpy(msg->info.phone, str1);printf("please enter addr:");fgets(str2,DATALEN,stdin);str2[strlen(str2)-1]='\0';strcpy(msg->info.addr, str2);printf("please enter work:");fgets(str2,DATALEN,stdin);str2[strlen(str2)-1]='\0';strcpy(msg->info.work, str2);printf("please enter date:");fgets(str2,DATALEN,stdin);str2[strlen(str2)-1]='\0';strcpy(msg->info.date, str2);printf("please enter level:");scanf("%d", &tem);msg->info.level = tem;printf("please enter salary:");scanf("%d", &tem);msg->info.salary = tem;if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("Sending the account to the server error\n");return;}recv(sockfd, msg, sizeof(MSG), 0);if (!strncmp(msg->recvmsg, "ok", 2)){printf("user add success\n");return;}else if (!strncmp(msg->recvmsg, "no", 2)){printf("user add error\n");return;}printf("user add error\n");
}/***************************************函数名:admin_deluser*参 数:消息结构体*功 能:管理员删除用户****************************************/
void do_admin_deluser(int sockfd, MSG *msg) //管理员删除用户
{system("clear");msg->msgtype = ADMIN_DELUSER;int no = 0;printf("pelase enter delete user NO:");scanf("%d", &no);msg->info.no = no;if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("Sending the account to the server error\n");return;}recv(sockfd, msg, sizeof(MSG), 0);if (!strncmp(msg->recvmsg, "ok", 2)){printf("user delete success\n");return;}else if (!strncmp(msg->recvmsg, "no", 2)){printf("user delete error\n");return;}
}/***************************************函数名:do_history*参 数:消息结构体*功 能:管理员查看历史记录****************************************/
void do_admin_history(int sockfd, MSG *msg)
{system("clear");memset(msg, 0, sizeof(MSG));msg->msgtype = ADMIN_HISTORY;putchar(10);printf(" %s | %s | %s \n","data","time","log");if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("Sending the account to the server error\n");return;}while (1){recv(sockfd, msg, sizeof(MSG), 0);if (msg->flags == 1){printf("find success\n");break;}if (msg->flags == 2){printf("find error\n");break;}printf("%s",msg->recvmsg);send(sockfd, msg, sizeof(MSG), 0);}}void do_admin_list(int sockfd, MSG *msg)
{system("clear");memset(msg, 0, sizeof(MSG));msg->msgtype = ADMIN_LIST;char name[NAMELEN] = "";//发送查询请求if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("Sending the account to the server error\n");return;}//接受服务器响应while (1){recv(sockfd, msg, sizeof(MSG), 0);if (!strncmp(msg->recvmsg, "endd", 4)){printf("find success\n");return;}if (!strncmp(msg->recvmsg, "no", 2)){printf("find error\n");return;}//printf("%d\t%d\t%s\t%s\t%d\t%s\t%s\t%s\t%s\t%d\t%d\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("----------------------------------\n");printf("staffno :%d\nusertype:%d\nname :%s\npasswd :%s\nage :%d\nphone :%s\naddr :%s\nwork :%s\ndate :%s\nlevel :%d\nsalary :%d\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("----------------------------------\n");send(sockfd, msg, sizeof(MSG), 0);}
}/***************************************函数名:admin_menu*参 数:套接字、消息结构体*功 能:管理员菜单****************************************/
void admin_menu(int sockfd, MSG *msg)
{int op = -1;printf(" ************ 1 查看 ************\n");printf(" ************ 2 修改 ************\n");printf(" ************ 3 添加 ************\n");printf(" ************ 4 删除 ************\n");printf(" ************ 5 列表 ************\n");printf(" ************ 6 清屏 ************\n");printf(" ************ 7 历史记录 ************\n");printf(" ************ 0 退回上级 ************\n");printf("请输入选项:");scanf("%d", &op);while(getchar()!='\n');if(op < 0 || op > 7){system("clear");printf("输入错误 请重新输入\n");admin_menu(sockfd,msg);}switch (op){case 0:system("clear");do_login(sockfd);break;case 1:do_admin_query(sockfd, msg);break;case 2:do_admin_modification(sockfd, msg);break;case 3:do_admin_adduser(sockfd, msg);break;case 4:do_admin_deluser(sockfd, msg);break;case 5:do_admin_list(sockfd, msg);break;case 6:system("clear");break;case 7:do_admin_history(sockfd,msg);break;default:printf("enter error\n");return;}
}/***************************************函数名:do_query*参 数:消息结构体*功 能:用户查找****************************************/
void do_user_query(int sockfd, MSG *msg)
{system("clear");memset(msg, 0, sizeof(MSG));msg->msgtype = USER_QUERY;strcpy(msg->username, user_name);strcpy(msg->passwd,user_passwd);//发送查询请求if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("Sending the account to the server error\n");return;}//接受服务器响应while(1){recv(sockfd, msg, sizeof(MSG), 0);if (!strncmp(msg->recvmsg, "end", 3)){printf("find success\n");return;}if (!strncmp(msg->recvmsg, "no", 2)){printf("find error\n");return;}printf("----------------------------------\n");printf("staffno :%d\nusertype:%d\nname :%s\npasswd :%s\nage :%d\nphone :%s\naddr :%s\nwork :%s\ndate :%s\nlevel :%d\nsalary :%d\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("----------------------------------\n");}
}/***************************************函数名:do_modification*参 数:消息结构体*功 能:用户修改****************************************/
void do_user_modification(int sockfd, MSG *msg)
{system("clear");memset(msg, 0, sizeof(MSG));msg->msgtype = USER_MODIFY;strcpy(msg->username, user_name);strcpy(msg->passwd,user_passwd);int opt = 0;int tem;char str1[NAMELEN] = "";char str2[DATALEN] = "";char str3[PASSLEN] = "";printf("1:no\n2:usertype(Please contact the administrator)\n3:name\n4:passwd\n5:age\n6:phone\n7:addr\n8:work\n9:date\n10:level\n11:salary\nplease enter change option:");scanf("%d", &opt);while(getchar()!='\n');switch (opt){case 1:msg->flags = 1;printf("please enter no:");scanf("%d", &tem);msg->info.no = tem;break;case 2:msg->flags = 2;printf("please enter usertype:");scanf("%d", &tem);msg->info.usertype = tem;break;case 3:msg->flags = 3;printf("please enter name:");fgets(str1,NAMELEN,stdin);str1[strlen(str1)-1]='\0';strcpy(msg->info.name, str1);break;case 4:msg->flags = 4;printf("please enter passwd:");fgets(str3,PASSLEN,stdin);str3[strlen(str3)-1]='\0';strcpy(msg->info.passwd, str3);break;case 5:msg->flags = 5;printf("please enter age:");scanf("%d", &tem);msg->info.age = tem;break;case 6:msg->flags = 6;printf("please enter phone:");fgets(str1,NAMELEN,stdin);str1[strlen(str1)-1]='\0';strcpy(msg->info.phone, str1);break;case 7:msg->flags = 7;printf("please enter addr:");fgets(str2,DATALEN,stdin);str2[strlen(str2)-1]='\0';strcpy(msg->info.addr, str2);break;case 8:msg->flags = 8;printf("please enter work:");fgets(str2,DATALEN,stdin);str2[strlen(str2)-1]='\0';strcpy(msg->info.work, str2);break;case 9:msg->flags = 9;printf("please enter date:");fgets(str2,DATALEN,stdin);str2[strlen(str2)-1]='\0';strcpy(msg->info.date, str2);break;case 10:msg->flags = 10;printf("please enter level:");scanf("%d", &tem);msg->info.level = tem;break;case 11:msg->flags = 11;printf("please enter salary:");scanf("%d", &tem);msg->info.salary = tem;break;default:printf("enter error\n");return;}if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("Sending the account to the server error\n");return;}system("clear");recv(sockfd, msg, sizeof(MSG), 0);if (!strncmp(msg->recvmsg, "ok", 2)){printf("user change success\n");return;}else if(!strncmp(msg->recvmsg, "no", 2)){printf("user change error\n");return;}
}/***************************************函数名:user_menu*参 数:消息结构体*功 能:用户菜单****************************************/
void user_menu(int sockfd, MSG *msg)
{int op = -1;printf(" ************ 1 查看 ************\n");printf(" ************ 2 修改 ************\n");printf(" ************ 3 清屏 ************\n");printf(" ************ 0 退回上级 *********\n");printf("请输入选项:");scanf("%d", &op);while(getchar()!='\n');if(op < 0 || op > 3){system("clear");printf("输入错误 请重新输入\n");user_menu(sockfd,msg);}switch (op){case 0:system("clear");do_login(sockfd);break;case 1:do_user_query(sockfd, msg);break;case 2:do_user_modification(sockfd, msg);break;case 3:system("clear");break;default:printf("enter error\n");break;}
}int admin_or_user_login(int sockfd, MSG *msg)
{//输入用户名和密码memset(msg->username, 0, NAMELEN);printf("请输入用户名:");scanf("%s", msg->username);getchar();memset(msg->passwd, 0, DATALEN);printf("请输入密码: ");scanf("%s", msg->passwd);getchar();strcpy(user_name,msg->username);strcpy(user_passwd,msg->passwd);//发送登陆请求if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("Sending the account to the server error\n");return -1;}//接受服务器响应recv(sockfd, msg, sizeof(MSG), 0);//判断是否登陆成功if (strncmp(msg->recvmsg, "OK", 2) == 0){if (msg->usertype == ADMIN){system("clear");printf("亲爱的管理员,欢迎您登陆员工管理系统!\n");while (1){admin_menu(sockfd, msg);}}else if (msg->usertype == USER){system("clear");printf("亲爱的用户,欢迎您登陆员工管理系统!\n");while (1){user_menu(sockfd, msg);}}}else{printf("登陆失败!%s\n", msg->recvmsg);admin_or_user_login(sockfd,msg);}return 0;
}/*************************************************函数名:do_login*参 数:套接字、消息结构体*返回值:是否登陆成功*功 能:登陆*************************************************/
int do_login(int socketfd)
{int n;MSG msg;while (1){printf("**********************************\n");printf("******** 1: 管理员模式 ********\n");printf("******** 2:普通用户模式 ********\n");printf("******** 0: 断开客户端 ********\n");printf("**********************************\n");printf("请输入您的选择(数字)>> ");scanf("%d", &n);while(getchar()!='\n');if(n < 0 || n > 2){system("clear");printf("输入错误 请重新输入\n");do_login(socketfd);}switch (n){case 1://管理员模式登录msg.msgtype = ADMIN_LOGIN; // 1msg.usertype = ADMIN; // 0break;case 2://普通用户登录msg.msgtype = USER_LOGIN;msg.usertype = USER;break;case 0://退出msg.msgtype = QUIT;if (send(socketfd, &msg, sizeof(MSG), 0) < 0){perror("do_login send");return -1;}close(socketfd);exit(0);default:printf("您的输入有误,请重新输入\n");}admin_or_user_login(socketfd, &msg);}
}int main(int argc, const char *argv[])
{// socket->填充->绑定->监听->等待连接->数据交互->关闭system("clear");int socketfd;//创建网络通信的套接字 流式套接字if (-1 == (socketfd = socket(AF_INET, SOCK_STREAM, 0))){printf("socket error\n");return -1;}printf("socket success\n");//填充网络结构体//填充服务器网路信息结构体struct sockaddr_in sin;//填充为IPV4地址sin.sin_family = AF_INET;//填充服务器IPsin.sin_addr.s_addr = inet_addr(IP);//填充服务器端口号sin.sin_port = htons(atoi(PORT));//连接服务器if (-1 == connect(socketfd, (struct sockaddr *)&sin, sizeof(sin))){printf("connect error\n");return -1;}printf("connect suceess\n");//登陆do_login(socketfd);//关闭套接字close(socketfd);return 0;
}
测试现象
Ubuntu 18.04 PZB - VMware