由于libevent的多线程限制,以及性能方面原因。 本人重新从底层写了一套网络引擎。 性能超10万以上。 先上图 : 有图有真相:
测试环境:
服务器:
虚拟机: centos 7.2,
虚拟机: cpu, 4核
内存: 8G
客户端:
操作系统: win10
测试工具 : vcClient客户端
每个 客户端开启 10000的模拟终端, 不间断发送应答请求, 未收到应答, 报错。
本次测试, 分为 网关 gateway 和 游戏服务器 gameserver。
gateway 承载 5万在线,数据转发给gameserver, 由gameserver处理后,再经过gateway发送给 每个终端链接。
数据流: user-> gateway -> gameserver(处理及应答) -> gateway -> user 闭环。
描述: 上图,客户机 开启 5万模拟终端, 虚拟机中 gateway 占用cpu: 31.6. 内存 1.5G * 10%
由于单台客户端 ,能开启的客户端有限, 未能进一步测试 10万级数据。
但 5万用户的测试,足以说明, 在数据接收,应答等, 足够 承载10万以上 数据!!!
由于代码量比较大, 只能打包下载了。
上传部分代码:
#include "DataManager.h"
#include <stdio.h>
#include "NodeManager.h"
#include "CircularQueue.cpp"
//中间层数据格式定义: head[14] ####(4),midNum(1),type(1),seq(2),len(2),fd(4)
//中间层 是由 gateway进行封装。
//midNum:表示 经过几层 中转。
//type :表示 数据包类型,0 中转包 1 请求,2 应答,3 通知(无应答), 4 ACK, 5 SNIFF。(逻辑层的)
//seq: 表示 数据包流水号,
//ACK: 网络层应答包, 仅仅指 底层确保 数据被收到。
//SNIFF: 网络测试包(心跳), 服务器 ACK应答.
//session: 由登陆服务器生成, 保存到 游戏服务器的redis中。
#include <stdio.h>
#include "NodeManager.h"
#include "CircularQueue.cpp"
//中间层数据格式定义: head[14] ####(4),midNum(1),type(1),seq(2),len(2),fd(4)
//中间层 是由 gateway进行封装。
//midNum:表示 经过几层 中转。
//type :表示 数据包类型,0 中转包 1 请求,2 应答,3 通知(无应答), 4 ACK, 5 SNIFF。(逻辑层的)
//seq: 表示 数据包流水号,
//ACK: 网络层应答包, 仅仅指 底层确保 数据被收到。
//SNIFF: 网络测试包(心跳), 服务器 ACK应答.
//session: 由登陆服务器生成, 保存到 游戏服务器的redis中。
#define GATEWAY
extern CNodeManager* g_pNodeManager;
DataManager::DataManager()
{
{
}
void DataManager::Init()
{
for (int i = 0; i < 10; i++)
{
thData[i].threadID = -1;
thData[i].m_objClientQueue = new CircularQueue<user_data*>(200000);
}
}
{
for (int i = 0; i < 10; i++)
{
thData[i].threadID = -1;
thData[i].m_objClientQueue = new CircularQueue<user_data*>(200000);
}
}
DataManager::~DataManager()
{
for (int i = 0; i < 10; i++)
{
while (thData[i].m_objClientQueue->length() > 0)
{
user_data* pdata = NULL;
thData[i].m_objClientQueue->PopQueue(pdata);
delete pdata;
}
delete thData[i].m_objClientQueue;
{
for (int i = 0; i < 10; i++)
{
while (thData[i].m_objClientQueue->length() > 0)
{
user_data* pdata = NULL;
thData[i].m_objClientQueue->PopQueue(pdata);
delete pdata;
}
delete thData[i].m_objClientQueue;
}
}
}
int DataManager::PushRecvData(int threadID, int fd, char* buff, int len, bool isClient)
{
if (isClient)
{
user_data* pdata = new user_data();
memcpy(pdata->line, buff, len);
pdata->fd = fd;
pdata->iType = 1;
pdata->n_size = len;
{
if (isClient)
{
user_data* pdata = new user_data();
memcpy(pdata->line, buff, len);
pdata->fd = fd;
pdata->iType = 1;
pdata->n_size = len;
thData[threadID].m_objClientQueue->PushQueue(pdata);
printf("recv client: head: ++ \n");
}
else
{
user_data* pdata = new user_data();
memcpy(pdata->line, buff, len);
pdata->fd = fd;
pdata->n_size = len;
pdata->iType = 2;
thData[threadID].m_objClientQueue->PushQueue(pdata);
printf("recv Server: head: ++ \n");
}
printf("recv client: head: ++ \n");
}
else
{
user_data* pdata = new user_data();
memcpy(pdata->line, buff, len);
pdata->fd = fd;
pdata->n_size = len;
pdata->iType = 2;
thData[threadID].m_objClientQueue->PushQueue(pdata);
printf("recv Server: head: ++ \n");
}
return 0;
}
}
int DataManager::InitThreadData(int threadID)
{
thData[threadID].threadID = threadID;
return 0;
}
{
thData[threadID].threadID = threadID;
return 0;
}
int DataManager::CreatePage(char* buff, char midNum, char iType, short seq, short lenth, int fd)
{
sprintf(buff, "####");
buff[4] = midNum;
buff[5] = iType;
memcpy(&(buff[6]), &seq, 2);
memcpy(&(buff[8]), &lenth, 2);
memcpy(&(buff[10]), &fd, 4);
return 0;
}
{
sprintf(buff, "####");
buff[4] = midNum;
buff[5] = iType;
memcpy(&(buff[6]), &seq, 2);
memcpy(&(buff[8]), &lenth, 2);
memcpy(&(buff[10]), &fd, 4);
return 0;
}
int DataManager::ProcDataPage()
{
for (int i = 0; i < 10; i++)
{
if(thData[i].threadID > -1)
{
char head[14] = { 0 };
sprintf(head, "####");
char midNum = 1;//
char iType = 0;//中转
static short seq = 0;
seq++;
short len = 0;
int cliFD = 0;
//------------------------------
user_data* pdata = NULL;
//user_data* pMidData = new user_data();
//pMidData->pData = new char[2048];
{
for (int i = 0; i < 10; i++)
{
if(thData[i].threadID > -1)
{
char head[14] = { 0 };
sprintf(head, "####");
char midNum = 1;//
char iType = 0;//中转
static short seq = 0;
seq++;
short len = 0;
int cliFD = 0;
//------------------------------
user_data* pdata = NULL;
//user_data* pMidData = new user_data();
//pMidData->pData = new char[2048];
thData[i].m_objClientQueue->PopQueue(pdata);
while (pdata != NULL)
{
//printf("DataManager::ProcDataPage: fd: %d pdata: %d iType: %d \n", pdata->fd, pdata, pdata->iType);
g_pNodeManager->PushRecvData(pdata->fd, pdata);/
//printf("DataManager::ProcDataPage: fd: %d pdata: %d iType: %d \n", pdata->fd, pdata, pdata->iType);
pdata = NULL;
thData[i].m_objClientQueue->PopQueue(pdata);
}
}
}
g_pNodeManager->ProcRecvData();
g_pNodeManager->Senddata();
return 0;
}
int DataManager::PushRequstData(int fd, char* buff, int len)
{
while (pdata != NULL)
{
//printf("DataManager::ProcDataPage: fd: %d pdata: %d iType: %d \n", pdata->fd, pdata, pdata->iType);
g_pNodeManager->PushRecvData(pdata->fd, pdata);/
//printf("DataManager::ProcDataPage: fd: %d pdata: %d iType: %d \n", pdata->fd, pdata, pdata->iType);
pdata = NULL;
thData[i].m_objClientQueue->PopQueue(pdata);
}
}
}
g_pNodeManager->ProcRecvData();
g_pNodeManager->Senddata();
return 0;
}
int DataManager::PushRequstData(int fd, char* buff, int len)
{
return 0;
}
int DataManager::PushAnswerData(int fd, char* buff, int len)
{
}
int DataManager::PushAnswerData(int fd, char* buff, int len)
{
return 0;
}
int DataManager::PushMidTranData(int fd, char* buff, int len)
{
}
int DataManager::PushMidTranData(int fd, char* buff, int len)
{
return 0;
}
}