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);  //同樣,鎖上
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章