项目 - 员工信息管理系统

员工管理系统工作流程图:

员工管理系统-服务器端流程图:

 员工管理系统-客户端流程图:

项目名称:员工管理系统

项目时间:3天

项目描述:

1)服务器负责管理所有员工表单(以数据库形式或文件形式都可),其他客户端可通过网络连接服务器来查询员工表单。

2)需要账号密码登陆,其中需要区分管理员账号还是普通用户账号。

3)管理员账号可以查看、修改员工表单,管理员要负责管理所有的普通用户。

4)普通用户只能查询修改与本人有关的相关信息,其他员工信息(出于保密原则)不得泄露。

5)有查询历史记录功能。

6)能同时处理多台客户端的请求功能。

【1】TCP通信的编程步骤
  1.服务器:
	1)创建套接字
	2)绑定ip和端口号
	3)监听
	4)等待客户端连接
	
	int main()
	{
		//1.创建套接字
		int sockfd = socket();
		//2.初始化通信结构
		struct sockaddr_in addr;
		addr.sin_family=AF_INET;
		addr.sin_port = port;
		addr.sin_addr=addr;
		bind(sockfd, &addr);
		//3.监听
		listen();
		//4.连接
		while(1)
		{
			int connfd = accept();
			//5.循环数据收发
			while(1)
			{
				recv();
				send();
			}
		}
		close(sockfd);
		close(connfd);
	}
  2.客户端:
	1)创建套接字
	2)连接服务器
	
	int main()
	{
		//1.创建套接字
		int sockfd = socket();
		//2.初始化通信结构
		struct sockaddr_in addr;
		addr.sin_family=AF_INET;
		addr.sin_port = port;
		addr.sin_addr=addr;
		//3.连接
		connect();
		//5.循环数据收发
		while(1)
		{
			send();
			recv();
		}
	}
	
【2】服务器模型
 1.循环服务器
 2.并发服务器
	1)多线程
	2)多进程
	3)IO多路复用:
		a. select:
		基本思想:
		1. 先构造一张有关文件描述符的表(集合、数组); fd_set fd;
		2. 将你关心的文件描述符加入到这个表中;FD_SET();
		3. 然后调用一个函数。 select / poll 
		4. 当这些文件描述符中的一个或多个已准备好进行I/O操作的时候
				该函数才返回(阻塞)。
		5. 判断是哪一个或哪些文件描述符产生了事件(IO操作);
		6. 做对应的逻辑处理;
		****select函数返回之后,会自动将除了产生事件的文件描述符以外的位全部清空;
		程序步骤:
		1.把关心的文件描述符放入集合--FD_SET
		2.监听集合中的文件描述符--select
		3.依次判断哪个文件描述符有数据--FD_ISSET
		4.依次处理有数据的文件描述符的数据
		伪代码:
		fd_set fd;
		FD_SET(sockfd);
		while(1) {
			设置监听读写文件描述符集合(FD_*);
			调用select;
			select();	
			如果是监听套接字就绪,说明有新的连接请求 
			if(sockfd)
			{
				建立连接();
				int connfd = accept();
				加入到监听文件描述符集合;
				FD_SET(connfd);
			}否则说明是一个已经连接过的描述符 
			else
			{
				进行操作(send或者recv);
				recv();
				send();
			}
		} 
		select弊端: 
			1. 一个进程最多只能监听1024个文件描述符 (千级别)
			2. select是一种轮询的机制;
			3. 涉及到用户态和内核态的数据拷贝;
		
		b. poll
			1. 优化文件描述符个数的限制;
			2. poll是一种轮询的机制;
			3. 涉及到用户态和内核态的数据拷贝;
			函数接口:	   
			int poll(struct pollfd *fds, nfds_t nfds, int timeout);
			参数:
				struct pollfd *fds
				关心的文件描述符数组struct pollfd fds[N];
				nfds:个数
				timeout: 超市检测
						毫秒级的:如果填1000,1秒
								  如果-1,阻塞
								  
			问题:
			我想检测是键盘事件(标准输入 文件描述如为0 ),
			还是鼠标事件(文件描述符是/dev/input/mouse1);				  				
			1. 创建一个结构体数组
				struct pollfd fds[2];
			2. 将你关心的文件描述符加入到结构体成员中
				struct pollfd {
				   int   fd;         // 关心的文件描述符;
				   short events;     // 关心的事件,读
				   short revents;    // 如果产生事件,则会自动填充该成员的值
				};
			
				// 键盘
				fds[0].fd = 0;
				fds[0].events = POLLIN;
				
				//鼠标
				fds[1].fd = mouse1_fd;
				fds[1].events = POLLIN;
			
			3. 调用poll函数
				如果返回表示有事件产生;
				poll(fds,2,1000)
			4. 判断具体是哪个文件描述符产生了事件
				if(fds[0].revents == POLLIN)
				{
					....
				}
			
		c. epoll
			1. 没有文件描述符的限制
			2. 异步IO,当有事件产生,文件描述符主动调用callback
			3. 不用数据拷贝;
			
		3个功能函数:
			#include <sys/epoll.h>
			int epoll_create(int size);//创建红黑树根节点
			//成功时返回epoll文件描述符,失败时返回-1
			
			//控制epoll属性
			int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
			epfd:epoll_create函数的返回句柄。
			op:表示动作类型。有三个宏 来表示:
			EPOLL_CTL_ADD:注册新的fd到epfd中
			EPOLL_CTL_MOD:修改已注册fd的监听事件
			EPOLL_CTL_DEL:从epfd中删除一个fd
			FD:需要监听的fd。
			event:告诉内核需要监听什么事件
				EPOLLIN:表示对应文件描述符可读
				EPOLLOUT:可写
				EPOLLPRI:有紧急数据可读;
				EPOLLERR:错误;
				EPOLLHUP:被挂断;
				EPOLLET:触发方式,电平触发;
					 ET模式:表示状态的变化;
			//成功时返回0,失败时返回-1
			
			//等待事件到来
			int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
			功能:等待事件的产生,类似于select嗲用
			epfd:句柄;
			events:用来从内核得到事件的集合;
			maxevents:表示每次能处理事件最大个数;
			timeout:超时时间,毫秒,0立即返回,-1阻塞		
			//成功时返回发生事件的文件描述数,失败时返回-1
		伪代码:
		1.定义epoll事件,创建epoll的fd
			int epfd,epct,i;
			struct epoll_event event;       //定义epoll 事件
			struct epoll_event events[20];  //定义epoll 事件集合
			epfd = epoll_create(1); // 创建epoll 的fd 
		2.填充事件
			event.data.fd = serverFd;           //填充事件的fd
			event.events = EPOLLIN | EPOLLET;   //填充 事件类型 
			epoll_ctl(epfd,EPOLL_CTL_ADD,serverFd,&event);  //把serverFd(监听FD)注册到epfd中
		3.监听事件
			while(1){		
				epct = epoll_wait(epfd,events,20,-1); // 等待事件到来,阻塞模式 
				for(i=0;i<epct;i++){  //根据epoll返回的值来查询事件			
					if(events[i].data.fd == serverFd){ // 如果事件的fd是监听fd,调用accept处理
						clientFd = accept();
						//添加clientfd描述符
						epoll_ctl(epfd,EPOLL_CTL_ADD,clientFd,&event);					
					}else {  
					//如果不是serverFd,应是client数据事件,调用读数据
						read();
					}	
				}
			}

【3】数据库函数接口
	1.int   sqlite3_open(char  *path,   sqlite3 **db);        
	功能:打开sqlite数据库  
	参数:
		path: 数据库文件路径         
		db: 指向sqlite句柄的指针     
	返回值:成功返回0,失败返回错误码(非零值)

	2.int   sqlite3_close(sqlite3 *db);
	功能:关闭sqlite数据库
    返回值:成功返回0,失败返回错误码

	3.int sqlite3_exec(sqlite3 *db, const  char  *sql,  
			sqlite3_callback callback, void *,  char **errmsg);
	功能:执行SQL语句
	参数:
		 db:数据库句柄
         sql:SQL语句 ("create table stu .....;")
         callback:回调函数
		 void * arg: 
			当使用查询命令的时候,callback和arg才有意义;
			select .....			
         errmsg:错误信息指针的地址
			 char *errmsg;    
			 &errmsg;
	返回值:成功返回0,失败返回错误码
	int callback(void *para, int f_num, char **f_value, char **f_name);
	功能:每找到一条记录自动执行一次回调函数
	参数:
		para:   传递给回调函数的参数
		f_num:  记录中包含的字段数目(id name score) 
				 相当于有多少列;
		f_value:包含每个字段值的指针数组
		f_name:包含每个字段名称的指针数组		
	返回值:成功返回0,失败返回-1
	
	4.int  sqlite3_get_table(sqlite3 *db, const  char  *sql,
			char ***resultp,  int *nrow,  int *ncolumn, char **errmsg);
    功能:执行SQL操作
	参数:
		db:数据库句柄
		sql:SQL语句
		resultp:用来指向sql执行结果的指针;实际上就是“指针数组指针”;
		nrow:满足条件的记录的数目,实际上就是有多少行数据;
		ncolumn:每条记录包含的字段数目,实际上就是有多少个字段(多少列);
		errmsg:错误信息指针的地址
    返回值:成功返回0,失败返回错误码
	
练习:创建数据库stu.db,包含name、id、score字段,实现对数据库的增删改查。

代码实现:

服务器端(common.h文件,客户端服务器通用):


#ifndef _COMMON_H_
#define _COMMON_H_

#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 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 "124.223.177.144"
#define PORT "8888"

char user_name[NAMELEN];	 //姓名
char user_passwd[PASSLEN];	 //登陆密码

char history[DATALEN+100];




#endif

服务器端(server.h文件):

int process_user_or_admin_login_request(int acceptfd, MSG *msg);
int process_user_modify_request(int acceptfd, MSG *msg);
int process_user_query_request(int acceptfd, MSG *msg);
int process_admin_modify_request(int acceptfd, MSG *msg);
int process_admin_adduser_request(int acceptfd, MSG *msg);
int process_admin_deluser_request(int acceptfd, MSG *msg);
int process_admin_query_request(int acceptfd, MSG *msg);
int process_admin_history_request(int acceptfd, MSG *msg);
int process_admin_list_request(int acceptfd, MSG *msg);
int process_client_quit_request(int acceptfd, MSG *msg);
int process_client_request(int acceptfd, MSG *msg);
int process_recv_history_request(char *name,char *str);

服务器端(server.c文件):


#include "common.h"
#include "server.h"

sqlite3 *db = NULL;

//登录
int process_user_or_admin_login_request(int acceptfd, MSG *msg)
{

	//封装sql命令,表中查询用户名和密码-存在-登录成功-发送响应-失败-发送失败响应
	char sql[DATALEN] = {0};
	char *errmsg;
	char **result;
	int nrow, ncolumn;

	msg->info.usertype = msg->usertype;
	strcpy(msg->info.name, msg->username);
	strcpy(msg->info.passwd, msg->passwd);

	strcpy(user_name, msg->username);
	strcpy(user_passwd, msg->username);

	printf("usertype: %#x ,username: %s ,userpasswd: %s.\n", msg->info.usertype, msg->info.name, msg->info.passwd);
	sprintf(sql, "select * from usrinfo where usertype=%d and name='%s' and passwd='%s';", msg->info.usertype, msg->info.name, msg->info.passwd);

	if (sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
	{
		printf("---****----%s.\n", errmsg);
	}
	else
	{
		// printf("----nrow-----%d,ncolumn-----%d.\n",nrow,ncolumn);
		if (nrow == 0)
		{
			//查询到行为0
			strcpy(msg->recvmsg, "name or passwd failed.\n");
			send(acceptfd, msg, sizeof(MSG), 0);
			process_recv_history_request(msg->username, "longin error!");
		}
		else
		{
			strcpy(msg->recvmsg, "OK");
			send(acceptfd, msg, sizeof(MSG), 0);
			process_recv_history_request(msg->username, "longin success!");
		}
	}
	return 0;
}

//用户修改
int process_user_modify_request(int acceptfd, MSG *msg)
{
	char cmd[NAMELEN] = "";
	char *errmsg;
	char sql[DATALEN + 100] = "";
	int nrow = 0, ncolumn;
	char **result;

	switch (msg->flags)
	{
	case 1:
		sprintf(sql, "select * from usrinfo where taffon=%d;",msg->info.no);

		if (sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg) == SQLITE_OK)
		{
			memset(msg->recvmsg, 0, DATALEN);
			strcpy(msg->recvmsg, "no");
			send(acceptfd, msg, sizeof(MSG), 0);
			sqlite3_free_table(result);
			return -1;
		}
		sprintf(sql, "UPDATE usrinfo SET taffon=%d WHERE name='%s' AND passwd='%s';", msg->info.no, msg->username, msg->passwd);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change taffon -> %d", msg->info.no);
		process_recv_history_request(msg->username, history);
		
		break;
	case 2:
		// sprintf(sql, "UPDATE usrinfo SET usertype=%d WHERE name='%s' AND passwd='%s';",msg->info.usertype,msg->username,msg->passwd);
		{
			memset(msg, 0, sizeof(MSG));
			strcpy(msg->recvmsg, "no");
			if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
			{
				printf("Sending the account to the client error\n");
				return -1;
			}
			return -1;
		}
		break;
	case 3:
		sprintf(sql, "UPDATE usrinfo SET name='%s' WHERE name='%s' AND passwd='%s';", msg->info.name, msg->username, msg->passwd);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change name -> %s", msg->info.name);
		process_recv_history_request(msg->username, history);
		
		break;
	case 4:
		sprintf(sql, "UPDATE usrinfo SET passwd='%s' WHERE name='%s' AND passwd='%s';", msg->info.passwd, msg->username, msg->passwd);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change passwd -> %s", msg->info.passwd);
		process_recv_history_request(msg->username, history);

		break;
	case 5:
		sprintf(sql, "UPDATE usrinfo SET age=%d WHERE name='%s' AND passwd='%s';", msg->info.age, msg->username, msg->passwd);

		memset(history, 0, DATALEN);
		sprintf(history,"change age -> %d", msg->info.age);
		process_recv_history_request(msg->username, history);
		
		break;
	case 6:
		sprintf(sql, "UPDATE usrinfo SET phone='%s' WHERE name='%s' AND passwd='%s';", msg->info.phone, msg->username, msg->passwd);

		memset(history, 0, DATALEN);
		sprintf(history,"change phone -> %s", msg->info.phone);
		process_recv_history_request(msg->username, history);
		
		break;
	case 7:
		sprintf(sql, "UPDATE usrinfo SET addr='%s' WHERE name='%s' AND passwd='%s';", msg->info.addr, msg->username, msg->passwd);

		memset(history, 0, DATALEN);
		sprintf(history,"change addr -> %s", msg->info.addr);
		process_recv_history_request(msg->username, history);
		
		break;
	case 8:
		sprintf(sql, "UPDATE usrinfo SET work='%s' WHERE name='%s' AND passwd='%s';", msg->info.work, msg->username, msg->passwd);

		memset(history, 0, DATALEN);
		sprintf(history,"change work -> %s", msg->info.work);
		process_recv_history_request(msg->username, history);
		
		break;
	case 9:
		sprintf(sql, "UPDATE usrinfo SET date='%s' WHERE name='%s' AND passwd='%s';", msg->info.date, msg->username, msg->passwd);

		memset(history, 0, DATALEN);
		sprintf(history,"change date -> %s", msg->info.date);
		process_recv_history_request(msg->username, history);
		
		break;
	case 10:
		sprintf(sql, "UPDATE usrinfo SET level=%d WHERE name='%s' AND passwd='%s';", msg->info.level, msg->username, msg->passwd);

		memset(history, 0, DATALEN);
		sprintf(history,"change level -> %d", msg->info.level);
		process_recv_history_request(msg->username, history);
		
		break;
	case 11:
		sprintf(sql, "UPDATE usrinfo SET salary=%d WHERE name='%s' AND passwd='%s';", msg->info.salary, msg->username, msg->passwd);

		memset(history, 0, DATALEN);
		sprintf(history,"change salary -> %d", msg->info.salary);
		process_recv_history_request(msg->username, history);
		
		break;
	default:
		printf("enter error\n");
		return -1;
	}

	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
		memset(msg, 0, sizeof(MSG));
		strcpy(msg->recvmsg, "no");
		if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
		{
			printf("Sending the account to the client error\n");
			return -1;
		}
		return -1;
	}
	memset(msg, 0, sizeof(MSG));
	strcpy(msg->recvmsg, "ok");
	if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
	{
		printf("Sending the account to the client error\n");
		return -1;
	}
	return 1;
}

//用户查找
int process_user_query_request(int acceptfd, MSG *msg)
{
	char sql[DATALEN + 50] = "";
	char **result = NULL;
	int row, column;
	char *errmsg = NULL;

	memset(history, 0, DATALEN);
	sprintf(history,"query self request");
	process_recv_history_request(msg->username, history);

	sprintf(sql, "select * from usrinfo where name='%s' and passwd='%s';", msg->username, msg->passwd);

	if (sqlite3_get_table(db, sql, &result, &row, &column, &errmsg) != SQLITE_OK)
	{
		goto end;
	}
	printf("查询结果成功\n");

	if (row == 0)
	{
		memset(msg->recvmsg, 0, DATALEN);
		strcpy(msg->recvmsg, "no");
		send(acceptfd, msg, sizeof(MSG), 0);
		sqlite3_free_table(result);
		return -1;
	}

	printf("row=%d column=%d\n", row, column);

	int i = 0;

	memset(msg->recvmsg, 0, DATALEN);
	for (i = 11; i < (row + 1) * column; i++)
	{
		switch (i % column)
		{
		case 0:
			msg->info.no = atoi(result[i]);
			break;
		case 1:
			msg->info.usertype = atoi(result[i]);
			break;
		case 2:
			strcpy(msg->info.name, result[i]);
			break;
		case 3:
			strcpy(msg->info.passwd, result[i]);
			break;
		case 4:
			msg->info.age = atoi(result[i]);
			break;
		case 5:
			strcpy(msg->info.phone, result[i]);
			break;
		case 6:
			strcpy(msg->info.addr, result[i]);
			break;
		case 7:
			strcpy(msg->info.work, result[i]);
			break;
		case 8:
			strcpy(msg->info.date, result[i]);
			break;
		case 9:
			msg->info.level = atoi(result[i]);
			break;
		case 10:
			msg->info.salary = atoi(result[i]);
			break;
		default:
			break;
		}
		if (i % column == (column - 1))
		{
			send(acceptfd, msg, sizeof(MSG), 0);
			memset(msg->recvmsg, 0, DATALEN);
		}
	}
	putchar(10);

end:
	memset(msg->recvmsg, 0, DATALEN);
	strcpy(msg->recvmsg, "end");
	send(acceptfd, msg, sizeof(MSG), 0);

	//释放查询到的结果
	sqlite3_free_table(result);

	return 0;
}

//管理修改
int process_admin_modify_request(int acceptfd, MSG *msg)
{
	char cmd[NAMELEN] = "";
	char *errmsg;
	char sql[DATALEN + 100] = "";
	int nrow = 0, ncolumn;
	char **result;

	sprintf(sql, "select * from usrinfo where name='%s';", msg->username);

	if (sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
	{
		printf("---select error----%s.\n", errmsg);
	}

	if (nrow == 0)
	{
		//如果此人信息不存在
		memset(msg, 0, sizeof(MSG));
		strcpy(msg->recvmsg, "no");
		send(acceptfd, msg, sizeof(MSG), 0);
		return 0;
	}

	switch (msg->flags)
	{
	case 1:
		sprintf(sql, "UPDATE usrinfo SET taffon=%d WHERE name='%s';", msg->info.no, msg->username);
				
		memset(history, 0, DATALEN);
		sprintf(history,"change %s taffon -> %d",msg->username,msg->info.no);
		process_recv_history_request(msg->username, history);
		
		break;
	case 2:
		sprintf(sql, "UPDATE usrinfo SET usertype=%d WHERE name='%s';", msg->info.usertype, msg->username);
				
		memset(history, 0, DATALEN);
		sprintf(history,"change %s usertype -> %s",msg->username, msg->info.name);
		process_recv_history_request(msg->username, history);
		
		break;
	case 3:
		sprintf(sql, "UPDATE usrinfo SET name='%s' WHERE name='%s';", msg->info.name, msg->username);
				
		memset(history, 0, DATALEN);
		sprintf(history,"change %s name -> %s",msg->username, msg->info.name);
		process_recv_history_request(msg->username, history);
		
		break;
	case 4:
		sprintf(sql, "UPDATE usrinfo SET passwd='%s' WHERE name='%s';", msg->info.passwd, msg->username);
				
		memset(history, 0, DATALEN);
		sprintf(history,"change %s passwd -> %s",msg->username, msg->info.passwd);
		process_recv_history_request(msg->username, history);

		break;
	case 5:
		sprintf(sql, "UPDATE usrinfo SET age=%d WHERE name='%s';", msg->info.age, msg->username);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change %s age -> %d", msg->username,msg->info.age);
		process_recv_history_request(msg->username, history);
		
		break;
	case 6:
		sprintf(sql, "UPDATE usrinfo SET phone='%s' WHERE name='%s';", msg->info.phone, msg->username);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change %s phone -> %s",msg->username, msg->info.phone);
		process_recv_history_request(msg->username, history);
		
		break;
	case 7:
		sprintf(sql, "UPDATE usrinfo SET addr='%s' WHERE name='%s';", msg->info.addr, msg->username);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change %s addr -> %s",msg->username, msg->info.addr);
		process_recv_history_request(msg->username, history);
		
		break;
	case 8:
		sprintf(sql, "UPDATE usrinfo SET work='%s' WHERE name='%s';", msg->info.work, msg->username);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change %s work -> %s",msg->username, msg->info.work);
		process_recv_history_request(msg->username, history);
		
		break;
	case 9:
		sprintf(sql, "UPDATE usrinfo SET date='%s' WHERE name='%s';", msg->info.date, msg->username);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change %s date -> %s",msg->username, msg->info.date);
		process_recv_history_request(msg->username, history);
		
		break;
	case 10:
		sprintf(sql, "UPDATE usrinfo SET level=%d WHERE name='%s';", msg->info.level, msg->username);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change %s level -> %d",msg->username, msg->info.level);
		process_recv_history_request(msg->username, history);
		
		break;
	case 11:
		sprintf(sql, "UPDATE usrinfo SET salary=%d WHERE name='%s';", msg->info.salary, msg->username);
		
		memset(history, 0, DATALEN);
		sprintf(history,"change %s salary -> %d", msg->username,msg->info.salary);
		process_recv_history_request(msg->username, history);
		
		break;
	default:
		printf("enter error\n");
		return -1;
	}

	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
		return -1;
	}
	memset(msg, 0, sizeof(MSG));
	strcpy(msg->recvmsg, "ok");
	if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
	{
		printf("Sending the account to the client error\n");
		return -1;
	}
	return 1;
}

//管理添加
int process_admin_adduser_request(int acceptfd, MSG *msg)
{
	char cmd[NAMELEN] = "";
	char *errmsg;
	char sql[DATALEN + 400] = "";
	int nrow = 0, ncolumn;
	char **result;

					
	memset(history, 0, DATALEN);
	sprintf(history,"%s add %s",user_name,msg->info.name);
	process_recv_history_request(msg->username, history);
		

	sprintf(sql, "select * from usrinfo where staffno=%d;", msg->info.no);

	if (sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg) != SQLITE_OK)
	{
		printf("%d\n", __LINE__);
		memset(msg, 0, sizeof(MSG));
		strcpy(msg->recvmsg, "no");
		send(acceptfd, msg, sizeof(MSG), 0);
		return -1;
	}

	if (nrow != 0)
	{
		//如果此人信息存在
		printf("%d\n", __LINE__);
		memset(msg, 0, sizeof(MSG));
		strcpy(msg->recvmsg, "no");
		send(acceptfd, msg, sizeof(MSG), 0);
		return 0;
	}

	sprintf(sql, "INSERT INTO usrinfo VALUES (%d,%d,'%s','%s',%d,'%s','%s','%s','%s',%d,%d);", 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);

	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
		return -1;
	}
	memset(msg, 0, sizeof(MSG));
	strcpy(msg->recvmsg, "ok");
	if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
	{
		printf("Sending the account to the client error\n");
		return -1;
	}
}

//管理删除
int process_admin_deluser_request(int acceptfd, MSG *msg)
{
	char sql[DATALEN] = "";
	char *errmsg;

	memset(history, 0, DATALEN);
	sprintf(history,"%s del no -> %d",user_name,msg->info.no);
	process_recv_history_request(msg->username, history);

	sprintf(sql, "DELETE FROM usrinfo WHERE staffno=%d;", msg->info.no);

	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
		memset(msg, 0, sizeof(MSG));
		strcpy(msg->recvmsg, "no");
		if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
		{
			printf("Sending the account to the client error\n");
			return -1;
		}
		return -1;
	}

	memset(msg, 0, sizeof(MSG));
	strcpy(msg->recvmsg, "ok");
	if (send(acceptfd, msg, sizeof(MSG), 0) < 0)
	{
		printf("Sending the account to the client error\n");
		return -1;
	}
}

//管理查找
int process_admin_query_request(int acceptfd, MSG *msg)
{
	char sql[DATALEN + 50] = "";
	char **result = NULL;
	int row, column;
	char *errmsg = NULL;

	
	memset(history, 0, DATALEN);
	sprintf(history,"find no-> %d",msg->info.no);
	process_recv_history_request(user_name, history);


	sprintf(sql, "select * from usrinfo where staffno=%d;", atoi(msg->recvmsg));

	if (sqlite3_get_table(db, sql, &result, &row, &column, &errmsg) != SQLITE_OK)
	{
		goto end;
	}
	printf("查询结果成功\n");

	if (row == 0)
	{
		memset(msg->recvmsg, 0, DATALEN);
		strcpy(msg->recvmsg, "no");
		send(acceptfd, msg, sizeof(MSG), 0);
		sqlite3_free_table(result);
		return -1;
	}

	printf("row=%d column=%d\n", row, column);

	int i = 0;

	memset(msg->recvmsg, 0, DATALEN);
	for (i = 11; i < (row + 1) * column; i++)
	{
		switch (i % column)
		{
		case 0:
			msg->info.no = atoi(result[i]);
			break;
		case 1:
			msg->info.usertype = atoi(result[i]);
			break;
		case 2:
			strcpy(msg->info.name, result[i]);
			break;
		case 3:
			strcpy(msg->info.passwd, result[i]);
			break;
		case 4:
			msg->info.age = atoi(result[i]);
			break;
		case 5:
			strcpy(msg->info.phone, result[i]);
			break;
		case 6:
			strcpy(msg->info.addr, result[i]);
			break;
		case 7:
			strcpy(msg->info.work, result[i]);
			break;
		case 8:
			strcpy(msg->info.date, result[i]);
			break;
		case 9:
			msg->info.level = atoi(result[i]);
			break;
		case 10:
			msg->info.salary = atoi(result[i]);
			break;
		default:
			break;
		}
		if (i % column == (column - 1))
		{
			send(acceptfd, msg, sizeof(MSG), 0);
			memset(msg->recvmsg, 0, DATALEN);
		}
	}
	putchar(10);

end:
	memset(msg->recvmsg, 0, DATALEN);
	strcpy(msg->recvmsg, "end");
	send(acceptfd, msg, sizeof(MSG), 0);

	//释放查询到的结果
	sqlite3_free_table(result);

	return 0;
}

//管理历史
int process_admin_history_request(int acceptfd, MSG *msg)
{
	
	memset(history, 0, DATALEN);
	sprintf(history,"(passwd:%s) -> cat history",user_passwd);
	process_recv_history_request(user_name, history);


	char sql[DATALEN] = "";
	char **result = NULL;
	int row, column;
	char *errmsg = NULL;

	sprintf(sql, "SELECT * FROM historyinfo;");

	if (sqlite3_get_table(db, sql, &result, &row, &column, &errmsg) != SQLITE_OK)
	{
		memset(msg->recvmsg, 0, DATALEN);
	
		msg->flags = 1;

		send(acceptfd, msg, sizeof(MSG), 0);

		//释放查询到的结果
		sqlite3_free_table(result);

		return -1;

	}
	printf("查询结果成功\n");

	if (row == 0)
	{
		memset(msg->recvmsg, 0, DATALEN);
		//strcpy(msg->recvmsg, "no");

		msg->flags = 2;

		send(acceptfd, msg, sizeof(MSG), 0);
		sqlite3_free_table(result);
		
		return -1;
	}

	printf("row=%d column=%d\n", row, column);

	int i = 0;

	
	for (i = 3; i < (row + 1) * column; i++)
	{
		strcat(msg->recvmsg, result[i]);
		strcat(msg->recvmsg, "\t");
		if (i % column == (column - 1))
		{
			strcat(msg->recvmsg, "\n");
			send(acceptfd, msg, sizeof(MSG), 0);

			recv(acceptfd, msg, sizeof(MSG), 0);
			
			printf("%s",msg->recvmsg);
			
			memset(msg->recvmsg, 0, DATALEN);
		}
	}

	memset(msg->recvmsg, 0, DATALEN);
	
	msg->flags = 1;

	send(acceptfd, msg, sizeof(MSG), 0);

	//释放查询到的结果
	sqlite3_free_table(result);
}

int process_recv_history_request(char *name, char *str)
{
	char data[11] = ""; // 2022/10/29
	char timeb[9] = ""; // 02:18:00

	char his[50] = "";
	char sql[DATALEN] = "";
	char *errmsg = NULL;

	strcat(his, name);
	strcat(his, " : ");
	strcat(his, str);

	//转换成日历格式
	struct tm *p = NULL;
	long int q;

	q = time(NULL);
	p = localtime(&q);

	sprintf(data, "%04d-%02d-%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday);
	sprintf(timeb, "%02d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec);

	sprintf(sql, "INSERT INTO historyinfo VALUES ('%s','%s','%s');", data, timeb, his);

	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
		return -1;
	}
}

//列表
int process_admin_list_request(int acceptfd, MSG *msg)
{
		
	memset(history, 0, DATALEN);
	sprintf(history,"(passwd:%s) -> cat list",user_passwd);
	process_recv_history_request(user_name, history);



	char sql[DATALEN] = "";
	char **result = NULL;
	int row, column;
	char *errmsg = NULL;

	sprintf(sql, "SELECT * FROM usrinfo;");

	if (sqlite3_get_table(db, sql, &result, &row, &column, &errmsg) != SQLITE_OK)
	{
		goto end;
	}
	printf("查询结果成功\n");

	if (row == 0)
	{
		memset(msg->recvmsg, 0, DATALEN);
		strcpy(msg->recvmsg, "no");
		send(acceptfd, msg, sizeof(MSG), 0);
		sqlite3_free_table(result);
		return -1;
	}

	printf("row=%d column=%d\n", row, column);

	int i = 0;

	memset(msg->recvmsg, 0, DATALEN);
	for (i = 11; i < (row + 1) * column; i++)
	{
		switch (i % column)
		{
		case 0:
			msg->info.no = atoi(result[i]);
			break;
		case 1:
			msg->info.usertype = atoi(result[i]);
			break;
		case 2:
			strcpy(msg->info.name, result[i]);
			break;
		case 3:
			strcpy(msg->info.passwd, result[i]);
			break;
		case 4:
			msg->info.age = atoi(result[i]);
			break;
		case 5:
			strcpy(msg->info.phone, result[i]);
			break;
		case 6:
			strcpy(msg->info.addr, result[i]);
			break;
		case 7:
			strcpy(msg->info.work, result[i]);
			break;
		case 8:
			strcpy(msg->info.date, result[i]);
			break;
		case 9:
			msg->info.level = atoi(result[i]);
			break;
		case 10:
			msg->info.salary = atoi(result[i]);
			break;
		default:
			break;
		}
		if (i % column == (column - 1))
		{
			send(acceptfd, msg, sizeof(MSG), 0);
			recv(acceptfd, msg, sizeof(MSG), 0);
			memset(msg->recvmsg, 0, DATALEN);
		}
	}
	putchar(10);

end:
	memset(msg->recvmsg, 0, DATALEN);
	strcpy(msg->recvmsg, "endd");
	send(acceptfd, msg, sizeof(MSG), 0);

	//释放查询到的结果
	sqlite3_free_table(result);
}

//客户端退出
int process_client_quit_request(int acceptfd, MSG *msg)
{
	printf("------------%s-----------%d.\n", __func__, __LINE__);
}

//处理客户端请求
int process_client_request(int acceptfd, MSG *msg)
{
	//请求的消息类型
	switch (msg->msgtype)
	{
	case USER_LOGIN:
	case ADMIN_LOGIN:
		process_user_or_admin_login_request(acceptfd, msg); //登录
		break;
	case USER_MODIFY:
		process_user_modify_request(acceptfd, msg); //用户修改
		break;
	case USER_QUERY:
		process_user_query_request(acceptfd, msg); //用户查找
		break;
	case ADMIN_MODIFY:
		process_admin_modify_request(acceptfd, msg); //管理修改
		break;
	case ADMIN_ADDUSER:
		process_admin_adduser_request(acceptfd, msg); //管理添加
		break;
	case ADMIN_DELUSER:
		process_admin_deluser_request(acceptfd, msg); //管理删除
		break;
	case ADMIN_QUERY:
		process_admin_query_request(acceptfd, msg); //管理查找
		break;
	case ADMIN_HISTORY:
		process_admin_history_request(acceptfd, msg); //管理历史
		break;
	case ADMIN_LIST:
		process_admin_list_request(acceptfd, msg); //列表
		break;
	case QUIT:
		process_client_quit_request(acceptfd, msg); //客户端退出
		break;
	default:
		break;
	}
}

int main(int argc, const char *argv[])
{
	system("clear");
	//打开数据库
	if (sqlite3_open(STAFF_DATABASE, &db) != SQLITE_OK)
	{
		printf("%s.\n", sqlite3_errmsg(db));
		return -1;
	}
	printf("database open success\n");
	

	// socket->填充->绑定->监听->等待连接->数据交互->关闭

	//创建网络通信的套接字
	int socketfd = socket(AF_INET, SOCK_STREAM, 0);
	if (socketfd < 0)
	{
		printf("socket error\n");
		return -1;
	}
	printf("socket success\n");

	//允许端口快速重用
	int reuse = 1;
	if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		printf("setsockopt error\n");
		return -1;
	}
	printf("setsockopt success\n");

	//填充网络结构体
	//填充服务器网路信息结构体
	struct sockaddr_in sin;
	//填充为IPV4地址
	sin.sin_family = AF_INET;
	//填充服务器IP
	sin.sin_addr.s_addr = inet_addr(S_IP);
	//填充服务器端口号
	sin.sin_port = htons(atoi(PORT));

	//绑定网络套接字和网络结构体
	if (bind(socketfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
	{
		printf("bind error\n");
		return -1;
	}
	printf("bind success\n");

	//监听套接字,将主动套接字转化为被动套接字
	if (listen(socketfd, 10) < 0)
	{
		printf("listen error\n");
		return -1;
	}
	printf("listen success\n");

	//通过select实现并发
	//客户端网络信息结构体
	struct sockaddr_in cin;
	socklen_t addrlen = sizeof(cin);

	//创建一个读集合
	fd_set readfds, tempfds;

	//将集合清空
	FD_ZERO(&readfds);
	FD_ZERO(&tempfds);

	//将sfd文件描述符添加到集合
	FD_SET(socketfd, &readfds);

	//最大文件描述符
	int maxfd = socketfd;
	//接收select返回值
	int select_res = 0;
	MSG msg;
	ssize_t recvbytes = 0;
	int acceptfd = -1;
	int i = 0;

	//定义一个数组,存储每次连接成功的客户端的信息
	struct sockaddr_in save_addr[1024 - 4];

	while (1)
	{
		tempfds = readfds;
		//>0, 三个集合中成功触发事件的文件描述符个数  =0超时  =-1失败;
		select_res = select(maxfd + 1, &tempfds, NULL, NULL, NULL);
		if (select_res < 0)
		{
			printf("select error\n");
			return -1;
		}
		else if (select_res == 0)
		{
			printf("select timeout\n");
			return -1;
		}

		for (i = 0; i <= maxfd; i++)
		{
			//判断0~maxfd这些文件描述符在不在集合中
			if (FD_ISSET(i, &tempfds) == 0)
			{
				continue;
			}

			//能运行到当前位置,则说明i所代表的文件描述符有事件产生

			//判断是否是集合里关注的事件

			if (socketfd == i)
			{
				printf("触发客户端连接事件:");
				fflush(stdout);

				//数据交互
				acceptfd = accept(socketfd, (struct sockaddr *)&cin, &addrlen);
				if (acceptfd == -1)
				{
					printf("acceptfd error\n");
					return -1;
				}
				//网络字节序的IP-->点分十进制  网络字节序的port--->本机字节序
				printf("[%s : %d] acceptfd = %d\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), acceptfd);

				memset(history, 0, DATALEN);
				sprintf(history,"[%s : %d] acceptfd[%d]",inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), acceptfd);
				process_recv_history_request("connect", history);



				//将cin存储到 save_addr数组对应的位置,
				// acceptfd==4,则存储到下标为0,acceptfd==5,存储到下标为1,acceptfd==n,则存储到下标为n-4的位置
				save_addr[acceptfd - 4] = cin;

				//将acceptfd添加到集合中
				FD_SET(acceptfd, &readfds);

				//更新maxfd
				maxfd = maxfd > acceptfd ? maxfd : acceptfd;
			}
			else
			{
				//客户端交互事件
				bzero(&msg, sizeof(MSG));
				recvbytes = recv(i, &msg, sizeof(MSG), 0);
				if (recvbytes == -1)
				{
					// <0 错误
					printf("recv error\n");
					continue;
				}
				else if (recvbytes == 0)
				{
					// ==0
					printf("[%s : %d] acceptfd = %d client off-line\n",
						   inet_ntoa(save_addr[i - 4].sin_addr), ntohs(save_addr[i - 4].sin_port), i);

					memset(history, 0, DATALEN);
					sprintf(history,"[%s : %d] acceptfd = [%d]",inet_ntoa(save_addr[i - 4].sin_addr), ntohs(save_addr[i - 4].sin_port), i);
					process_recv_history_request("lost connect", history);

					//关闭文件描述符
					close(i);

					//将文件描述符从集合中剔除
					FD_CLR(i, &readfds);

					//更新maxfd
					for (int i = maxfd; i > 0; i--)
					{
						if (FD_ISSET(i, &readfds))
						{
							maxfd = i;
							break;
						}
					}
					printf("peer shutdown.\n");
				}
				else
				{
					//处理客户端请求
					process_client_request(i, &msg);
				}
			}
		}
	}

	close(socketfd);

	return 0;
}

客户端(client.h文件):

void do_admin_query(int sockfd, MSG *msg);
void do_admin_modification(int sockfd, MSG *msg);
void do_admin_adduser(int sockfd, MSG *msg);
void do_admin_deluser(int sockfd, MSG *msg);
void do_admin_history(int sockfd, MSG *msg);
void do_admin_list(int sockfd, MSG *msg);
void admin_menu(int sockfd, MSG *msg);
void do_user_query(int sockfd, MSG *msg);
void do_user_modification(int sockfd, MSG *msg);
void user_menu(int sockfd, MSG *msg);
int admin_or_user_login(int sockfd, MSG *msg);
int do_login(int socketfd);

客户端(client.c文件):


#include "common.h"
#include "client.h"

/**************************************
 *函数名: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  find   ************\n");
	printf(" ************ 2 change  ************\n");
	printf(" ************ 3  add    ************\n");
	printf(" ************ 4 delete  ************\n");
	printf(" ************ 5  list   ************\n");
	printf(" ************ 6  clean   ************\n");
	printf(" ************ 7 history ************\n");
	printf(" ************ 0  quit   ************\n");
	printf("please enter your option:");
	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  find  ************\n");
	printf(" ************ 2 change ************\n");
	printf(" ************ 3 clean  ************\n");
	printf(" ************ 0  quit  ************\n");
	printf("please enter your option:");
	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; // 1
			msg.usertype = ADMIN;	   // 0
			break;
		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;
	//填充服务器IP
	sin.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;
}

员工信息管理系统 测试

  • 7
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coding Peasant

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值