欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-14 08:26:03
...

时间就是这么的快,不知不觉就到了日报(七),感觉像是到了项目的后半场了,但是我还有一整个模块(文件管理与FTP传输)还没弄,现有模块也还没进行梳理,都是各个模块各自为政,感觉时间不太够用了。

看一下上一次的日报情况,看看团队其他成员是否有同样感慨:

日报

1号 日报6(epoll模型与责任链模式的有机结合)
3号 日报6
4号 日报5
5号 日报6(不定长包)
日报5(线程及线程池)
日报4(Socket连接)
9号 日报4

任务实现

将前后端和中控服务器都安排好了,前置服务器使用的是 ”epoll+责任链“ 的组合,后置服务器还是采用传统模式,“*集权”。具体看图:

前置服务器设计

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

中控服务器设计

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

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

后置服务器设计

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

前置服务器部分代码

前置服务器的代码已经经过初步测试,这里先放出来,还需要待进一步的压力测试。

在日报六里面放过的代码就不再放了,放没放过的:

//EtoC.h
#pragma once

#include "Abstract_Front.h"
#include "Epoll.h"
#include "PacketCommand2.h"

#define SERV_PORT 8888	//中控端口号

class EtoC :
	public Abstract_Front
{
private:
	int connect_fd;
	Epoll* ep;
	PacketBase* packetbase;

public:
	EtoC(Epoll* epp);
	void Start();
	void send_name();
	int run(int ffdd);
};
//EtoC.cpp

#include "EtoC.h"

EtoC::EtoC(Epoll* epp) {
		this->ep = epp;
		
		packetbase = new PacketBase();

		connect_fd = socket(PF_INET, SOCK_STREAM, 0);
		
		set_fd(connect_fd);

		ep->Epoll_add(connect_fd);	
}

void EtoC::Start() {
	struct sockaddr_in servaddr;
	bzero(&servaddr, sizeof(servaddr));	

	servaddr.sin_family = PF_INET;
	inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);	
	servaddr.sin_port = htons(SERV_PORT);

	bind(connect_fd, (struct sockaddr*) & servaddr, sizeof(servaddr));

	connect(connect_fd, (struct sockaddr*) & servaddr, sizeof(servaddr));
}

void EtoC::send_name() {
	PacketCommand2* Pack2 = new PacketCommand2();
	char* name = new char[6];
	strcpy(name,"Front");
	Pack2->Send_name(name);
	send(connect_fd,Pack2->getData(),Pack2->getSize(),0);
}

//´ÓÖпطþÎñÆ÷¶Áµ½Êý¾Ý
int EtoC::run(int ffdd) {
	int n = read(connect_fd, packetbase->getData(), 1024);
	packetbase->setSize(n);
	packetbase->unpack();
	send(packetbase->getHead()->fd, packetbase->getData(), packetbase->getSize(),0);
}

//Recv_Data.h

#pragma once
#include "Abstract_Front.h"
#include "PacketBase.h"
#include "Epoll.h"

//处理从客户端收到的消息

class RecvData :
	public Abstract_Front
{
private:
	PacketBase* packetbase;
	Epoll* ep;
public:
	RecvData(Epoll* ep);
	int run(int ffdd);
};
//Recv_Date.cpp

#include "RecvData.h"

RecvData::RecvData(Epoll* ep) {
	this->ep = ep;
}

//场景类实地操作时先将fd配置为接入中控的
int RecvData::run(int ffdd)
{

	packetbase = new PacketBase();

	int n = read(ffdd, packetbase->getData(), 1024);
	if (n <= 0) {
		ep->Epoll_del(ffdd);
		close(ffdd);
		cout << "A Client Close!" << endl;
	}

	packetbase->setSize(n);	//我看这一步可以并到解包里面去

	packetbase->unpack();

	packetbase->getHead()->fd = ffdd;

	packetbase->pack();

	send(this->get_fd(), packetbase->getData(), packetbase->getSize(),0);
}
//Packet_Command2.h

#pragma once
#include "PacketBase.h"
#include "Packet2.h"

//用于边缘服务器向中控服务器自报家门
class PacketCommand2 :
	public PacketBase
{
public:
	bool Send_name(char* name);
};
//Packet2.h

#pragma once

#include<stdio.h>

typedef struct edge {
	char name[6];	//连入服务器名称
}Edge_t;
//Packet_Command2.cpp
#include "PacketCommand2.h"

bool PacketCommand2::Send_name(char* name) {
    int sz = sizeof(Edge_t);
    this->setBodySize(sz);
    this->Body = new char[sz];

    Head.funcId = 0x30;
    Head.optid = 0x01;
    Head.usrlenth = sz;
    Head.syn = 0x04;

    Edge_t* body = (Edge_t*)Body;
    strcpy(body->name, name);

    Tail.pack_tail = 0x05;

    return this->pack();
}
//场景类

//前置服务器场景类

#include"Abstract_Front.h"
#include"Epoll.h"
#include"EtoC.h"
#include"RecvData.h"
#include"Socket.h"

int main()
{
	Epoll* ep = new Epoll;

	EtoC* ec = new EtoC(ep);
	ec->Start();	//连向中控服务器
	ec->send_name();//自保家门
	
	Socket* sc = new Socket(ep);

	RecvData* rc = new RecvData(ep);
	rc->set_fd(ec->get_fd());	//将fd与连入中控的fd进行挂载

	//组链:面向客户端连接、面向中控连接、面向客户端数据处理
	ep->setFrontHead(sc);
	sc->setNextHandle(ec);
	ec->setNextHandle(rc);
	
	while (1) {
		int nevent = ep->Epoll_Wait();
		ep->Epoll_run(nevent);
	}
}

从这个Packet_Command2和Packet2的添加,就可以看出设计模式的优势。有兴趣可以去看我的设计模式专栏。
这里就不放链接了,文章挺多,自取。

中控服务器部分代码

中控服务器中有些地方采用默认的形式,如果后续要拓展,可以在默认的地方改为动态,不碍事,比较懒就没弄成动态。

部分代码和前置相同,就不再放

//Socket.h

#pragma once
#include "Abstract_Front.h"
#include "Epoll.h"
class Socket :
	public Abstract_Front
{
public:
	Socket(Epoll* epp);	
	int run(int ffdd);	
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

    set_fd(listen_fd);
    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(8888);//绑定端口号

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

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

int Socket::run(int ffdd) {
    struct sockaddr_in cliaddr;
    socklen_t clilen = sizeof(cliaddr);
    int connfd = accept(listen_fd, (struct sockaddr*) & cliaddr, &clilen);

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

#pragma once
#include "Abstract_Front.h"
#include "PacketBase.h"
#include "Epoll.h"

//处理从客户端收到的消息


class RecvData :
	public Abstract_Front
{
private:
	PacketBase* packetbase;
	Epoll* ep;
public:
	RecvData(Epoll* ep);
	int run(int ffdd);
};
//RecvDate.cpp

#include "RecvData.h"

RecvData::RecvData(Epoll* ep) {
	this->ep = ep;
	this->set_fd(-1);
}

//场景类实地操作时先将fd配置为接入中控的
int RecvData::run(int ffdd)
{
	packetbase = new PacketBase();
	
	int n = read(ffdd, packetbase->getData(), 1024);
	if (n <= 0) {
		ep->Epoll_del(ffdd);
		close(ffdd);
		cout << "A Client Close!" << endl;
	}

	packetbase->setSize(n);	//我看这一步可以并到解包里面去

	packetbase->unpack();

	if (packetbase->getHead()->funcId == 0x30) {	//收到登记包
		
		string temp = packetbase->getBody();
		fds[temp] = ffdd;
	}
	else if(packetbase->getHead()->funcId == 0x31){	//如果是中转包(这里默认中转给DB服务器或Front服务器)
		int to_fd = fds["DB"];	//形式还是要走一下的,通过容器表来定位fd
		send(to_fd, packetbase->getData(), packetbase->getSize(),0);
	}
	else if (packetbase->getHead()->funcId == 0x32) {
		int to_fd = fds["FTP"];	//形式还是要走一下的,通过容器表来定位fd
		send(to_fd, packetbase->getData(), packetbase->getSize(),0);
	}
	else {
		cout << "无人认领包" << endl;
	}
}
//场景类
#include"Epoll.h"
#include"Socket.h"
#include"RecvData.h"

int main() {
	Epoll* ep = new Epoll();
	Socket* sc = new Socket(ep);
	RecvData* rc = new RecvData(ep);

	ep->setFrontHead(sc);
	sc->setNextHandle(rc);

	while (1) {
		int nevent = ep->Epoll_Wait();
		ep->Epoll_run(nevent);
	}
}

后置服务器前奏

后置服务器用了很多动态库,不然代码量会有点大,所以还没测好。

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