时间就是这么的快,不知不觉就到了日报(七),感觉像是到了项目的后半场了,但是我还有一整个模块(文件管理与FTP传输)还没弄,现有模块也还没进行梳理,都是各个模块各自为政,感觉时间不太够用了。
看一下上一次的日报情况,看看团队其他成员是否有同样感慨:
日报
1号 | 日报6(epoll模型与责任链模式的有机结合) |
---|---|
3号 | 日报6 |
4号 | 日报5 |
5号 | 日报6(不定长包) |
日报5(线程及线程池) | |
日报4(Socket连接) | |
9号 | 日报4 |
任务实现
将前后端和中控服务器都安排好了,前置服务器使用的是 ”epoll+责任链“ 的组合,后置服务器还是采用传统模式,“中央集权”。具体看图:
前置服务器设计
中控服务器设计
后置服务器设计
前置服务器部分代码
前置服务器的代码已经经过初步测试,这里先放出来,还需要待进一步的压力测试。
在日报六里面放过的代码就不再放了,放没放过的:
//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);
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
//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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
//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);
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
//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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
//Packet_Command2.h
#pragma once
#include "PacketBase.h"
#include "Packet2.h"
//用于边缘服务器向中控服务器自报家门
class PacketCommand2 :
public PacketBase
{
public:
bool Send_name(char* name);
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
//Packet2.h
#pragma once
#include<stdio.h>
typedef struct edge {
char name[6]; //连入服务器名称
}Edge_t;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
//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();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
//场景类
//前置服务器场景类
#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);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
从这个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;
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
//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); //同样,锁上
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
//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);
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
//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;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
//场景类
#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);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
后置服务器前奏
后置服务器用了很多动态库,不然代码量会有点大,所以还没测好。
文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。
原文链接:lion-wu.blog.csdn.net/article/details/106957541