日報情況
今晚的會二組長去畢業典禮了,所以顯得有點冷清啊。
還是先來盤點一下各位的日報。(第五工作日)
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); //同樣,鎖上
}