FTP文件管理项目(本地云)项目日报(六)

时间:2022-07-23
本文章向大家介绍FTP文件管理项目(本地云)项目日报(六),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

日报情况

今晚的会二组长去毕业典礼了,所以显得有点冷清啊。 还是先来盘点一下各位的日报。(第五工作日)

1号

https://blog.csdn.net/qq_43762191/article/details/106893729

https://blog.csdn.net/qq_43762191/article/details/106915706

3号

https://blog.csdn.net/blackcamouflage/article/details/106935067

4号

https://blog.csdn.net/luyaozhima/article/details/106934513

8号

https://blog.csdn.net/qq_42151344/article/details/106934421

哎,心塞。。。

我的进度

算了算了,说我的进度吧。

画了张进程间TCP通信的简单类图:

测试并修订了解压包模块,已经纪录在上面的第二篇日报中,收获还是蛮大的。

重点是对epoll模块的改装。

可以先看一下旧的epoll:

旧的epoll类图:

可以看出来这个epoll是非常之任务繁忙的,线程池也要,TCP通信也要,进程间通信也要,解压包也要,我以前写的那个项目,还要个日志类对象,真是,能者多劳啊。

但是,这样就很难拓展了,如果我要安插一个新的文件描述符,它代表一个全新的模块,那要改多少?来个对象,初始化对象,配置对象,然后再配置epoll属性,然后插入epoll监控表,麻烦,还容易出错。

于是我就苦思冥想,终于让我想到了:责任链模式。学以致用C++设计模式之“责任链模式” 将请求与实现分开!!!

于是类图就成这样了:

现在epoll就可以专心干自己的事情了。

于是代码实现就是这样:(为了更直观,我还写了客户端连接处理类) (未测试)

//AbstractFront.h

#pragma once
class Abstract_Front
{
private:
	Abstract_Front* nexthandle;
	int fd;

public:
	void setNextHandle(Abstract_Front* h);
	void HandleCommand(int fdd);
	int get_fd();
	void set_fd();	//×îºóÒ»Õ¾µÄfdÉèΪ-1£¬×îºóһվΪһ¶Ñ¿Í»§¶Ë
	virtual int run() = 0;
};
//AbstractFront.cpp

#include "Abstract_Front.h"
#include<stdio.h>

void Abstract_Front::setNextHandle(Abstract_Front* h) {
	this->nexthandle = h;
}

int Abstract_Front::get_fd() {
	return this->fd;
}

void Abstract_Front::HandleCommand(int fdd) {
	if (fdd == this->fd || this->nexthandle == NULL)	//Èç¹ûfd¶ÔÉÏÁË»òÕßÊÇ¿Í»§¶ËµÄ
		this->run();
	else
		this->nexthandle->HandleCommand(fdd);
}
//epoll.h

#pragma once
#include "Abstract_Front.h"

#include <errno.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include<iostream>

using namespace std;

class Epoll
{
private:
	Abstract_Front* Head;
	struct epoll_event* retEvents;
	int	maxEvent;
	int	timeout;
	int		epfd;
	struct  epoll_event event;

public:
	Epoll(unsigned int maxEvent = 100, int timeout = -1);
	~Epoll();
	void Epoll_add(int fd);
	void Epoll_del(int fd);
	void Epoll_run(int nevent);
	int Epoll_Wait();

	void setFrontHead(Abstract_Front* h);
};
//epoll.cpp

#include "Epoll.h"

Epoll::Epoll(unsigned int maxEvent = 100, int timeout = -1) {
    this->maxEvent = maxEvent;
    this->timeout = timeout;
    this->retEvents = new struct epoll_event[maxEvent];

    this->epfd = epoll_create(this->maxEvent);
    if (this->epfd < 0)
    {
        perror("Epoll Create Error!");
        return;
    }
}

Epoll::~Epoll() {
    if (epfd != -1)
    {
        close(this->epfd);
        epfd = -1;
    }
    if (NULL != this->retEvents)
    {
        delete[]this->retEvents;
        this->retEvents = NULL;
    }
}

void Epoll::Epoll_add(int fd) {
    this->event.events = EPOLLIN | EPOLLET;
    this->event.data.fd = fd;
    int ret = epoll_ctl(this->epfd, EPOLL_CTL_ADD, fd, &this->event);
    if (ret < 0)
    {
        perror("Epoll Add Event Error!");
    }
}

void Epoll::Epoll_del(int fd) {
    this->event.events = EPOLLIN | EPOLLET;
    this->event.data.fd = fd;
    int ret = epoll_ctl(this->epfd, EPOLL_CTL_DEL, fd, &this->event);
    if (ret < 0)
    {
        perror("Epoll Delete Event Error!");
    }
}

int Epoll::Epoll_Wait() {
    int nevent = epoll_wait(this->epfd, this->retEvents, this->maxEvent, -1);
    if (nevent < 0)
    {
        perror("epoll wait error!");
    }
    return nevent;
}

void Epoll::setFrontHead(Abstract_Front* h) {
    this->Head = h;
}

void Epoll::Epoll_run(int nevent) {
    //¿ªÊ¼ÔðÈÎÁ´
    for (int i = 0; i < nevent; i++)
    {
        if(this->Head)
        if (!(retEvents + i)->events & EPOLLIN)
            continue;

        Head->HandleCommand((retEvents + i)->data.fd);
        
    }
}
//Socket.h

#pragma once
#include "Abstract_Front.h"
#include "Epoll.h"
class Socket :
	public Abstract_Front
{
public:
	Socket(Epoll* epp);	//Ö±½ÓÅäÖÃÍê»·¾³£¬»ñÈ¡³ölistened£¬È»ºó¼ÓÈëµ½epfd¾ä±úµÄÄÇÕűíÖĞ
	int run();	//ÕâÀïÓÃÀ´acceptÒ»ÏÂ
private:
	Epoll* ep;
	int listen_fd;
};
//Socket.cpp

#include "Socket.h"

Socket::Socket(Epoll* epp) {
    this->ep = epp;

    struct sockaddr_in  servaddr;//客户端地址及服务器地址
    listen_fd = socket(AF_INET, SOCK_STREAM, 0);//1.创建文件描述符(用于监听)
    //成功返回文件描述符,失败返回-1,并设置errno

    ep->Epoll_add(listen_fd);   //凡是在外面使用ep的,都要上锁,这里等着被锁吧

    bzero(&servaddr, sizeof(servaddr));//清零客户端地址结构体
    servaddr.sin_family = AF_INET;//IPv4类型地址
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//主机本地任意IP地址
    servaddr.sin_port = htons(8000);//绑定端口号

    bind(listen_fd, (struct sockaddr*) & servaddr, sizeof(servaddr));//将监听文件描述与IP地址绑定

    listen(listen_fd, 20);//监听广播(查看是否有客户端发出连接请求)
}

int Socket::run() {

    struct sockaddr_in cliaddr;
    socklen_t clilen = sizeof(cliaddr);
    int connfd = accept(listen_fd, (struct sockaddr*) & cliaddr, &clilen);

    ep->Epoll_add(connfd);  //同样,锁上
}