项目——员工管理系统

开发环境: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,失败返回-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,失败返回错误码

 客户端流程及涉及知识简介:

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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值