开发环境:vmware ubuntu18.04
实现功能:基本功能包括管理者和普通员工用户的登录,管理者拥有操作所有员工信息的最高权限,可以进行增删改 查等操作,普通用户仅拥有查看、修改个人部分信息的权限
具体功能详解:
1)服务器负责管理所有员工表单(以数据库形式或文件形式都可),客户端可通过网络连接服务器来查询员工表单。
2)需要账号密码登陆,其中需要区分管理员账号还是普通用户账号。
3)管理员账号可以查看、修改员工表单,管理员要负责管理所有的普通用户。
4)普通用户只能查询修改与本人有关的部分相关信息,其他员工信息(出于保密原则)不得泄露,个人职务、工资等信息(出于公司管理角度)员工无法自己进行更改。
5)有查询历史记录功能。
6)能同时处理多台客户端的请求功能。
项目职责:
使用socket实现TCP通信
使用多进程实现并发服务器
使用SQLite数据库管理用户和学生信息
使用SQLite数据库记录系统运行的日志信息
服务器流程及设计知识简介:
一、TCP通信编程步骤:
1、创建套接字——socket;
2、绑定服务器ip和端口号——bind;
3、设置为被动监听状态——listen;
4、等待客户端连接——accept;
5、数据的交互——recv、send;
二、服务器模型:
1>循环服务器
//1. 一次只能处理一个客户端,等这个客户端退出后,才能处理下一个客户端。 //2. 缺点多个客户端不能同时处理。 sfd = socket(); bind(); listen(); while(1) { newfd = accept(); while(1) { recv(); send(); } close(newfd); } close(sfd);
2>并发服务器
①多进程并发服务器:
Ⅰ可以同时处理多个客户端的请求,创建子进程或者分支线程来处理客户端处理客户端的请求。
Ⅱ父进程/主线程只负责连接,子进程/分支线程 只负责与客户端交互。
void handler(int sig) { while(waitpid(-1, NULL, WNOHANG) > 0); } signal(17, handler); sfd=socket(); bind(); listen(); while(1) { newfd=accept(); pid=fork(); if(0 == pid) { close(sfd); while(1) { recv(); send(); } close(newfd); exit(0); } else if(pid > 0) { close(newfd); } }
②多线程并发服务器
sfd = socket(); bind(); listen(); while(1) { newfd = accept(); info.newfd = newfd; info.cin = cin; ..... pthread_create(&tid, NULL, callBack, &info); pthread_detach(tid); } void* callBack(void* arg) { while(1) { recv(); send(); } close(newfd); }
③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.依次处理有数据的文件描述符的数据
socket(); bind(); listen(); fd_set readfds, tempfds; FD_ZERO(&readfds); FD_SET(0, &readfds); FD_SET(sfd, &readfds); while(1) { tempfds = readfds; select(maxfd+1, &tempfds, NULL, NULL, NULL); for(i=0; i<=maxfd; i++) { if(FD_ISSET(i, &tempfds) == 0) continue; if(0 == i){ fgets() } //键盘输入事件 else if(sfd == i){ //客户端连接事件 newfd = accept(); FD_SET(newf, &readfds); maxfd = maxfd>newfd?maxfd:newfd; } else { //客户端交互事件 recv(); 判断是否要关闭文件描述符 判断是否要将文件描述符从readfds中剔除; 判断是否需要更新maxfd; } } } close(sfd);
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>#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.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,失败返回-14.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,失败返回错误码
客户端流程及涉及知识简介:
TCP客户端流程
1、创建套接字
2、连接服务器
3、完成数据的收发,实现增删改查功能
服务器测试结果:
ubuntu-staff$ ./a.out
sqlite3 open staff success
create table staff success
create table history success
bind success
listen success
192.168.250.100:57954 newfd=5 accept
1 boss 1员工登录系统 2022-12-10 11:08:17
1 boss 1管理员成功添加3 ppp用户 2022-12-10 11:08:53
1 boss 1管理员查询员工信息
1 boss 1管理员查询员工信息
1 boss 1管理员查询员工信息
1 boss 1员工修改3 员工姓名信息为ooo 2022-12-10 11:09:30
192.168.250.100:57956 newfd=5 accept
1 boss 1员工登录系统 2022-12-10 11:11:38
1 boss 1管理员成功添加4 wang用户 2022-12-10 11:12:13
192.168.250.100:57960 newfd=5 accept
4 wang 4员工登录系统 2022-12-10 11:12:32
4 wang 4管理员查询员工信息
4 li 4员工修改4 员工姓名信息为li 2022-12-10 11:12:42
192.168.250.100:57962 newfd=5 accept
4 li 4员工登录系统 2022-12-10 11:13:33
4 li 4管理员查询员工信息
4 li 4员工修改4 员工年龄信息为1997 2022-12-10 11:13:49
4 li 4管理员查询员工信息
管理员登录功能测试:
ubuntu-staff$ ./c
connect success
___________________________
| |
|**********登录界面*********|
|*******1.管理员登录********|
|*******2.普通用户登录******|
|*******3.退出界面**********|
|___________________________|
请输入您的选择(数字):1
请输入您的用户名(工号):1
请输入密码:success
管理员登录成功
___________________________
| |
|******管理员登录界面*******|
|******1.添加用户***********|
|******2.查询用户***********|
|******3.删除用户***********|
|******4.修改用户信息*******|
|******5.查询历史记录*******|
|******6.退出登录***********|
|___________________________|
请输入您的选择(数字):1
请输入员工工号:3
请输入员工权限(管理员权限:1 普通用户权限:0:1
请输入要添加的用户姓名:ppp
请输入用户密码(6位):999999
请输入员工年龄(18-60岁):19
请输入员工电话:0000
请输入员工家庭住址:99
请输入员工职位:09
请输入员工入职年月:90
请输入员工职等(1-10等):9
请输入员工工资:90
3 ppp员工信息添加成功
___________________________
| |
|******管理员登录界面*******|
|******1.添加用户***********|
|******2.查询用户***********|
|******3.删除用户***********|
|******4.修改用户信息*******|
|******5.查询历史记录*******|
|******6.退出登录***********|
|___________________________|
请输入您的选择(数字):2
___________________________
| |
|******管理员登录界面*******|
|******1.根据人名查找*******|
|******2.根据工号查找*******|
|******3.查询所有***********|
|******4.退出查询***********|
|___________________________|
请输入您的选择(数字):1
请输入要查找的员工姓名:ppp
工号 姓名 年龄 电话 地址 职位 入职年月 职等 工资
3 ppp 19 0000 99 09 90 9 90.000000
___________________________
| |
|******管理员登录界面*******|
|******1.根据人名查找*******|
|******2.根据工号查找*******|
|******3.查询所有***********|
|******4.退出查询***********|
|___________________________|
请输入您的选择(数字):2
请输入要查找的员工工号:3
工号 姓名 年龄 电话 地址 职位 入职年月 职等 工资
3 ppp 19 0000 99 09 90 9 90.000000
___________________________
| |
|******管理员登录界面*******|
|******1.根据人名查找*******|
|******2.根据工号查找*******|
|******3.查询所有***********|
|******4.退出查询***********|
|___________________________|
请输入您的选择(数字):3
工号 姓名 年龄 电话 地址 职位 入职年月 职等 工资
1 boss 18 100010 china 老板 1990 18 500.000000
3 ppp 19 0000 99 09 90 9 90.000000
___________________________
| |
|******管理员登录界面*******|
|******1.根据人名查找*******|
|******2.根据工号查找*******|
|******3.查询所有***********|
|******4.退出查询***********|
|___________________________|
请输入您的选择(数字):4
___________________________
| |
|******管理员登录界面*******|
|******1.添加用户***********|
|******2.查询用户***********|
|******3.删除用户***********|
|******4.修改用户信息*******|
|******5.查询历史记录*******|
|******6.退出登录***********|
|___________________________|
请输入您的选择(数字):4
___________________________
| |
|******管理员修改界面*******|
|******1.修改姓名***********|
|******2.修改密码***********|
|******3.修改电话***********|
|******4.修改地址***********|
|******5.修改职位***********|
|******6.修改职等***********|
|******7.修改工资***********|
|******8.修改年龄***********|
|******9.退出修改***********|
|___________________________|
请输入您的选择(数字):1
请输入要修改员工的工号:3
请输入要修改后的姓名:ooo
1员工修改3 员工姓名信息为ooo (null)
___________________________
| |
|******管理员修改界面*******|
|******1.修改姓名***********|
|******2.修改密码***********|
|******3.修改电话***********|
|******4.修改地址***********|
|******5.修改职位***********|
|******6.修改职等***********|
|******7.修改工资***********|
|******8.修改年龄***********|
|******9.退出修改***********|
|___________________________|
请输入您的选择(数字):9
___________________________
| |
|******管理员登录界面*******|
|******1.添加用户***********|
|******2.查询用户***********|
|******3.删除用户***********|
|******4.修改用户信息*******|
|******5.查询历史记录*******|
|******6.退出登录***********|
|___________________________|
请输入您的选择(数字):5
工号 姓名 操作信息
1 boss 1员工登录系统 2022-12-10 11:05:58
1 boss 1管理员查询员工信息
1 boss 1管理员查询员工信息
1 boss 1员工登录系统 2022-12-10 11:06:44
1 boss 1管理员查询员工信息
1 boss 1员工修改1 员工姓名信息为boss 2022-12-10 11:07:25
1 boss 1员工登录系统 2022-12-10 11:08:17
1 boss 1管理员成功添加3 ppp用户 2022-12-10 11:08:53
1 boss 1管理员查询员工信息
1 boss 1管理员查询员工信息
1 boss 1管理员查询员工信息
1 boss 1员工修改3 员工姓名信息为ooo 2022-12-10 11:09:30
___________________________
| |
|******管理员登录界面*******|
|******1.添加用户***********|
|******2.查询用户***********|
|******3.删除用户***********|
|******4.修改用户信息*******|
|******5.查询历史记录*******|
|******6.退出登录***********|
|___________________________|
请输入您的选择(数字):6
ubuntu-staff$ ^C
普通用户登录功能测试
ubuntu-staff$ ./c
connect success
___________________________
| |
|**********登录界面*********|
|*******1.管理员登录********|
|*******2.普通用户登录******|
|*******3.退出界面**********|
|___________________________|
请输入您的选择(数字):2
请输入您的用户名(工号):4
请输入密码:888888
普通用户登录成功
___________________________
| |
|*****普通用户登录界面******|
|******1.查询个人信息*******|
|******2.修改个人信息*******|
|******3.退出登录***********|
|___________________________|
请输入您的选择(数字):1
工号 姓名 年龄 电话 地址 职位 入职年月 职等 工资
4 li 18 8888 888i jl 9709 8 90.000000
___________________________
| |
|*****普通用户登录界面******|
|******1.查询个人信息*******|
|******2.修改个人信息*******|
|******3.退出登录***********|
|___________________________|
请输入您的选择(数字):2
___________________________
| |
|******普通用户修改界面*****|
|******1.修改姓名***********|
|******2.修改密码***********|
|******3.修改电话***********|
|******4.修改地址***********|
|******5.修改年龄***********|
|******6.退出修改***********|
|___________________________|
请输入您的选择(数字):5
请输入要修改后的出生年份:1997
4员工修改4 员工年龄信息为1997 (null)
___________________________
| |
|******普通用户修改界面*****|
|******1.修改姓名***********|
|******2.修改密码***********|
|******3.修改电话***********|
|******4.修改地址***********|
|******5.修改年龄***********|
|******6.退出修改***********|
|___________________________|
请输入您的选择(数字):6
___________________________
| |
|*****普通用户登录界面******|
|******1.查询个人信息*******|
|******2.修改个人信息*******|
|******3.退出登录***********|
|___________________________|
请输入您的选择(数字):1
工号 姓名 年龄 电话 地址 职位 入职年月 职等 工资
4 li 1997 8888 888i jl 9709 8 90.000000
___________________________
| |
|*****普通用户登录界面******|
|******1.查询个人信息*******|
|******2.修改个人信息*******|
|******3.退出登录***********|
|___________________________|
请输入您的选择(数字):3
ubuntu-staff$
附:代码实现见员工管理系统代码实现链接
https://blog.csdn.net/ww1106/article/details/128265598?spm=1001.2014.3001.5502