This commit is contained in:
aixianling
2025-01-09 17:45:40 +08:00
commit 5c9f1dae4a
3482 changed files with 1146531 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++14",
"intelliSenseMode": "clang-x64",
"compileCommands": "${workspaceFolder}/build/compile_commands.json"
}
],
"version": 4
}

View File

@@ -0,0 +1,63 @@
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) 启动",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/../../build/SessionServer/sessionserver_d",
"args": ["${workspaceFolder}/../../build/SessionServer/SessionServerLinux.txt"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"showDisplayString": true,
"additionalSOLibSearchPath": "${workspaceFolder}/../common/libs;${workspaceFolder}/../srvlib/libs;${workspaceFolder}/../../common/cpp/libs/3rd/bin;"
},
{
"name": "(gdb) 附加",
"type": "cppdbg",
"request": "attach",
"program": "${workspaceFolder}/../../build/SessionServer/sessionserver_d",
"processId": "${command:pickProcess}",
"MIMode": "gdb",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"showDisplayString": true,
"additionalSOLibSearchPath": "${workspaceFolder}/../common/libs;${workspaceFolder}/../srvlib/libs;${workspaceFolder}/../../common/cpp/libs/3rd/bin;"
},
{
"name": "(gdb) 附加TWJ",
"type": "cppdbg",
"request": "attach",
"program": "${workspaceFolder}/../../../TangWangJin/SessionServer/sessionserver_d",
"processId": "${command:pickProcess}",
"MIMode": "gdb",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"showDisplayString": true,
"additionalSOLibSearchPath": "${workspaceFolder}/../common/libs;${workspaceFolder}/../srvlib/libs;${workspaceFolder}/../../common/cpp/libs/3rd/bin;"
}
]
}

View File

@@ -0,0 +1,165 @@
{
"C_Cpp.default.cppStandard": "c++11",
"C_Cpp.default.cStandard": "c11",
"C_Cpp.default.intelliSenseMode": "gcc-x64",
"C_Cpp.intelliSenseEngineFallback": "Enabled",
"C_Cpp.intelliSenseEngine": "Tag Parser",
"C_Cpp.default.includePath": [
"${default}",
"${workspaceFolder}/include/**"
],
"cmake.buildDirectory": "${workspaceFolder}/../build",
"cmake.configureOnOpen": true,
// 启用跟踪日志到文件和控制台(非常嘈杂)。
"cmake.enableTraceLogging": true,
"workbench.list.horizontalScrolling": true,
"workbench.tree.indent": 10,
"workbench.editor.tabSizing": "shrink",
"workbench.settings.openDefaultSettings": true,
"workbench.settings.openDefaultKeybindings": true,
"workbench.sideBar.location": "right",
"terminal.integrated.cursorBlinking": true,
"terminal.integrated.confirmOnExit": true,
"editor.renderWhitespace": "none",
"editor.renderControlCharacters": false,
// 启用后,扩展将本地下载并安装在远程上。
"remote.downloadExtensionsLocally": true,
// 始终显示SSH登录终端。
"remote.SSH.showLoginTerminal": true,
// 默认行尾字符。
// - \n: LF
// - \r\n: CRLF
// - auto: 使用具体操作系统规定的行末字符。
"files.eol": "auto",
// 配置排除的文件和文件夹的 glob 模式。
// 例如,文件资源管理器将根据此设置决定要显示或隐藏的文件和文件夹。
"files.exclude": {
"bin": true,
"build": true,
"lib": true,
"cmake": true,
"test/bin": true,
"test/lib": true,
"**/.vscode": false
},
// 配置文件路径的 glob 模式以从文件监视排除。
// 模式必须在绝对路径上匹配(例如 ** 前缀或完整路径需正确匹配)。
// 更改此设置需要重启。如果在启动时遇到 Code 消耗大量 CPU 时间,则可以排除大型文件夹以减少初始加载。
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/*/**": true,
"**/.vscode": true,
"bin": true,
"build": true,
"cmake": true,
"test/bin": true,
"test/lib": true
},
// 控制已更新文件的自动保存。可在[此处](https://code.visualstudio.com/docs/editor/codebasics#_save-auto-save)阅读有关自动保存的详细信息。
// - off: 永不自动保存更新后的文件。
// - afterDelay: 当文件修改后的时间超过 `files.autoSaveDelay` 中配置的值时自动进行保存。
// - onFocusChange: 编辑器失去焦点时自动保存更新后的文件。
// - onWindowChange: 窗口失去焦点时自动保存更新后的文件。
"files.autoSave": "off",
// 启用后,保存文件时在文件末尾插入一个最终新行。
"files.insertFinalNewline": true,
// 实验性:启用后,允许在编辑器中打开工作区搜索结果。
"search.enableSearchEditorPreview": true,
// 控制调试工具栏的位置。可在所有视图中“浮动”、在调试视图中“停靠”,也可“隐藏”。
//"search.location": "panel",
// 控制是否显示搜索结果所在的行号。
"search.showLineNumbers": true,
// 控制在搜索文件时是否使用 `.gitignore` 和 `.ignore` 文件。
"search.useIgnoreFiles": true,
// 控制在搜索文件时是否使用全局 `.gitignore` 和 `.ignore` 文件。
"search.useGlobalIgnoreFiles": true,
// 配置在搜索中排除的文件和文件夹的 glob 模式。已经继承 `files.exclude` 设置的所有 glob 模式。可在[此处](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options)阅读有关 glob 模式的详细信息。
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/*.code-search": true
},
"files.associations": {
"ctime": "cpp",
"ratio": "cpp",
"chrono": "cpp",
"system_error": "cpp",
"type_traits": "cpp",
"bitset": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"functional": "cpp",
"optional": "cpp",
"tuple": "cpp",
"array": "cpp",
"string_view": "cpp",
"utility": "cpp",
"future": "cpp",
"typeinfo": "cpp",
"atomic": "cpp",
"hash_map": "cpp",
"hash_set": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"condition_variable": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"random": "cpp",
"regex": "cpp",
"set": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp"
},
}

View File

@@ -0,0 +1,615 @@
#include <stdio.h>
#ifdef WIN32
#include <tchar.h>
#include <WinSock2.h>
#include <windows.h>
#endif
#include <_ast.h>
#include <_memchk.h>
#include <Thread.h>
#include <Lock.h>
#include <Tick.h>
#include <QueueList.h>
#include <Stream.h>
#include <RefString.hpp>
#include <CustomSocket.h>
#include "ShareUtil.h"
#include "BufferAllocator.h"
#include "DataPacketReader.hpp"
#include "DataPacket.hpp"
#include "AppItnMsg.h"
#include "SendPackPool.h"
#include "CustomWorkSocket.h"
#include "CustomClientSocket.h"
#include "CommonDef.h"
#include "ServerDef.h"
#include "EDCode.h"
#include "AMProcto.h"
#include "AMClient_tx.h"
using namespace AMProcto;
using namespace jxSrvDef;
/*
CAMClient::CAMClient()
: Inherited()
{
SetClientName(_T("AMC"));
m_sProductName[0] = 0;
m_sProviderId[0] = 0;
m_OPResultList.setLock(&m_OPResultLock);
}
CAMClient::~CAMClient()
{
}
LPCSTR CAMClient::GetProductName()
{
return m_sProductName;
}
VOID CAMClient::SetProductName(LPCSTR sProductName)
{
_asncpytA(m_sProductName, sProductName);
}
LPCSTR CAMClient::GetSPID()
{
return m_sProviderId;
}
VOID CAMClient::SetSPID(LPCSTR sSPID)
{
_asncpytA(m_sProviderId, sSPID);
}
VOID CAMClient::ProcessRecvBuffers(PDATABUFFER pDataBuffer)
{
char *pBuffer, *pStart, *pEnd;
size_t nProcessLen = 0;
if ( pDataBuffer->nOffset > 0 )
{
pBuffer = pDataBuffer->pPointer;
while ( TRUE )
{
//搜索包头
if ( pBuffer[0] != '#' )
pStart = strchr(pBuffer, '#');
else pStart = pBuffer;
if ( !pStart )
break;
//搜索包尾
pEnd = strchr(pStart, '!');
if ( !pEnd )
break;
pBuffer = pEnd + 1;
pStart++;
pEnd[0] = 0;
Assert( *pBuffer || (int)(pBuffer - pDataBuffer->pBuffer) == pDataBuffer->nOffset );
//处理数据包
CDataPacketReader packet(pStart, pEnd - pStart);
ProcessRecvPacket(packet);
}
nProcessLen = pBuffer - pDataBuffer->pPointer;
pDataBuffer->pPointer = pBuffer;
}
SwapRecvProcessBuffers();
}
VOID CAMClient::SendKeepAlive()
{
static const int ReserveSize = 512;
AMMSG msg;
msg.nCmd = AMProcto::AMC_KEEP_ALIVE;
msg.nServerId = 0;
msg.nUserId = msg.nResult = 0;
msg.lOPPtr = 0;
CDataPacket &pack = allocSendPacket();
pack.reserve(ReserveSize);
pack.adjustOffset(EncodeBuffer(&msg, pack.getOffsetPtr(), (DWORD)sizeof(msg), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
flushSendPacket(pack);
}
VOID CAMClient::SendRegisteClient()
{
static const int ReserveSize = 512;
AMMSG msg;
msg.nCmd = AMProcto::AMC_REGIST_CLIENT;
msg.nServerId = 0;
msg.nUserId = msg.nResult = 0;
msg.lOPPtr = 0;
CDataPacket &pack = allocSendPacket();
pack.reserve(ReserveSize);
pack.adjustOffset(EncodeBuffer(&msg, pack.getOffsetPtr(), (DWORD)sizeof(msg), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
pack.adjustOffset(EncodeBuffer(m_sProductName, pack.getOffsetPtr(), (DWORD)strlen(m_sProductName), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
pack << (char)'/';
pack.adjustOffset(EncodeBuffer(m_sProviderId, pack.getOffsetPtr(), (DWORD)strlen(m_sProviderId), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
flushSendPacket(pack);
}
VOID CAMClient::ProcessRecvPacket(CDataPacketReader &packet)
{
if (packet.getLength() < 32)
{
TRACE(_T("[AMC]无效的数据包长度%d\n"), packet.getLength());
return;
}
AMMSG msg;
AMOPData opData;
DecodeBuffer(packet.getOffsetPtr(), &msg, (DWORD)packet.getAvaliableLength(), (DWORD)sizeof(msg));
packet.adjustOffset(32);
switch(msg.nCmd)
{
case AMProcto::AMS_REGIST_CLIENT:
OutputMsg(rmTip, _T("[AMC]regist client success!"));
break;
case AMProcto::AMS_KEEP_ALIVE:
break;
case AMProcto::AMS_QUERY_AMOUNT:
{
opData.opType = amQueryAmount;
opData.nUserId = msg.nUserId;
opData.nServerId = msg.nServerId;
opData.nResult = msg.nResult;
opData.lOPPtr = msg.lOPPtr;
m_OPResultList.append(opData);
}
break;
case AMProcto::AMS_COMSUME:
{
opData.opType = amConsume;
opData.nUserId = msg.nUserId;
opData.nServerId = msg.nServerId;
opData.nResult = msg.nResult;
opData.lOPPtr = msg.lOPPtr;
m_OPResultList.append(opData);
}
break;
case AMProcto::AMS_INVALID_CMD:
OutputMsg(rmWaning, _T("[AMC]server does not implement CMD %d"), msg.nResult);
break;
default:
OutputMsg(rmWaning, _T("[AMC]client does not implement CMD %d"), msg.nCmd);
break;
}
}
CDataPacket& CAMClient::allocSendPacket()
{
CDataPacket &pack = Inherited::allocSendPacket();
pack << (char)'#';
return pack;
}
VOID CAMClient::flushSendPacket(CDataPacket& packet)
{
packet << (char)'!';
Inherited::flushSendPacket(packet);
}
INT_PTR CAMClient::GetAMOPResults(wylib::container::CBaseList<AMOPDATA> &list)
{
m_OPResultList.flush();
INT_PTR nCount = m_OPResultList.count();
if (nCount > 0)
{
list.addList(m_OPResultList);
m_OPResultList.trunc(0);
}
return nCount;
}
VOID CAMClient::PostQueryAmount(unsigned int nUserId, INT_PTR nServerId, INT64 lOPPtr)
{
static const int ReserveSize = 512;
AMMSG msg;
msg.nCmd = AMProcto::AMC_QUERY_AMOUNT;
msg.nServerId = (INT)nServerId;
msg.nUserId = (INT)nUserId;
msg.nResult = 0;
msg.lOPPtr = lOPPtr;
CDataPacket &pack = allocSendPacket();
pack.reserve(ReserveSize);
pack.adjustOffset(EncodeBuffer(&msg, pack.getOffsetPtr(), (DWORD)sizeof(msg), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
flushSendPacket(pack);
}
VOID CAMClient::PostConsume(unsigned int nUserId, INT_PTR nServerId, INT_PTR nAmount, LPCSTR sCharName, INT64 lOPPtr)
{
static const int ReserveSize = 512;
AMMSG msg;
msg.nCmd = AMProcto::AMC_COMSUME;
msg.nServerId = (INT)nServerId;
msg.nUserId = (INT)nUserId;
msg.nResult = (INT)nAmount;
msg.lOPPtr = lOPPtr;
CDataPacket &pack = allocSendPacket();
pack.reserve(ReserveSize);
pack.adjustOffset(EncodeBuffer(&msg, pack.getOffsetPtr(), (DWORD)sizeof(msg), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
if (sCharName)
{
pack.adjustOffset(
EncodeBuffer(sCharName, pack.getOffsetPtr(), (DWORD)strlen(sCharName), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr() ))
);
}
flushSendPacket(pack);
}
*/
CAMClient::CAMClient()
: Inherited()
{
SetClientName(_T("AMC"));
m_sProductName[0] = 0;
m_sProviderId[0] = 0;
m_OPResultList.setLock(&m_OPResultLock);
m_OPRTaskList.setLock(&m_OPTaskLock);
}
CAMClient::~CAMClient()
{
}
LPCSTR CAMClient::GetProductName()
{
return m_sProductName;
}
VOID CAMClient::SetProductName(LPCSTR sProductName)
{
_asncpytA(m_sProductName, sProductName);
}
LPCSTR CAMClient::GetSPID()
{
return m_sProviderId;
}
VOID CAMClient::SetSPID(LPCSTR sSPID)
{
_asncpytA(m_sProviderId, sSPID);
}
INT_PTR CAMClient::GetAMOPResults(wylib::container::CBaseList<AMOPDATA> &list)
{
m_OPResultList.flush();
INT_PTR nCount = m_OPResultList.count();
if (nCount > 0)
{
list.addList(m_OPResultList);
m_OPResultList.trunc(0);
}
return nCount;
}
INT_PTR CAMClient::GetTaskOPResults(wylib::container::CBaseList<TASKMSG> &list)
{
m_OPRTaskList.flush();
INT_PTR nCount = m_OPRTaskList.count();
if (nCount > 0)
{
list.addList(m_OPRTaskList);
m_OPRTaskList.trunc(0);
}
return nCount;
}
VOID CAMClient::PostQueryAmount(unsigned int nUserId, INT_PTR nServerId, INT64 lOPPtr)
{
static const int ReserveSize = 256;
AMMSG msg;
msg.nServerId = (INT)nServerId;
msg.nUserId = (INT)nUserId;
msg.nResult = 0;
msg.lOPPtr = lOPPtr;
CDataPacket &pack = allocProtoPacket(AMProcto::AMC_QUERY_AMOUNT);
pack.reserve(ReserveSize);
pack.adjustOffset(EncodeBuffer(&msg, pack.getOffsetPtr(), (DWORD)sizeof(msg), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
flushProtoPacket(pack);
}
VOID CAMClient::PostAmTaskData(tagTASKMsg &data)
{
static const int ReserveSize = 256;
CDataPacket &pack = allocProtoPacket(AMProcto::AMC_TASK_SITUATION);
pack.reserve(ReserveSize);
pack.adjustOffset(EncodeBuffer(&data, pack.getOffsetPtr(), (DWORD)sizeof(data), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
flushProtoPacket(pack);
}
VOID CAMClient::PostConsume(unsigned int nUserId, INT_PTR nServerId, INT_PTR nAmount, LPCSTR sCharName, INT64 lOPPtr, BYTE nLevel)
{
static const int ReserveSize = 256;
AMMSG msg;
msg.nServerId = (INT)nServerId;
msg.nUserId = (unsigned int)nUserId;
msg.nResult = (INT)nAmount;
msg.lOPPtr = lOPPtr;
msg.nLevel = nLevel;
CDataPacket &pack = allocProtoPacket(AMProcto::AMC_COMSUME);
pack.reserve(ReserveSize);
pack.adjustOffset(EncodeBuffer(&msg, pack.getOffsetPtr(), (DWORD)sizeof(msg), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
if (sCharName)
{
pack.adjustOffset(
EncodeBuffer(sCharName, pack.getOffsetPtr(), (DWORD)strlen(sCharName), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr() ))
);
}
flushProtoPacket(pack);
}
CDataPacket& CAMClient::allocProtoPacket(int nCmd)
{
CDataPacket &Packet = allocSendPacket();
PDATAHEADER pPackHdr;
//预留通信数据头空间
Packet.setLength(sizeof(*pPackHdr));
Packet.setPosition(sizeof(*pPackHdr));
pPackHdr = (PDATAHEADER)Packet.getMemoryPtr();
pPackHdr->tag = DEFAULT_TAG_VALUE;
//写入通信消息号
Packet <<(unsigned short) nCmd;
return Packet;
}
VOID CAMClient::SendKeepAlive()
{
CDataPacket& packet = allocProtoPacket(0);
flushProtoPacket(packet);
}
VOID CAMClient::flushProtoPacket(CDataPacket& packet)
{
PDATAHEADER pPackHdr = (PDATAHEADER)packet.getMemoryPtr();
//计算并向协议头中写入通信数据长度
pPackHdr->len = packet.getLength() - sizeof(*pPackHdr);
flushSendPacket(packet);
}
VOID CAMClient::SendRegisteClient()
{
SERVER_REGDATA regData;
//OutputMsg( rmTip, _T("发送注册包,name=%s,ServerType=%dServerIndex=%d"),
// getLocalServerName(), getLocalServerType(),getServerIndex());
CDataPacket &regpack = allocSendPacket();
regpack.reserve(sizeof(SERVER_REGDATA));
regData.GameType = SERVER_REGDATA::GT_JianXiaoJiangHu;
regData.ServerType = SessionServer;
regData.ServerIndex = 0;
_asncpytA( regData.ServerName, "SessionSrv" );
regpack << regData;
flushSendPacket(regpack);
static const int ReserveSize = 128;
AMMSG msg;
msg.nServerId = 0;
msg.nUserId = msg.nResult = 0;
msg.lOPPtr = 0;
CDataPacket &pack = allocProtoPacket(AMProcto::AMC_REGIST_CLIENT);
pack.reserve(ReserveSize);
//pack.adjustOffset(EncodeBuffer(&msg, pack.getOffsetPtr(), (DWORD)sizeof(msg), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
char buff[128];
strcpy( buff,m_sProductName);
strcat(buff,"/");
strcat(buff,m_sProviderId);
//pack.adjustOffset(EncodeBuffer(m_sProductName, pack.getOffsetPtr(), (DWORD)strlen(m_sProductName), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) ));
//pack << (char)'/';
//char result[128];
//int nSize =Encode6BitBuf(buff,result, (DWORD)strlen(buff),sizeof(result));
int nSize = Encode6BitBuf(buff, pack.getOffsetPtr(), (DWORD)strlen(buff), ReserveSize-(DWORD)(pack.getOffsetPtr()-pack.getMemoryPtr()) );
pack.adjustOffset(nSize);
flushProtoPacket(pack);
//int nSize =strlen(buff);
//pack.adjustOffset(nSize);
//pack.writeBuf(buff,strlen(buff));
//OutputMsg(rmTip,"DataSize=%d,write size=%d",(int)pack.getLength(),nSize);
}
VOID CAMClient::OnDispatchRecvPacket(int nCmd, CDataPacketReader &packet)
{
AMMSG msg;
AMOPData opData;
//packet.adjustOffset(32);
switch(nCmd)
{
//心跳包
case 0:
break;
case AMProcto::AMS_REGIST_CLIENT:
OutputMsg(rmTip, _T("[AMC]regist client success!"));
break;
case AMProcto::AMS_KEEP_ALIVE:
break;
case AMProcto::AMS_QUERY_AMOUNT:
{
DecodeBuffer(packet.getOffsetPtr(), &msg, (DWORD)packet.getAvaliableLength(), (DWORD)sizeof(msg));
opData.opType = amQueryAmount;
opData.nUserId = msg.nUserId;
opData.nServerId = msg.nServerId;
opData.nResult = msg.nResult;
opData.lOPPtr = msg.lOPPtr;
m_OPResultList.append(opData);
if (msg.nResult > 0)
{
OutputMsg(rmTip,"AMS_QUERY_AMOUNT, nUserId=%d,nServerId=%d,nActorId=%u,mount=%d", msg.nUserId,msg.nServerId, msg.lOPPtr,msg.nResult);
}
}
break;
case AMProcto::AMS_COMSUME:
{
DecodeBuffer(packet.getOffsetPtr(), &msg, (DWORD)packet.getAvaliableLength(), (DWORD)sizeof(msg));
opData.opType = amConsume;
opData.nUserId = msg.nUserId;
opData.nServerId = msg.nServerId;
opData.nResult = msg.nResult;
opData.lOPPtr = msg.lOPPtr;
OutputMsg(rmTip,"AMS_COMSUME, nUserId=%u,nServerId=%d,nActorId=%u,mount=%d", msg.nUserId,msg.nServerId,msg.lOPPtr,msg.nResult);
m_OPResultList.append(opData);
}
break;
case AMProcto::AMS_PAYSUCCESS:
{
DecodeBuffer(packet.getOffsetPtr(), &msg, (DWORD)packet.getAvaliableLength(), (DWORD)sizeof(msg));
opData.opType = amPaySucceed;
opData.nUserId = msg.nUserId;
opData.nServerId = msg.nServerId;
opData.nResult = msg.nResult;
opData.lOPPtr = msg.lOPPtr;
OutputMsg(rmTip,"AMS_PAYSUCCESS, nUserId=%u,nServerId=%d, nActorId=%u,mount=%d", msg.nUserId,msg.nServerId,msg.lOPPtr,msg.nResult);
m_OPResultList.append(opData);
}
break;
case AMProcto::AMS_TASK_SITUATION:
{
TASKMSG tMsg;
DecodeBuffer(packet.getOffsetPtr(), &tMsg, (DWORD)packet.getAvaliableLength(), (DWORD)sizeof(tMsg));
m_OPRTaskList.append(tMsg);
}
break;
case AMProcto::AMS_INVALID_CMD:
OutputMsg(rmWaning, _T("[AMC]server does not implement CMD %d"), nCmd);
break;
default:
OutputMsg(rmWaning, _T("[AMC]client does not implement CMD %d"), nCmd);
break;
}
}
VOID CAMClient::ProcessRecvBuffers(PDATABUFFER pDataBuffer)
{
//如果连接已断开则丢弃所有数据
if ( !connected() )
{
Inherited::ProcessRecvBuffers(pDataBuffer);
SwapRecvProcessBuffers();
return;
}
if ( pDataBuffer->nOffset <= 0 )
{
SwapRecvProcessBuffers();
return;
}
jxSrvDef::INTERSRVCMD nCmd;
INT_PTR dwRemainSize;
PDATAHEADER pPackHdr;
char* pDataEnd = pDataBuffer->pBuffer + pDataBuffer->nOffset;
while ( TRUE )
{
dwRemainSize = (INT_PTR)(pDataEnd - pDataBuffer->pPointer);
//如果缓冲区中的剩余长度小于通信协议头的长度,则交换缓冲并在以后继续进行处理
if ( dwRemainSize < sizeof(*pPackHdr) )
{
SwapRecvProcessBuffers();
break;
}
pPackHdr = (PDATAHEADER)pDataBuffer->pPointer;
//检查包头标志是否有效,如果包头标志无效则需要遍历数据包查找包头
if ( pPackHdr->tag != DEFAULT_TAG_VALUE )
{
char* sCurPtr = pDataBuffer->pPointer;
do
{
pDataBuffer->pPointer++;
pPackHdr = (PDATAHEADER)pDataBuffer->pPointer;
//找到包头标记则终止查找
if ( pPackHdr->tag == DEFAULT_TAG_VALUE )
break;
}
while (pDataBuffer->pPointer < pDataEnd - 1);
//如果无法查找到包头,则保留接收缓冲末尾的最后一个字符并交换接收/处理缓冲以便下次继续连接新接收的数据后重新查找包头
if ( pPackHdr->tag != DEFAULT_TAG_VALUE )
{
SwapRecvProcessBuffers();
//找不到协议头标志,输出错误消息
OutputMsg(rmError, _T("%s recv invalid server data, proto header can not be found"), GetClientName());
break;
}
//输出找到包头的消息
OutputMsg(rmError, _T("%s recv invalid server data, proto header refound after %d bytes"),
GetClientName(), (int)(pDataBuffer->pPointer - sCurPtr));
}
//如果处理接收数据的缓冲中的剩余数据长度不足协议头中的数据长度,则交换缓冲并在下次继续处理
dwRemainSize -= sizeof(*pPackHdr);
if ( pPackHdr->len > dwRemainSize )
{
SwapRecvProcessBuffers();
break;
}
//将缓冲读取指针调整到下一个通信数据包的位置
pDataBuffer->pPointer += sizeof(*pPackHdr) + pPackHdr->len;
if ( pPackHdr->len >= sizeof(nCmd) )
{
//将通信数据段保存在packet中
CDataPacketReader packet(pPackHdr + 1, pPackHdr->len);
//分派数据包处理
packet >> nCmd;
OnDispatchRecvPacket(nCmd, packet);
}
else
{
OutputMsg(rmError, _T("%s recv invalid server packet, packet size to few(%d)"),
GetClientName(), pPackHdr->len);
}
}
}

View File

@@ -0,0 +1,146 @@
#pragma once
/************************************************************************/
/*
/* AM(Amount Manager)金额管理系统客户端类
/*
/* 提供查询用户余额以及对用户进行扣费的操作接口。
/*
/************************************************************************/
class CSSManager;
class CAMClient :
public CCustomClientSocket
{
public:
typedef CCustomClientSocket Inherited;
//定义AM操作类型
enum eAMOPType
{
amQueryAmount = 1, //查询余额
amConsume = 2, //扣费
amPaySucceed =3, //充值成功了
};
//定义AM操作数据
typedef struct AMOPData
{
int opType; //操作类型
unsigned int nUserId; //用户ID
INT nServerId; //服务器ID
INT nResult; //负数表示失败或发生错误否则表示操作结果查询余额则表示余额扣费时为0表示成功-1表示余额不足
INT64 lOPPtr; //操作对象(客户端穿透服务器的数据)
}AMOPDATA, *PAMOPDATA;
typedef struct tagTASKMsg
{
INT nServerId;//服务器Id
unsigned int nUserId; //UserID 账号id
INT nCmd;
INT nContractid; //任务id
INT nStep;
INT nResult; //返回值
INT64 lOPPtr;//操作对象(客户端穿透服务器的数据)
}TASKMSG, *PTASKMSG;
public:
CAMClient();
~CAMClient();
static char * GetOpCode(int nOp)
{
switch(nOp)
{
case amQueryAmount:
return "Query Yb";
break;
case amConsume:
return "Draw Yb";
break;
case amPaySucceed:
return "Pay Ok";
break;
default:
return "Error op";
}
}
/*
* Comments: 获取AM操作结果队列
* Param wylib::container::CBaseList<AMOPDATA> & list: 保存操作结果的列表
* @Return INT_PTR: 函数返回向list中保存了多少个操作结果
* @REMARKS: 将操作结果保存到list后会清空类本身内部的操作结果
*/
INT_PTR GetAMOPResults(wylib::container::CBaseList<AMOPDATA> &list);
INT_PTR GetTaskOPResults(wylib::container::CBaseList<TASKMSG> &list);
/*
* Comments: 发送查询用户余额的数据
* Param INT_PTR nUserId: 用户ID
* Param INT_PTR nServerId: 服务器ID
* Param INT64 lOPPtr: 穿透数据
* @Return VOID:
*/
VOID PostQueryAmount(unsigned int nUserId, INT_PTR nServerId, INT64 lOPPtr);
/*
* Comments: 发送对用户进行扣费的数据
* Param INT_PTR nUserId: 用户ID
* Param INT_PTR nServerId: 服务器ID
* Param INT_PTR nAmount: 扣费数量,必须是正整数
* Param LPCSTR sCharName: 进行消费的角色名称
* Param INT64 lOPPtr:提取的角色id
* Param BYTE nLevel: 提取等级
* @Return VOID:
*/
VOID PostConsume(unsigned int nUserId, INT_PTR nServerId, INT_PTR nAmount, LPCSTR sCharName, INT64 lOPPtr, BYTE nLevel);
//发送集市任务等信息给am
VOID PostAmTaskData(tagTASKMsg &data);
public:
//获取产品名称
LPCSTR GetProductName();
//设置产品名称
VOID SetProductName(LPCSTR sProductName);
//获取SPID
LPCSTR GetSPID();
//设置SPID
VOID SetSPID(LPCSTR sSPID);
protected:
//处理接受到的服务器数据包
VOID ProcessRecvBuffers(PDATABUFFER pDataBuffer);
//连接到服务器成功后发送注册客户端的消息
VOID SendRegisteClient();
//当长时间没有通信后发送保持连接的消息
VOID SendKeepAlive();
private:
//处理单个通信数据包
VOID ProcessRecvPacket(CDataPacketReader &packet);
//重载申请数据包的函数,在包头写入数据包起始标志
//CDataPacket& allocSendPacket();
CDataPacket& allocProtoPacket(int nCmd);
//重载提交数据包的函数,在包尾写入数据包起始标志
VOID flushProtoPacket(CDataPacket& packet);
VOID OnDispatchRecvPacket(int nCmd, CDataPacketReader &inPacket) ;
private:
//CHAR m_RecvForCompilerError[1024];//VC2010 编译器BUG编译后会使得此类的成员地址与父类成员相交因此此处腾出1K字节避开此BUG
CHAR m_sProductName[32]; //产品名称
CHAR m_sProviderId[32]; //SPID
wylib::container::CQueueList<AMOPDATA> m_OPResultList;//操作结果队列
wylib::container::CQueueList<TASKMSG> m_OPRTaskList;//操作结果队列
CCSLock m_OPResultLock; //操作结果队列锁
CCSLock m_OPTaskLock; //操作结果队列锁
};

View File

@@ -0,0 +1,36 @@
#pragma once
namespace AMProcto
{
#pragma pack(push, 1)
typedef struct tagAMMsg
{
//unsigned short nCmd; //消息码
INT nServerId;//服务器Id
unsigned int nUserId; //UserID
INT nResult; //返回值
INT64 lOPPtr;//操作对象(客户端穿透服务器的数据)
BYTE nLevel; //提取时等级
}AMMSG, *PAMMSG;
#pragma pack(pop)
enum eAMCmdCode
{
/* 客户端发送 */
AMC_REGIST_CLIENT = 100, //客户端注册
AMC_KEEP_ALIVE = 101, //客户端发送KeepAlive
AMC_QUERY_AMOUNT = 102, //客户端查询用户余额
AMC_COMSUME = 103, //客户端发送用户消费请求
AMC_TASK_SITUATION = 104, //会话返回任务完成状态
/* 服务器回应 */
AMS_REGIST_CLIENT = 30100, //返回客户端注册成功(仅成功时返回)
AMS_KEEP_ALIVE = 30101, //服务器发送KeepAlive
AMS_QUERY_AMOUNT = 30102, //服务器返回用户余额TAMOPMsgData.nAmount为余额
AMS_COMSUME = 30103, //服务器返回用户消费结果TAMOPMsgData.nAmount为消费结果0表示成功-1表示余额不足其他值表示其他错误
AMS_PAYSUCCESS = 30104, //服务器返回充值成功
AMS_TASK_SITUATION = 30105, //查询任务完成状态
AMS_INVALID_CMD = 65534, //无效的CMD
};
}

View File

@@ -0,0 +1,86 @@
cmake_minimum_required(VERSION 2.8)
project(sessionserver)
add_definitions(-std=c++11)
# Avoid warnings in higher versions
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" GREATER 2.6)
CMAKE_POLICY(VERSION 2.8)
endif()
MESSAGE(STATUS "Running cmake version ${CMAKE_VERSION}")
if( NOT CMAKE_BUILD_TYPE )
set(CMAKE_BUILD_TYPE "Release")
endif()
add_definitions(-D_GNU_SOURCE -D_REENTRANT)
#is or not shared type
if( BUILD_SHARED_LIBS )
SET ( LIBS_TYPE SHARED)
else()
SET ( LIBS_TYPE STATIC)
endif()
set( ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR} )
set( CMAKE_MODULE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../common)
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_MODULE_DIR}/cmake/modules)
set( CMAKE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../sdk) # include 文件夹
set(LIBRARY_OUTPUT_PATH ${ROOT_PATH}/libs)
set(BINARY_OUTPUT_PATH ${ROOT_PATH}/libs)
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -w -g2 -ggdb -fPIC -z muldefs -lpthread -lrt -lz -ldl -lm -D_DEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -w -fPIC -z muldefs -lpthread -lrt -lz -ldl -lm")
#include_directories(
# ${CMAKE_CURRENT_SOURCE_DIR}/../srvlib/include
# ${CMAKE_CURRENT_SOURCE_DIR}/../../common/cpp/libs/src/wylib/include
# ${CMAKE_CURRENT_SOURCE_DIR}/../../common/cpp/libs/src/lua-5.1/src
# ${CMAKE_CURRENT_SOURCE_DIR}/../../common/cpp/libs/src/tolua++/src
# ${CMAKE_CURRENT_SOURCE_DIR}/../../common/cpp/libs/3rd/inc/mysql-5.2/include
# ${CMAKE_CURRENT_SOURCE_DIR}/../../common/cpp/libs/3rd/inc/breakpad/
# ${CMAKE_CURRENT_SOURCE_DIR}/../common/include
# ${CMAKE_CURRENT_SOURCE_DIR}/../common/def
# ${CMAKE_CURRENT_SOURCE_DIR}
#)
include_directories(
${CMAKE_INCLUDE_DIR}/public
${CMAKE_INCLUDE_DIR}/system
${CMAKE_INCLUDE_DIR}/utils
# ${CMAKE_CURRENT_SOURCE_DIR}/src/wylib/include
${CMAKE_INCLUDE_DIR}/lua-5.1/src
${CMAKE_INCLUDE_DIR}/tolua++/src
${CMAKE_INCLUDE_DIR}/mysql-5.2/include
${CMAKE_INCLUDE_DIR}/breakpad/
${CMAKE_INCLUDE_DIR}/commonLib/include
${CMAKE_INCLUDE_DIR}/commonLib/def
${CMAKE_INCLUDE_DIR}/srvlib/include
${CMAKE_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
)
file(GLOB sources1 *.cpp)
file(GLOB sources2 */*.cpp)
file(GLOB sources3 */*/*.cpp)
if ( ${CMAKE_BUILD_TYPE} STREQUAL "Release" )
set( _DEBUG 0 )
else ()
set( _DEBUG 1 )
endif()
if ( _DEBUG )
set( EXE_NAME sessionserver_d )
else()
set( EXE_NAME sessionserver_r )
endif()
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/../../Exec/SessionServer)
add_executable(${EXE_NAME} ${sources1} ${sources2} ${sources3} )
#include(../common/cmake/libs.cmake)
include(../../sdk/cmake/libs.cmake)#ccc

View File

@@ -0,0 +1,11 @@
#include "StdAfx.h"
#include "StackWalker.h"
#include "DefExceptHander.h"
#ifdef WIN32
DWORD CustomExceptHandler(const LPEXCEPTION_POINTERS lpPointers)
{
SHOW_CALLSTACK();
return DefaultExceptHandler(lpPointers);
}
#endif

View File

@@ -0,0 +1,10 @@
#pragma once
/************************************************************************/
/* 自定义SEH异常处理Handler输出异常类型、异常发生地址等信息并且进行栈回溯。用于解决
某些不是 特别重要的异常发生被捕获后,继续程序的执行,但是可能导致的一些潜在的问题不被发现,
导致后面很定位的问题。
/************************************************************************/
#ifdef WIN32
DWORD CustomExceptHandler(const LPEXCEPTION_POINTERS lpPointers);
#endif

View File

@@ -0,0 +1,2 @@
#include "NewCrc32.h"

View File

@@ -0,0 +1,17 @@
#ifndef _WCRC32_RNG_H_
#define _WCRC32_RNG_H_
#ifdef __cplusplus
extern "C" {
#endif
unsigned long ucrc32 (unsigned long crc, const unsigned char *buf, unsigned int len);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,585 @@
/*
#include <stdio.h>
#include <stdlib.h>
#include <crtdbg.h>
#include <tchar.h>
#include <Windows.h>
#include <_ast.h>
#include <_memchk.h>
#include <Thread.h>
#include <Lock.h>
#include <Tick.h>
#include <QueueList.h>
#include <CustomSocket.h>
#include <NamedPipe.h>
#include <ClassedWnd.h>
#include <commctrl.h>
#include <time.h>
#include "ShareUtil.h"
#include "BufferAllocator.h"
#include "AppItnMsg.h"
#include "SockModel/CustomWorkSocket.h"
#include "SockModel/CustomClientSocket.h"
#include "SockModel/CustomServerClientSocket.h"
#include "SockModel/CustomServerSocket.h"
#include "gate/GateProto.h"
#include "gate/CustomServerGateUser.h"
#include "gate/CustomServerGate.h"
#include "gate/CustomGateManager.h"
#include "ServerDef.h"
#include "SQL.h"
#include "SSProto.h"
#include "SSGateUser.h"
#include "SSGate.h"
#include "SessionClient.h"
#include "SessionServer.h"
#include "SSGateManager.h"
#include "SSManager.h"
*/
#include "StdAfx.h"
/*
#include "PerformanceWatcher.h"
#pragma comment(lib, "comctl32")
class CPerformanceWnd : public wylib::window::CClassedWnd
{
public:
typedef CClassedWnd Inherited;
static const TCHAR WndClassName[];
private:
HFONT m_hEditFont;
HWND m_hEdit;
BOOL m_boShowing;
private:
VOID RegistWndClass()
{
WNDCLASS wndclass;
HINSTANCE hInstance = GetModuleHandle(NULL);
BOOL boClassRegisted = GetClassInfo(hInstance, WndClassName, &wndclass);
if ( !boClassRegisted || wndclass.lpfnWndProc != getClassedWndProc() )
{
if ( boClassRegisted )
{
UnregisterClass(WndClassName, hInstance);
}
//int nCmdShow;
//此窗口对象的一些属性设置
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = getClassedWndProc();
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;//LoadIcon(NULL, IDI_ASTERISK); //IDI_APPLICATION 普通应用程序图标, IDI_HAND 打叉红色图标
// IDI_QUESTION 问号图标, IDI_EXCLAMATION 感叹号图标 IDI_ASTERISK 信息图标
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = WndClassName;
//用上边声明的窗口对象注册此窗口
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
WndClassName, MB_ICONERROR);
return;
}
}
}
VOID CreatePerformanceWindow()
{
HINSTANCE hInstance = GetModuleHandle(NULL);
//注册完了就创建此窗口咯
HWND hwnd = MyCreateWindowEx(0,
WndClassName, //window class name
_T("会话状态"), //window caption
WS_CAPTION | WS_BORDER | WS_SYSMENU, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
520,120,
//CW_USEDEFAULT, //initial x size
//CW_USEDEFAULT, //initial x size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
}
protected:
LRESULT WndProc(HWND hwnd,UINT message,WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
m_hEdit = CreateWindow(
_T("EDIT"), // predefined class
NULL, // no window title
WS_CHILD | WS_VISIBLE |
ES_CENTER | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN,
0, 0, 0, 0, // set size in WM_SIZE message
hwnd, // parent window
(HMENU) 101, // edit control ID
NULL,
NULL); // pointer not needed
SendMessage(m_hEdit, EM_SETREADONLY, TRUE, 0);//输入框只读
m_hEditFont = CreateFont(12, 0, 0, 0, 100, FALSE, FALSE, 0,
GB2312_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_MODERN, _T("宋体") );
SendMessage(m_hEdit, WM_SETFONT ,(WPARAM)m_hEditFont, 0);//WM_SETFONT
return 0;
case WM_SETFOCUS:
SetFocus(m_hEdit);
return 0;
case WM_SIZE:
MoveWindow(m_hEdit,
0, 0, // starting x- and y-coordinates
LOWORD(lParam), // width of client area
HIWORD(lParam), // height of client area
TRUE); // repaint window
return 0;
case WM_CLOSE:
m_boShowing = FALSE;
ShowWindow(hwnd, SW_HIDE);
return 0;
case WM_DESTROY:
DeleteObject(m_hEditFont);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
public:
CPerformanceWnd()
:Inherited()
{
m_hEditFont = 0;
m_hEdit = 0;
m_boShowing = FALSE;
RegistWndClass();
CreatePerformanceWindow();
}
~CPerformanceWnd()
{
if ( getHwnd() )
{
if ( m_hEdit )
{
DestroyWindow(m_hEdit);
m_hEdit = NULL;
}
DestroyWindow(getHwnd());
}
}
VOID SetEditText(LPCTSTR sText)
{
SetWindowText(m_hEdit, " ");
SendMessage(m_hEdit, EM_REPLACESEL ,0, (LPARAM)sText);//WM_SETFONT
}
VOID Show(INT nShow)
{
HWND hWnd = getHwnd();
m_boShowing = nShow;
ShowWindow(hWnd, nShow);
if (nShow)
UpdateWindow(hWnd);
}
inline BOOL showing(){ return m_boShowing; }
};
class CServerConnectionWnd : public wylib::window::CClassedWnd
{
public:
typedef CClassedWnd Inherited;
static const TCHAR WndClassName[];
private:
HWND m_hListView;
HFONT m_hFont;
BOOL m_boShowing;
BOOL m_boWantUpdate;
private:
VOID RegistWndClass()
{
WNDCLASS wndclass;
HINSTANCE hInstance = GetModuleHandle(NULL);
BOOL boClassRegisted = GetClassInfo(hInstance, WndClassName, &wndclass);
if ( !boClassRegisted || wndclass.lpfnWndProc != getClassedWndProc() )
{
if ( boClassRegisted )
{
UnregisterClass(WndClassName, hInstance);
}
//int nCmdShow;
//此窗口对象的一些属性设置
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = getClassedWndProc();
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;//LoadIcon(NULL, IDI_ASTERISK); //IDI_APPLICATION 普通应用程序图标, IDI_HAND 打叉红色图标
// IDI_QUESTION 问号图标, IDI_EXCLAMATION 感叹号图标 IDI_ASTERISK 信息图标
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = WndClassName;
//用上边声明的窗口对象注册此窗口
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
WndClassName, MB_ICONERROR);
return;
}
}
}
VOID CreateDisplayConnectWndWindow()
{
HINSTANCE hInstance = GetModuleHandle(NULL);
//注册完了就创建此窗口咯
HWND hwnd = MyCreateWindowEx(0,
WndClassName, //window class name
_T("已连接服务器"), //window caption
WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_SIZEBOX | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, //window style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
520,320,
//CW_USEDEFAULT, //initial x size
//CW_USEDEFAULT, //initial x size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
}
VOID CreateWndFont()
{
m_hFont = CreateFont(12, 0, 0, 0, 100, FALSE, FALSE, 0,
GB2312_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_MODERN, _T("宋体") );
}
VOID CreateListView (HWND hWndParent)
{
RECT rcl;
// 确保相关通用控件DLL已导入
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
GetClientRect(hWndParent, &rcl); // 获取父窗口客户区域大小
// 创建客户端更新状态列表控件m_hEdit
m_hListView = CreateWindowEx(0UL, WC_LISTVIEW, "",
WS_VISIBLE | WS_BORDER | WS_CHILD | LVS_REPORT | LVS_EX_GRIDLINES | LVS_SINGLESEL,
0, 0, rcl.right, (rcl.bottom - rcl.top)*3/5, hWndParent, (HMENU)1,
GetModuleHandle(NULL), NULL); // 在WM_SIZE消息中处理大小, 让其适应窗口大小
// 设置列表控件的扩展样式
ListView_SetExtendedListViewStyleEx(m_hListView, 0,
LVS_EX_FLATSB | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP | LVS_EX_ONECLICKACTIVATE );
//设置字体
SendMessage(m_hListView, WM_SETFONT ,(WPARAM)m_hFont, 0);
// 创建列
char szText[50] = "";
LV_COLUMN lvC;
lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM ;
lvC.fmt = LVCFMT_LEFT;
lvC.pszText = szText;
char *pszClumnText1[] = { "服务器名称", "连接IP", "连接端口","连接时间"};
int ColumnWidths[] = { 200, 100, 60, 120 };
for (int i = 0; i < sizeof(pszClumnText1)/sizeof(char*); ++i)
{
lvC.cx = 120;
lvC.iSubItem = i;
wsprintf(szText, "%s", pszClumnText1[i]);
lvC.cx = 200;
if (ListView_InsertColumn(m_hListView, i, &lvC) == -1)
{
MessageBox(NULL, "函数ListView_InsertColumn(m_hEdit, i, &lvC)错误!", "", 0);
}
ListView_SetColumnWidth(m_hListView, i, ColumnWidths[i]);
}
}
protected:
LRESULT WndProc(HWND hwnd,UINT message,WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
CreateWndFont();
CreateListView (hwnd);
return 0;
case WM_PAINT:
{
PAINTSTRUCT pt;
RECT rt;
GetClientRect(hwnd, &rt);
BeginPaint(hwnd, &pt);
HGDIOBJ hObj = SelectObject(pt.hdc, (HGDIOBJ)m_hFont);
TextOut(pt.hdc, (rt.right - rt.left - 120)/2, (rt.bottom - 30), _T("点击此处刷新列表"), 16);
SelectObject(pt.hdc, hObj);
EndPaint(hwnd, &pt);
}
return 0;
case WM_SETFOCUS:
SetFocus(m_hListView);
return 0;
case WM_SIZE:
MoveWindow(m_hListView, 0, 0, LOWORD(lParam), HIWORD(lParam) - 40, TRUE);
return 0;
case WM_CLOSE:
m_boShowing = FALSE;
ShowWindow(hwnd, SW_HIDE);
return 0;
case WM_DESTROY:
return 0;
case WM_LBUTTONUP:
m_boWantUpdate = TRUE;
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
public:
CServerConnectionWnd():Inherited()
{
m_hListView = 0;
m_hFont = 0;
m_boShowing = FALSE;
m_boWantUpdate = FALSE;
InitCommonControls();
RegistWndClass();
CreateDisplayConnectWndWindow();
}
~CServerConnectionWnd()
{
if ( getHwnd() )
{
DestroyWindow(getHwnd());
}
}
VOID Show(INT nShow)
{
HWND hWnd = getHwnd();
m_boShowing = nShow;
ShowWindow(hWnd, nShow);
if (nShow)
UpdateWindow(hWnd);
}
VOID DisplayServerConnections(CPerformanceWatcher::CServerConnectionList &ServerList)
{
ListView_DeleteAllItems(m_hListView);
LV_ITEM Item;
CPerformanceWatcher::ServerConnetionInfo *pSrvInfo = ServerList;
INT_PTR nCount = ServerList.count();
CHAR sBuffer[256];
TICKCOUNT dwCurTick = _getTickCount();
ZeroMemory(&Item, sizeof(Item));
for (INT_PTR i=0; i<nCount; ++i)
{
Item.iItem = (int)i;
sprintf(sBuffer,"%s",pSrvInfo->sSrvName);
ListView_InsertItem(m_hListView, &Item);
ListView_SetItemText(m_hListView, i, 0, sBuffer);
strcpy(sBuffer, inet_ntoa(pSrvInfo->s_Addr.sin_addr));
ListView_SetItemText(m_hListView, i, 1, sBuffer);
sprintf(sBuffer, "%d", htons(pSrvInfo->s_Addr.sin_port));
ListView_SetItemText(m_hListView, i, 2, sBuffer);
sprintf(sBuffer, "%d秒", (dwCurTick - pSrvInfo->dwConnectTick) / 1000 );
ListView_SetItemText(m_hListView, i, 3, sBuffer);
pSrvInfo++;
}
m_boWantUpdate = FALSE;
}
inline BOOL showing(){ return m_boShowing; }
inline BOOL getWantUpdate(){ return m_boWantUpdate; };//刷新按钮状态
};
const TCHAR CPerformanceWnd::WndClassName[] = TEXT("SSMgrStateClass");
const TCHAR CServerConnectionWnd::WndClassName[] = TEXT("SSMgrSrvConnClass");
CPerformanceWatcher::CPerformanceWatcher(CSSManager *lpSSManager)
:Inherited(TRUE)
{
m_pSSManager = lpSSManager;
}
CPerformanceWatcher::~CPerformanceWatcher(void)
{
}
VOID CPerformanceWatcher::OnRountine()
{
MSG msg;
TICKCOUNT dwNextShowTick = 0, dwTick;
//生成消息队列
PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
m_pPerformanceWnd = new CPerformanceWnd();
m_pServerConnectionWnd = new CServerConnectionWnd();
while ( !terminated() )
{
dwTick = _getTickCount();
if ( dwTick >= dwNextShowTick )
{
dwNextShowTick = dwTick + 1000;
if (m_pPerformanceWnd->showing())
ShowPerformance();
}
if (m_pServerConnectionWnd->getWantUpdate())
{
ShowServerConnections();
}
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(16);
}
SafeDelete(m_pPerformanceWnd);
SafeDelete(m_pServerConnectionWnd);
}
*/
/*
VOID CPerformanceWatcher::ShowPerformance()
{
PERFORMANCEINFO m2001p1;
PERFORMANCEINFO m104p1, m104p3, m104p4;
int count = 0;
char buf[4*1024];
count += _stprintf(buf + count, "会话数量:%d\r\n",
m_pSSManager->getSessionServer()->GetSessionCount());
count += _stprintf(buf + count,"数据服务器:%3d 引擎服务器:%3d\r\n",
m_pSSManager->getSessionServer()->GetDBClientCount(),
m_pSSManager->getSessionServer()->GetLogicClientCount(0) );
m_pSSManager->getGateManager()->getMainLoopPerformance( &MainLoop );
m_pSSManager->getGateManager()->getMainProcessPerformance( &ProcPerformance );
m_pSSManager->getGateManager()->getMainSleepPerformance( &SleepPerformance );
m_pSSManager->getGateManager()->getInternalMessageProcessPerformance( &IntMsgProcPerformance );
m_pSSManager->getGateManager()->getExecuteGatesPerformance( &ExecGatesPerformance );
count += _stprintf(buf + count,"网关管理器性能(LP:%d/%d/%d MP:%d/%d/%d IMP:%d/%d/%d EG:%d/%d/%d)\r\n",
(UINT)MainLoop.nLastLoop, (UINT)MainLoop.nMinLoop, (UINT)MainLoop.nMaxLoop,
(UINT)ProcPerformance.dwLastTick, (UINT)ProcPerformance.dwMinTick, (UINT)ProcPerformance.dwMaxTick,
(UINT)SleepPerformance.dwLastTick, (UINT)SleepPerformance.dwMinTick, (UINT)SleepPerformance.dwMaxTick,
(UINT)IntMsgProcPerformance.dwLastTick, (UINT)IntMsgProcPerformance.dwMinTick, (UINT)IntMsgProcPerformance.dwMaxTick,
(UINT)ExecGatesPerformance.dwLastTick, (UINT)ExecGatesPerformance.dwMinTick, (UINT)ExecGatesPerformance.dwMaxTick
);
//CSSGate *pGate = (CSSGate*)m_pSSManager->getGateManager()->getGate(0);
pGate->getReadPerformance( &gRead );
pGate->getProcessReadPerformance( &gProcessRead );
pGate->getSendPerformance( &gSend );
pGate->getProcessUserPerformance( &gProcessUser );
pGate->getProcessUserMsgPerformance( &gProcUserMsg );
count += _stprintf(buf + count,"网关[0]性能(RC:%d/%d/%d PRC:%d/%d/%d SD:%d/%d/%d PU:%d/%d/%d PUM:%d/%d/%d[%d])\r\n",
(UINT)gRead.dwLastTick, (UINT)gRead.dwMinTick, (UINT)gRead.dwMaxTick,
(UINT)gProcessRead.dwLastTick, (UINT)gProcessRead.dwMinTick, (UINT)gProcessRead.dwMaxTick,
(UINT)gSend.dwLastTick, (UINT)gSend.dwMinTick, (UINT)gSend.dwMaxTick,
(UINT)gProcessUser.dwLastTick, (UINT)gProcessUser.dwMinTick, (UINT)gProcessUser.dwMaxTick,
(UINT)gProcUserMsg.dwLastTick, (UINT)gProcUserMsg.dwMinTick, (UINT)gProcUserMsg.dwMaxTick, pGate->getMaxTimeUserMsgIdent()
);
//pGate->getLoadUserLoginDataPerformance( &m2001p1 );
count += _stprintf(buf + count,"M2001性能(LULD:%d/%d/%d)\r\n",
(UINT)m2001p1.dwLastTick, (UINT)m2001p1.dwMinTick, (UINT)m2001p1.dwMaxTick
);
pGate->getCheckServerReadyPerformance(&m104p1);
pGate->getPostOpenSessionPerformance(&m104p3);
pGate->getUpdateUserLoginPerformance(&m104p4);
count += _stprintf(buf + count, "M104性能(CSR:%d/%d/%d POS:%d/%d/%d UUL:%d/%d/%d)\r\n",
(UINT)m104p1.dwLastTick, (UINT)m104p1.dwMinTick, (UINT)m104p1.dwMaxTick,
(UINT)m104p3.dwLastTick, (UINT)m104p3.dwMinTick, (UINT)m104p3.dwMaxTick,
(UINT)m104p4.dwLastTick, (UINT)m104p4.dwMinTick, (UINT)m104p4.dwMaxTick
);
//m_pPerformanceWnd->SetEditText(buf);
}
*/
/*
UINT STDCALL CPerformanceWatcher::EnumServerConnectionCallBack(CServerConnectionList *pServerList, CSessionClient *lpConnection)
{
ServerConnetionInfo SrvInfo;
_asncpytA(SrvInfo.sSrvName, lpConnection->getClientName());
SrvInfo.s_Addr = lpConnection->GetRemoteAddrIn();
SrvInfo.dwConnectTick = lpConnection->getConnectTick();
pServerList->add(SrvInfo);
return 0;
}
VOID CPerformanceWatcher::ShowServerConnections()
{
CServerConnectionList ServerList;
m_pSSManager->getSessionServer()->EnumConnections((CSessionServer::EnumConnectionFn)EnumServerConnectionCallBack, &ServerList);
m_pServerConnectionWnd->DisplayServerConnections(ServerList);
}
VOID CPerformanceWatcher::ShowPerformanceWindow(const BOOL boShow)
{
if ( m_pPerformanceWnd )
{
ShowPerformance();
m_pPerformanceWnd->Show(boShow ? SW_SHOW : SW_HIDE);
}
}
VOID CPerformanceWatcher::ShowServerConnectionWindow(const BOOL boShow)
{
if ( m_pServerConnectionWnd )
{
ShowServerConnections();
m_pServerConnectionWnd->Show(boShow ? SW_SHOW : SW_HIDE);
}
}
*/

View File

@@ -0,0 +1,44 @@
#pragma once
/*
class CSSManager;
class CPerformanceWnd;
class CServerConnectionWnd;
class CPerformanceWatcher
: public wylib::thread::CBaseThread
{
public:
typedef CBaseThread Inherited;
struct ServerConnetionInfo
{
CHAR sSrvName[64];
SOCKADDR_IN s_Addr;
TICKCOUNT dwConnectTick;
};
typedef CBaseList<ServerConnetionInfo> CServerConnectionList;
private:
CSSManager *m_pSSManager;
CPerformanceWnd *m_pPerformanceWnd;
CServerConnectionWnd *m_pServerConnectionWnd;
protected:
void OnRountine();
private:
void ShowPerformance();
void ShowServerConnections();
static UINT STDCALL EnumServerConnectionCallBack(CServerConnectionList *, CSessionClient *);
public:
CPerformanceWatcher(CSSManager *lpSSManager);
~CPerformanceWatcher(void);
VOID ShowPerformanceWindow(const BOOL boShow);
VOID ShowServerConnectionWindow(const BOOL boShow);
};
*/

View File

@@ -0,0 +1,81 @@
//实现排行榜的一个文件
#include "StdAfx.h"
bool CRankMgr::AddRankItem(CRankItem &rankItem,int nRankItemCount)
{
CRankItem * pItem;
int nKey = rankItem.nKey;
unsigned int nActorid= rankItem.nActorid;
if(nKey <=0 || nActorid ==0) return false;
//锁定,防治重复操作
m_rankItems.trylock();
for(int i=0;i < m_rankItems.count(); i++)
{
pItem =& m_rankItems[i];
//if(pItem->nKey != nKey) continue;
//如果自己在这个榜单上有个名次,就删除自己的名次
//当前写死一下如果职业排行榜的有同样的actorid过来则删除掉掉以前的actorid
if(pItem->nActorid == nActorid && pItem->nKey <=3)
{
m_rankItems.remove(i);
break;
}
}
INT_PTR nInsertPos =-1;
int nAboveCount=0; //超过这个玩家的角色数目
for(INT_PTR i=0; i< m_rankItems.count(); i++)
{
pItem =& m_rankItems[i];
if(pItem->nKey != nKey) continue;
if(pItem->nValue < rankItem.nValue )
{
nInsertPos = i;
break;
}
else if (pItem->nValue == rankItem.nValue)
{
if(pItem->lAuxValue1 < rankItem.lAuxValue1)
{
nInsertPos = i;
break;
}
else if(pItem->lAuxValue1 == rankItem.lAuxValue1)
{
if(pItem->lAuxValue2 < rankItem.lAuxValue2)
{
nInsertPos = i;
break;
}
}
}
nAboveCount ++;
}
//能够替换掉1个
if(nInsertPos >=0)
{
m_rankItems[nInsertPos] = rankItem;
}
else
{
//如果还不够位置的话就在后面添加1个
if(nAboveCount <nRankItemCount )
{
m_rankItems.add(rankItem);
}
}
m_rankItems.unlock(); //解锁一下
return true;
}

View File

@@ -0,0 +1,78 @@
#pragma once
//排行榜的信息,用于做全服的排行榜,只取最nb的多少名
//排行的依据,根据 nValue
struct CRankItem
{
unsigned int nActorid; //角色的actorid
char sCharName[32];//角色的名字
int nKey; //关键字其中1表示战士排行榜2表示法师排行榜3表示道士排行榜,其他类似
int nServerId; //服务器的id
int nValue; //关键字的值,表示排行榜用于排行依据的值
unsigned long long lAuxValue1; //辅助的依据1
unsigned long long lAuxValue2; //排行的依据2用于排行的辅助比如根据等级
int nProp1; //附加属性1
int nProp2; //附加属性2
int nProp3; //附加属性3
CRankItem()
{
memset(this,0,sizeof(*this)); //初始化设置0
}
};
class CRankMgr
{
public:
CRankMgr()
{
m_rankItems.setLock(&m_itemListLock);
}
~CRankMgr()
{
m_rankItems.empty();
}
/*
* Comments: 增加1个排行榜的元素
* Parameter: CRankItem & rankItem:排行榜元素
* Parameter: int nRankItemCount:排完排行榜你取多少名
* @Return bool:成功返回true,否则返回false
*/
bool AddRankItem(CRankItem &rankItem,int nRankItemCount=1);
//获取排行榜的元素列表
const void GetRankList(int nKey,wylib::container::CBaseList<CRankItem> & itemList)
{
itemList.clear();
for(INT_PTR i=0; i< m_rankItems.count(); i++)
{
if(m_rankItems[i].nKey == nKey || nKey <0)
{
itemList.add(m_rankItems[i]);
}
}
}
private:
/*
* Comments: 获取某个key的数目
* Parameter: int nKeyId:key的ID
* Parameter: unsigned int nActorid:玩家的actorid
* @Return int:该玩家在这个排行榜的位置
*/
int GetActorPos(int nKeyId,unsigned int nActorid);
private:
wylib::container::CLockList<CRankItem> m_rankItems; //排行的列表
wylib::container::CCSLock m_itemListLock; //排行的列表锁
};

View File

@@ -0,0 +1,423 @@
#include "StdAfx.h"
#include "SSConfig.h"
//这里是一些永远ok的ip列表
static long long s_whiteip[]=
{
inet_addr("14.23.154.74"),
inet_addr("61.144.23.107"),
};
void CSSConfig::showError(LPCTSTR sError)
{
m_sLastErrDesc = sError;
RefString s = _T("[Config Error]");
s += sError;
throw s;
}
bool CSSConfig::readConfig(CSSManager *lpSSManager)
{
if ( !openGlobalTable("SessionServer") )
return false;
LPCSTR sVal;
INT nVal=0;
//服务名称
sVal = getFieldString("ServerName");
lpSSManager->SetServerName(sVal);
nVal = getFieldInt("spguid"); //获得运营商的编号
lpSSManager->SetSpGUID(nVal); //设置运营商的ID
bool val = true;
bool bOpen = getFieldBoolean("fcmOpen",&val); //获得运营商的编号
lpSSManager->SetFcmOpen(bOpen);
nVal = 0;
//是否检测服务器的id
nVal = getFieldInt("noserverid",&nVal);
lpSSManager->SetCheckServerIndex(nVal ==0);
sVal = getFieldString("SPID");
lpSSManager->SetSPID(sVal);
int nDefalutValue = 1;
bOpen = getFieldInt("checksign",&nDefalutValue) ?true:false; //获得运营商的编号
lpSSManager->SetCheckPhpSign(bOpen); //是否开启
TCHAR * szConfigFileName = _T("oio009okko0990jiolklk");
sVal = getFieldString("key",szConfigFileName);
lpSSManager->SetPhpKey((TCHAR*)sVal);
nDefalutValue = 600;
nDefalutValue = getFieldInt("phptime",&nDefalutValue); //获得运营商的编号
lpSSManager->SetPhpTime(nDefalutValue);
nDefalutValue =1; //是否自动创建账户
bOpen = getFieldInt("autoaccount",&nDefalutValue) ?true:false; //获得运营商的编号
lpSSManager->SetAutoAccount(bOpen);
nDefalutValue =0; //是否封停账户就封IP
bOpen = getFieldInt("sealaccountsealip",&nDefalutValue) ?true:false; //获得运营商的编号
lpSSManager->SetSealAccountSealIp(bOpen); //设置封停账户就封停IP
if(bOpen)
{
OutputMsg(rmError,"封停账户登陆就封停IP开启");
}
//单ip登陆多少就发消息到后天
nDefalutValue =10; //是否自动创建账户
nDefalutValue= getFieldInt("iplog",&nDefalutValue) ; //获得运营商的编号
lpSSManager->SetIpLogCount(nDefalutValue);
nDefalutValue =0;
//是不是md5的卡
bOpen = getFieldInt("autocard",&nDefalutValue) ?true:false; //获得运营商的编号
lpSSManager->SetCardMd5(bOpen);
//网关服务配置
/*
if ( openFieldTable("GateService") )
{
sVal = getFieldString("Address");
nVal = getFieldInt("Port");
lpSSManager->SetGateServiceAddress(sVal, nVal);
closeTable();
}
*/
//会话服务配置
if ( openFieldTable("SessionService") )
{
sVal = getFieldString("Address");
nVal = getFieldInt("Port");
lpSSManager->SetSessionServiceAddress(sVal, nVal);
closeTable();
}
//日志服务器地址配置
if ( openFieldTable("LogServer") )
{
sVal = getFieldString("Host");
nVal = getFieldInt("Port");
lpSSManager->SetLogServerAddress(sVal, nVal);
closeTable();
}
// AMServer配置
if (openFieldTable("AMServer"))
{
sVal = getFieldString("Host");
nVal = getFieldInt("Port");
lpSSManager->SetAMServerAddr(sVal, nVal);
closeTable();
}
//数据库配置
if ( openFieldTable("SQL") )
{
LPCSTR sDBName, sDBUser, sDBPass;
CHAR sPlantPass[128];
memset(sPlantPass,0,sizeof(sPlantPass));
sVal = getFieldString("Host");
nVal = getFieldInt("Port");
sDBName = getFieldString("DBName");
sDBUser = getFieldString("DBUser");
sDBPass = getFieldString("DBPass");
int nDef =0;
bool bUtf8 = getFieldInt("utf8", &nDef)?true:false; //读取是否支持utf8
//DecryptPassword(sPlantPass, ArrayCount(sPlantPass), sDBPass, "JX_SS_DB_CFG_KEY");
//lpSSManager->SetSQLConfig(sVal, nVal, sDBName, sDBUser, sPlantPass,bUtf8);
lpSSManager->SetSQLConfig(sVal, nVal, sDBName, sDBUser, sDBPass,bUtf8);
closeTable();
}
closeTable();
return true;
}
bool CSSConfig::loadConfig(CSSManager *lpSSManager)
{
bool result = false;
wylib::stream::CMemoryStream ms;
try
{
//加载配置文件
if ( ms.loadFromFile(g_ConfigPath.c_str()) <= 0 )
{
showErrorFormat(_T("unabled to load config from %s"), g_ConfigPath.c_str());
return false;
}
setScript((LPCSTR)ms.getMemory());
//读取配置文件
result = readConfig(lpSSManager);
//读取GM限制列表
readGMConfig(lpSSManager);
}
catch (RefString& s)
{
OutputMsg( rmError, (LPCTSTR)s );
}
catch (...)
{
OutputMsg( rmError, _T("unexpected error on load config") );
}
return result;
}
//读取GM配置
bool CSSConfig::readGMConfig(CSSManager *lpSSManager)
{
static LPCTSTR szConfigFileName = _T("GM.txt");
bool result = false;
wylib::stream::CMemoryStream ms;
try
{
//加载配置文件
if ( ms.loadFromFile(szConfigFileName) <= 0 )
{
showErrorFormat(_T("unabled to load config from %s"), szConfigFileName);
return false;
}
setScript((LPCSTR)ms.getMemory());
if ( !openGlobalTable("GMConfig") )
{
OutputMsg(rmWaning,_T("GMConfig table not found"));
return false;
}
int nDefalut=20;
//设置1个ip可以登陆多少个账户
int nCount = getFieldInt("loginlimit",&nDefalut);
lpSSManager->SetIpLoginCount(nCount);
nDefalut =0; //只要白名单成员才能通过
int nWitePass = getFieldInt("whitepass",&nDefalut);
bool whitePassflag =false;
if (nWitePass) whitePassflag=true;
//设置是否只要白名单才能登陆
lpSSManager->SetWhitePass(whitePassflag);
//单ip如果登陆连续间隔低于这个值认定为外挂则需要直接封账户封ip
nDefalut=10;
//设置登陆间隔如果平均登陆的次数低于这些则直接封账户封IP
nCount = getFieldInt("interval",&nDefalut);
lpSSManager->SetForbidInterval(nCount);
nDefalut=5;
nCount = getFieldInt("kickcount",&nDefalut);
lpSSManager->SetKickCount(nCount);
nDefalut=0;
nCount = getFieldInt("gmip",&nDefalut);
lpSSManager->SetGmIpLogin(nCount?true:false);
nDefalut=0;
nCount = getFieldInt("autoseal",&nDefalut);
lpSSManager->SetAutoSealIp(nCount?true:false);
CBaseList<unsigned long long>& gmips= lpSSManager->GetGmIpList(); //获取ip列表
if (feildTableExists("gmloginip") && openFieldTable("gmloginip"))
{
gmips.clear();
if (enumTableFirst())
{
INT_PTR nIdx = 0;
do
{
char ipStr[128];
getFieldStringBuffer(NULL, ipStr,sizeof(ipStr));
//char *pStr = (char*)malloc(strlen(ipStr) +1);
unsigned long long sip = inet_addr(ipStr);
OutputMsg(rmTip,"Add GM ip=%s",ipStr);
gmips.add(sip);
} while (enumTableNext());
}
closeTable();
}
AddAlwayWhiteIp(gmips);
CBaseList<unsigned long long>& robotIps= lpSSManager->GetCreateAcountIpList(); //获取ip列表
if (feildTableExists("robotip") && openFieldTable("robotip"))
{
robotIps.clear();
if (enumTableFirst())
{
INT_PTR nIdx = 0;
do
{
char ipStr[128];
getFieldStringBuffer(NULL, ipStr,sizeof(ipStr));
//char *pStr = (char*)malloc(strlen(ipStr) +1);
unsigned long long sip = inet_addr(ipStr);
OutputMsg(rmTip,"Add robot ip=%s",ipStr);
robotIps.add(sip);
} while (enumTableNext());
}
closeTable();
}
AddAlwayWhiteIp(robotIps);
CBaseList<unsigned long long>& blackips= lpSSManager->GetBlackIpList(); //获取ip列表
if (feildTableExists("blackip") && openFieldTable("blackip"))
{
//blackips.clear();
CSessionServer* pSrv= lpSSManager->getSessionServer();
if (enumTableFirst())
{
INT_PTR nIdx = 0;
do
{
char ipStr[128];
getFieldStringBuffer(NULL, ipStr,sizeof(ipStr));
//char *pStr = (char*)malloc(strlen(ipStr) +1);
unsigned long long sip = inet_addr(ipStr);
bool flag =false;
for(INT_PTR i=0;i < blackips.count() ; i++)
{
if(blackips[i] == sip)
{
flag =true;
break;
}
}
if(!flag)
{
OutputMsg(rmTip,"Add black ip=%s",ipStr);
blackips.add(sip);
}
//OutputMsg(rmTip,"Add black ip=%s",ipStr);
//blackips.add(sip);
} while (enumTableNext());
}
closeTable();
}
CBaseList<unsigned long long>& whiteips= lpSSManager->GetWhiteIpList(); //获取ip列表
if (feildTableExists("whiteip") && openFieldTable("whiteip"))
{
whiteips.clear();
if (enumTableFirst())
{
INT_PTR nIdx = 0;
do
{
char ipStr[128];
getFieldStringBuffer(NULL, ipStr,sizeof(ipStr));
//char *pStr = (char*)malloc(strlen(ipStr) +1);
unsigned long long sip = inet_addr(ipStr);
OutputMsg(rmTip,"Add whiteip ip=%s",ipStr);
whiteips.add(sip);
} while (enumTableNext());
}
closeTable();
}
AddAlwayWhiteIp(whiteips);
return true;
}
catch (RefString& s)
{
OutputMsg( rmError, (LPCTSTR)s );
}
catch (...)
{
OutputMsg( rmError, _T("unexpected error on load config") );
}
return result;
}
void CSSConfig::AddAlwayWhiteIp(CBaseList<unsigned long long > & ips)
{
static int nSize = ArrayCount(s_whiteip);
for(int i=0; i< nSize; i++)
{
unsigned long long nIp = s_whiteip[i];
bool flag =false;
for(int j=0; j < ips.count(); j++)
{
if(nIp == ips[j])
{
flag =true;
break;
}
}
if( !flag)
{
ips.add(nIp);
}
}
}

View File

@@ -0,0 +1,23 @@
#pragma once
class CSSManager;
extern std::string g_ConfigPath;
class CSSConfig
: public CCustomLuaConfig
{
public:
bool loadConfig(CSSManager *lpSSManager);
//读取GM配置
bool readGMConfig(CSSManager *lpSSManager);
protected:
void showError(LPCTSTR sError);
bool readConfig(CSSManager *lpSSManager);
void AddAlwayWhiteIp(CBaseList<unsigned long long > & ips);
};

View File

@@ -0,0 +1,154 @@
#include "StdAfx.h"
/*
CSSGateManager::CSSGateManager(CSSManager *lpSSManager)
:Inherited()
{
m_dwReconnectSQLTick = 0;
m_pSSManager = lpSSManager;
m_SQLConnection.SetMultiThread(TRUE);
}
CSSGateManager::~CSSGateManager()
{
}
BOOL CSSGateManager::ConnectSQL()
{
TICKCOUNT nCurrentTick = _getTickCount();
if ( !m_SQLConnection.Connected() )
{
if ( nCurrentTick >= m_dwReconnectSQLTick )
{
if (NULL ==m_pSSManager) return FALSE;
m_pSSManager->SetupSQLConnection(&m_SQLConnection);
if ( m_SQLConnection.Connect() )
{
mysql_options(m_SQLConnection.GetMySql(), MYSQL_SET_CHARSET_NAME, "utf8");
//if (m_SQLConnection.Exec("charset utf8"))
//{
// OutputMsg( rmError, _T("设置utf8字符编码出错"));
//}
//else
//{
// m_SQLConnection.ResetQuery();
//}
return TRUE;
}
OutputMsg( rmError, "连接数据库ip=%s,port=%d失败",
m_SQLConnection.GetServerHost(),m_SQLConnection.GetServerPort());
//如果连接SQL失败则将在5秒后重试
m_dwReconnectSQLTick = _getTickCount() + 5 * 1000;
return FALSE;
}
}
else
{
if( nCurrentTick> m_dwDumpTime)
{
if(m_dwDumpTime )
{
if(m_dwDumpTime)
{
CTimeProfMgr::getSingleton().dump();
}
}
m_dwDumpTime = nCurrentTick + 300000; //5分钟打印一次
}
}
return TRUE;
}
VOID CSSGateManager::ResultUserSessionConfim(const int nSessionId, const BOOL boOnline)
{
CSSGate *pGate;
for ( int i=0; i<ArrayCount(m_Gates); ++i )
{
pGate = &m_Gates[i];
if (pGate && pGate->m_UserList.count() > 0)
{
if ( pGate->ResultGateUserSessionConfim(nSessionId, boOnline) )
{
break;
}
}
}
}
//打开一个session
VOID CSSGateManager::OnResultConformOpenSession(int nSessionId, int nServerIndex)
{
CSSGate *pGate;
for ( int i=0; i<ArrayCount(m_Gates); ++i )
{
pGate = &m_Gates[i];
if (pGate && pGate->m_UserList.count() > 0)
{
if ( pGate->ResultOpenSession(nSessionId,nServerIndex) )
{
break;
}
}
}
}
VOID CSSGateManager::Initialize()
{
int i;
for ( i=0; i<ArrayCount(m_Gates); ++i )
{
m_Gates[i].m_pSQLConnection = &m_SQLConnection;
m_Gates[i].m_pSSManager = m_pSSManager;
//将网关添加到列表
m_GateList[i] = &m_Gates[i];
}
m_dwDumpTime =0;
}
VOID CSSGateManager::Uninitialize()
{
int i;
for ( i=0; i<ArrayCount(m_GateList); ++i )
{
//将网关从列表移除
m_GateList[i] = NULL;
}
}
VOID CSSGateManager::OnResultGateUserExists(int nSessionId, const BOOL boOnline)
{
}
VOID CSSGateManager::DispatchInternalMessage(UINT uMsg, UINT64 uParam1, UINT64 uParam2, UINT64 uParam3, UINT64 uParam4)
{
switch (uMsg)
{
case GTIM_CONFIM_SESSION_RESULT://会话服务器向网关用户投递确认会话是否在线的结果(Param1=会话IDParam2=是否在线(0:1))
ResultUserSessionConfim((int)uParam1, (int)uParam2);
break;
//确认已经打开了会
case GTIM_CONFIRM_OPEN_SESSION:
OnResultConformOpenSession((int)uParam1,(int)uParam2);
break;
default:
Inherited::DispatchInternalMessage(uMsg, uParam1, uParam2, uParam3,uParam4);
break;
}
}
VOID CSSGateManager::OnRun()
{
if ( Started() )
{
ConnectSQL();
}
}
*/

View File

@@ -0,0 +1,44 @@
#ifndef _SS_GATEMANAGER_H_
#define _SS_GATEMANAGER_H_
/*
class CSSManager;
class CSSGateManager
: public CCustomGateManager
{
public:
typedef CCustomGateManager Inherited;
private:
CSSGate m_Gates[MaxGateCount]; //网关列表
CSSManager* m_pSSManager; //所属DBEngine
CSQLConenction m_SQLConnection; //网关数据库连接对象
TICKCOUNT m_dwReconnectSQLTick; //下次重新连接数据库的时间
TICKCOUNT m_dwDumpTime; //写日志的时间
private:
BOOL ConnectSQL();
//确认会话是否在线的结果处理
VOID ResultUserSessionConfim(const int nSessionId, const BOOL boOnline);
protected:
//返回异步查询网关中是否存在指定会话ID的用户的结果
VOID OnResultGateUserExists(int nSessionId, const BOOL boOnline);
//收到了确认opensession的数据包
VOID OnResultConformOpenSession(int nSessionId,int nServerIndex);
//进行内部消息的处理分派
VOID DispatchInternalMessage(UINT uMsg, UINT64 uParam1, UINT64 uParam2, UINT64 uParam3,UINT64 uParam4);
VOID OnRun();
public:
CSSGateManager(CSSManager *lpSSManager);
~CSSGateManager();
VOID Initialize();
VOID Uninitialize();
};
*/
#endif

View File

@@ -0,0 +1,47 @@
#ifndef _SS_GATEUSER_H_
#define _SS_GATEUSER_H_
/**
会话网关用户类
此类不可再继承
**/
class CSSGateUser
: public CCustomServerGateUser
{
public:
typedef CCustomServerGateUser Inherietd;
//网关用户状态
enum eGateUserState
{
guUnavailable = 0, //未登录
guConfimLogin, //正在确认账号是否在线
guLoginOK, //登录成功
guLoginFail, //登录失败
guSelectServer //选择了服务器
};
//检查会话是否在线的最终结果
enum eGateCheckSessionResult
{
crNoResult, //尚未有结果
crOnline, //账号已在线
crNotOnline, //账号不在线,可以登录
crTimedOut, //检查超时
};
public:
INT nUserSessionId; //全局会话ID
int nTodayOnlineSec; //账号今日在线时间,主要用于防沉迷系统
long long nLastLoginIP; //上次登录IP
eGateUserState nUserState; //网关用户状态
eGateCheckSessionResult nCheckSessionResult;//登录确认的结果
TICKCOUNT dwLoginConfimTimeOut; //登录确认超时时间
int nGmLevel; //账户的GM等级
int nServerIndex; //要登陆的服务器的编号
bool bHasReplySelServer; //是否回复了选择服务器,避免重复回复
};
#endif

View File

@@ -0,0 +1,546 @@
#include "StdAfx.h"
//#include "SSManager.h"
CSSManager::CSSManager()
{
m_sServerName[0] = 0;
SetSQLConfig("localhost", 3306, "gamedb", "root", "123456",false);
m_dwQueryCharTimeOut = 30 * 1000;
m_dwEntryGameTimeOut = 30 * 1000;
m_CharGateRouteList.setLock(&m_CharGateRouteListLock);
m_AdministLoginList.setLock(&m_AdministLoginListLock);
m_LogicServerInfoList.setLock(&m_LogicServerInfoLIstLock);
//去掉网关服务器
//m_pGateManager = new CSSGateManager(this);
//m_pGateManager->Initialize();
m_pSessionServer = new CSessionServer(this);
m_pLogClient =new LogSender(jxSrvDef::SessionServer,0,m_sServerName); //创建一个日志服务器的连接对象
m_pAMClient = new CAMClient();
m_pSessionCenter = new CSessionCenter(jxSrvDef::SessionServer,0,m_sServerName,this);
m_pAMClient->SetProductName(_T("djrm"));
m_isFcmOpen = false;
m_nLoginIpLimit =10; //默认10个
m_bCardmd5 =true;
m_spidMd5[0]=0;
m_logIpCount =0;
m_phpTime =180;
m_kickCount =5;
m_gmIpLogin =false;
}
CSSManager::~CSSManager()
{
Shutdown();
//m_pGateManager->Stop();
//m_pGateManager->Uninitialize();
//SafeDelete(m_pGateManager);
SafeDelete(m_pSessionServer);
SafeDelete(m_pLogClient);
SafeDelete(m_pAMClient);
SafeDelete(m_pSessionCenter);
}
VOID CSSManager::ClearRouteList()
{
INT_PTR i;
m_CharGateRouteList.lock();
for ( i=m_CharGateRouteList.count()-1; i>-1; --i )
{
delete m_CharGateRouteList[i];
}
m_CharGateRouteList.clear();
m_CharGateRouteList.unlock();
}
VOID CSSManager::ClearAdministLoginList()
{
INT_PTR i;
m_AdministLoginList.lock();
for ( i=m_AdministLoginList.count()-1; i>-1; --i )
{
delete m_AdministLoginList[i];
}
m_AdministLoginList.clear();
m_AdministLoginList.unlock();
}
VOID CSSManager::SetupSQLConnection(CSQLConenction *lpConnection)
{
lpConnection->SetServerHost(m_sSQLHost);
lpConnection->SetServerPort(m_nSQLPort);
lpConnection->SetDataBaseName(m_sSQLDBName);
lpConnection->SetUserName(m_sSQLUser);
lpConnection->SetPassWord(m_sSQLPassword);
lpConnection->SetConnectionFlags(CLIENT_FOUND_ROWS | CLIENT_MULTI_RESULTS);
lpConnection->SetMultiThread(FALSE);
}
VOID CSSManager::SetServerName(LPCSTR sSrvName)
{
_asncpytA(m_sServerName, sSrvName);
//SetConsoleTitle( sSrvName );
}
VOID CSSManager::SetGateServiceAddress(LPCTSTR sHost, const int nPort)
{
//m_pGateManager->SetServiceHost(sHost);
//m_pGateManager->SetServicePort(nPort);
}
VOID CSSManager::SetSessionServiceAddress(LPCTSTR sHost, const int nPort)
{
m_pSessionServer->SetServiceHost(sHost);
m_pSessionServer->SetServicePort(nPort);
}
VOID CSSManager::SetAMServerAddr(LPCTSTR sHost, const int nPort)
{
m_pAMClient->SetServerHost(sHost);
m_pAMClient->SetServerPort(nPort);
}
//计算hash值
VOID CSSManager::SetSPID(LPCTSTR sName)
{
_asncpyt(m_sSPID, sName);
m_pAMClient->SetSPID(m_sSPID);
//计算一下hash值的md5
char sTotal[128];
_asncpyt(sTotal, sName);
char num[20];
num[0]=0;
INT_PTR nSpguid= m_nSpGuid;
//itoa(nSpguid,num,10); //计算出spguid
sprintf(num,"%d",nSpguid);
strncat(sTotal,num,sizeof(sTotal) );
MD5_CTX ctx;
//使用 MD5加密玩家的密码
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *)sTotal, (unsigned int)strlen(sTotal) );
MD5Final(m_spidMd5,&ctx);
m_spidMd5[32]=0;
OutputMsg(rmTip,"spid=%s,spguid=%s,spguidmd5=%s,sTotal=%s",m_sSPID,num,m_spidMd5,sTotal);
}
VOID CSSManager::SetLogServerAddress(LPCTSTR sHost, const int nPort)
{
m_pLogClient->SetServerHost(sHost);
m_pLogClient->SetServerPort(nPort);
}
VOID CSSManager::SetSQLConfig(LPCSTR sHost, const int nPort, LPCSTR sDBName, LPCSTR sDBUser, LPCSTR sUserPassword,bool isUtf8)
{
_asncpytA(m_sSQLHost, sHost);
m_nSQLPort = nPort;
_asncpytA(m_sSQLDBName, sDBName);
_asncpytA(m_sSQLUser, sDBUser);
_asncpytA(m_sSQLPassword, sUserPassword);
m_bUtf8 = isUtf8;
}
PCHARGATEROUTE getServerRoute(CBaseList<PCHARGATEROUTE> &list, const int nServerIndex)
{
INT_PTR i;
for ( i=list.count()-1; i>-1; --i )
{
if (list[i]->nServerIndex == nServerIndex )
{
return list[i];
}
}
return NULL;
}
INT_PTR CSSManager::LoadCharGateRouteTable()
{
int nRouteCount = 0;
int nValue;
PCHARGATEROUTE pRoute;
MYSQL_ROW pRow;
CBaseList<PCHARGATEROUTE> RouteList;
CSQLConenction sql;
//配置数据库连接
SetupSQLConnection(&sql);
if ( !sql.Connect() )
return -1;
//从数据库加载角色网关路由表
if ( sql.Query( szLoadCharGateRouteTable ) )
{
sql.Disconnect();
return -2;
}
//读取角色网关路由表
pRow = sql.CurrentRow();
while ( pRow )
{
sscanf(pRow[1], "%d", &nValue); //server_id
pRoute = getServerRoute(RouteList, nValue);
if ( !pRoute )
{
pRoute = new CHARGATEROUTE;
ZeroMemory(pRoute, sizeof(*pRoute));
pRoute->nServerIndex = nValue;
RouteList.add(pRoute);
}
if ( pRoute->nRouteCount < ArrayCount(pRoute->RouteTable) )
{
_asncpytA(pRoute->RouteTable[pRoute->nRouteCount].sHost, pRow[2]); //名字
sscanf(pRow[3], "%d", &nValue); //端口
pRoute->RouteTable[pRoute->nRouteCount].nPort = nValue;
OutputMsg( rmNormal, _T("添加路由表Host=%s,port=%d,serverid=%d"),
pRoute->RouteTable[pRoute->nRouteCount].sHost,nValue,pRoute->nServerIndex);
pRoute->nRouteCount++;
nRouteCount++;
}
pRow = sql.NextRow();
}
//断开数据库连接
sql.ResetQuery();
sql.Disconnect();
//将加载的新的角色网关路由数据保存到角色网关路由表中
m_CharGateRouteList.lock();
ClearRouteList();
m_CharGateRouteList.addList(RouteList);
m_CharGateRouteList.unlock();
return nRouteCount;
}
INT_PTR CSSManager::LoadAdministLoginTable()
{
PADMINLOGINRECORD pRecord;
MYSQL_ROW pRow;
CBaseList<PADMINLOGINRECORD> AdministLoginList;
CSQLConenction sql;
//配置数据库连接
SetupSQLConnection(&sql);
if ( !sql.Connect() )
return -1;
//从数据库加载管理员登录表
if ( sql.Query( szLoadAdministLoginTable ) )
{
sql.Disconnect();
return -2;
}
//读取管理员登录表
pRow = sql.CurrentRow();
while ( pRow )
{
pRecord = new ADMINLOGINRECORD;
sscanf(pRow[0], "%d", &pRecord->eRecType);
_asncpytA(pRecord->sRecData, pRow[1]);
AdministLoginList.add(pRecord);
OutputMsg( rmNormal, _T("添加管理员,类型为%d,Name=%s"),pRecord->eRecType,pRecord->sRecData);
pRow = sql.NextRow();
}
//断开数据库连接
sql.ResetQuery();
sql.Disconnect();
//将加载的新的管理员登录数据保存到管理员登录表中
m_AdministLoginList.lock();
ClearAdministLoginList();
m_AdministLoginList.addList(AdministLoginList);
m_AdministLoginList.unlock();
return m_AdministLoginList.count();
}
BOOL CSSManager::SelectCharGateRoute(const INT_PTR nServerIndex, LPSTR lpGateHost, const SIZE_T dwHostLen, PINT lpGatePort)
{
INT_PTR i, nRouteIndex;
BOOL boResult = FALSE;
PCHARGATEROUTE pRoute;
m_CharGateRouteList.lock();
for ( i=m_CharGateRouteList.count()-1; i>-1; --i )
{
pRoute = m_CharGateRouteList[i];
if ( pRoute->nServerIndex == nServerIndex )
{
nRouteIndex = (_getTickCount() / 1000) % pRoute->nRouteCount;
strncpy(lpGateHost, pRoute->RouteTable[nRouteIndex].sHost, dwHostLen-1);
lpGateHost[dwHostLen-1] = 0;
*lpGatePort = pRoute->RouteTable[nRouteIndex].nPort;
boResult = TRUE;
break;
}
}
m_CharGateRouteList.unlock();
return boResult;
}
INT_PTR CSSManager::LoadLogicServerInfoList()
{
INT_PTR nResult = 0;
LOGICSERVERINFO si;
CBaseList<LOGICSERVERINFO> serverList;
CSQLConenction sql;
SetupSQLConnection(&sql);
if (!sql.Connect())
{
OutputMsg(rmError, _T("%s connect sql server failed"), __FUNCTION__);
return -1;
}
if (sql.Query(szLoadServerInfoList))
{
OutputMsg(rmError, _T("%s exec sp[%s] failed"), __FUNCTION__, szLoadServerInfoList);
sql.Disconnect();
return -2;
}
MYSQL_ROW pRow = sql.CurrentRow();
while ( pRow )
{
sscanf(pRow[0], "%d", &si.server_id);
sscanf(pRow[1], "%d", &si.cserver_id);
if (pRow[2])
{
_asncpytA(si.serverName, pRow[2]);
}
else
{
_asncpytA(si.serverName, "Unknown");
}
serverList.add(si);
/*
OutputMsg(rmNormal,
_T("添加服务器信息,[serverid=%d, cserverid=%d, Name=%s"),
si.server_id,
si.cserver_id,
si.serverName);
*/
pRow = sql.NextRow();
nResult++;
}
sql.ResetQuery();
sql.Disconnect();
m_LogicServerInfoList.lock();
m_LogicServerInfoList.clear();
m_LogicServerInfoList.addList(serverList);
// 更新m_CommServerClientList
m_CommServerClientList.Clear();
for (INT_PTR i = 0; i < m_LogicServerInfoList.count(); i++)
{
m_CommServerClientList.AddClient(m_LogicServerInfoList[i].cserver_id, m_LogicServerInfoList[i].server_id);
}
m_CommServerClientList.Trace();
m_LogicServerInfoList.unlock();
return nResult;
}
bool CSSManager::GetLogicServerInfo(const int nServerId, LOGICSERVERINFO &info)
{
m_LogicServerInfoList.lock();
for (INT_PTR i = 0; i < m_LogicServerInfoList.count(); i++)
{
if (nServerId == m_LogicServerInfoList[i].server_id)
{
CopyMemory(&info, &m_LogicServerInfoList[i], sizeof(LOGICSERVERINFO));
return true;
}
}
m_LogicServerInfoList.unlock();
return false;
}
void CSSManager::GetClientLogicServerList(const int nCommServerId, CBaseList<int> &clientList)
{
m_LogicServerInfoList.lock();
CommServerClient *pSC = m_CommServerClientList.GetServerClient(nCommServerId);
if (pSC)
{
clientList.addList(pSC->ClientList);
}
m_LogicServerInfoList.unlock();
}
BOOL CSSManager::IsAdministLogin(LPCSTR sAccount, LPCSTR sIPAddr)
{
INT_PTR i;
BOOL boResult = FALSE;
PADMINLOGINRECORD pRecord;
m_AdministLoginList.lock();
for ( i=m_AdministLoginList.count()-1; i>-1; --i )
{
pRecord = m_AdministLoginList[i];
if ( pRecord->eRecType == ADMINLOGINRECORD::alAccount )
{
if ( _stricmp(pRecord->sRecData, sAccount) == 0 )
{
boResult = TRUE;
break;
}
}
if ( pRecord->eRecType == ADMINLOGINRECORD::alIPAddress )
{
if ( _stricmp(pRecord->sRecData, sIPAddr) == 0 )
{
boResult = TRUE;
break;
}
}
}
m_AdministLoginList.unlock();
return boResult;
}
BOOL CSSManager::Startup()
{
//int nError;
//初始化网络套接字
int nError = CCustomWorkSocket::InitSocketLib();
if ( nError )
{
OutputError( nError, _T("初始化网络库失败") );
return FALSE;
}
//加载角色网关路由表
/*
if ( LoadCharGateRouteTable() < 0 )
{
OutputMsg( rmError, _T("加载角色网关路由表失败"));
return FALSE;
}
*/
//加载管理员登录表
/*
if ( LoadAdministLoginTable() < 0 )
{
OutputMsg( rmError, _T("加载管理员表失败"));
return FALSE;
}
// 加载逻辑服务器信息列表
if (LoadLogicServerInfoList() < 0)
{
OutputMsg(rmError, _T("加载逻辑服务器列表失败"));
}
*/
//启动日志客户端
if ( !m_pLogClient->Startup() )
{
OutputMsg(rmError, _T("启动日志失败"));
return FALSE;
}
if (m_pLogClient)
{
m_pLogClient->SetServerSpid(m_sSPID);
}
if (!m_pAMClient->Startup())
{
OutputMsg(rmError, _T("启动AM失败"));
return FALSE;
}
//启动会话客户端
if ( !m_pSessionServer->Startup() )
{
OutputMsg(rmError, _T("!m_pSessionServer->Startup() 失败"));
return FALSE;
}
//启动网关管理器
//m_pGateManager->Startup();
return TRUE;
}
VOID CSSManager::Shutdown()
{
//停止网关
//m_pGateManager->Stop();
//停止会话客户端
m_pSessionServer->Stop();
//停止日志客户端
m_pLogClient->Stop();
// 关闭AMClient
m_pAMClient->Stop();
if(m_pSessionCenter->connected())
{
m_pSessionCenter->Stop();
}
//销毁角色网关路由表
//ClearRouteList();
//销毁管理员登录列表
//ClearAdministLoginList();
//卸载网络库
//CSSGateManager::UnintSocketLib();
}
VOID CSSManager::UpdateAMC()
{
if (!m_pAMClient) return;
wylib::container::CBaseList<CAMClient::AMOPDATA> msg_list;
INT_PTR msg_count = m_pAMClient->GetAMOPResults(msg_list);
msg_count = __min(msg_count, msg_list.count());
for (INT_PTR i = 0; i < msg_count; i++)
{
m_pSessionServer->PostAMCMsg(msg_list[i]);
}
}
VOID CSSManager::UpdateTask()
{
if (!m_pAMClient) return;
wylib::container::CBaseList<CAMClient::TASKMSG> msg_list;
INT_PTR msg_count = m_pAMClient->GetTaskOPResults(msg_list);
msg_count = __min(msg_count, msg_list.count());
for (INT_PTR i = 0; i < msg_count; i++)
{
m_pSessionServer->PostAMCTaskMsg(msg_list[i]);
}
}

View File

@@ -0,0 +1,369 @@
#ifndef _SS_MANAGER_H_
#define _SS_MANAGER_H_
class CSSGateManager;
class LogSender;
class CSSManager
{
private:
CHAR m_sServerName[128]; //服务器名称
INT_PTR m_nSpGuid; //运营商的整形的ID
char m_sSPID[128]; // 运营商ID
char m_sPhpKey[128]; //php用来计算秘钥的key
bool m_bIsPhpSignCheck; //是否检查php的秘钥
bool m_bOnlyWhitePass; //只要白名单的才能登陆
int m_phpTime; //php时间过期读多久算失效
CHAR m_sSQLHost[128]; //数据库地址
int m_nSQLPort; //数据库端口
CHAR m_sSQLDBName[128]; //数据库名称
CHAR m_sSQLUser[128]; //数据库用户名
CHAR m_sSQLPassword[128];//数据库用户密码
TICKCOUNT m_dwQueryCharTimeOut;//会话查询角色的状态超时
TICKCOUNT m_dwEntryGameTimeOut;//会话进入游戏的状态超时
CSSGateManager *m_pGateManager; //网关管理器
LogSender *m_pLogClient; //日志客户端
CSessionServer *m_pSessionServer; //会话服务器
CAMClient *m_pAMClient; // 金融管理客户端
CSessionCenter *m_pSessionCenter; //会话中心客户端
CLockList<PCHARGATEROUTE> m_CharGateRouteList;//角色网关路由表
CCSLock m_CharGateRouteListLock; //角色网关路由表锁
CLockList<PADMINLOGINRECORD>m_AdministLoginList;//管理员登录列表
CCSLock m_AdministLoginListLock; //角色网关路由表锁
CLockList<LOGICSERVERINFO> m_LogicServerInfoList; // 逻辑服务器信息列表
CommServerClientList m_CommServerClientList; // 公共服务器连接的逻辑服务器列表
CCSLock m_LogicServerInfoLIstLock; // 逻辑服务器信息列表锁
bool m_isFcmOpen; //防沉迷是否开启默认是false表示防沉迷关闭
CBaseList<unsigned long long> m_gmIps; //GM能够登陆的IP
CBaseList<unsigned long long> m_createAccountIps; //能够创建账户的IP列表
CBaseList<unsigned long long> m_blackIps; //禁止的IP列表
CBaseList<unsigned long long> m_whiteIps; //能进去的IP列表
int m_nLoginIpLimit; //获取1个ip最多登陆多少个账户
bool m_bCardmd5; //卡是否用md5自动生成
bool m_bAutoAccount; //自动创建账户
unsigned char m_spidMd5[128]; //spid的md5的值
bool m_bUtf8 ; //是否是utf8编码
int m_logIpCount; //单ip超过了多少个就发消息到日志服去记录下
int m_forbidIpInterval; //封号的IP的间隔
int m_kickCount ; //单ip登陆间隔小于这个则踢
bool m_gmIpLogin; //GM只能在特定的ip登陆
bool m_autoSealIp; //是否自动封IP
bool m_sealAccountSealIp; //是否封账户的登陆了直接封IP
bool m_bCheckServerIndex; //是否密码的是否检测serverid手机这边因为拿不到serverid所以验证的地方要改下
private:
VOID ClearRouteList();
VOID ClearAdministLoginList();
public:
CSSManager();
~CSSManager();
inline LPCSTR getServerName(){ return m_sServerName; };
inline CSSGateManager* getGateManager(){ return m_pGateManager; };
inline LogSender* getLogClient(){ return m_pLogClient; };
inline CSessionServer* getSessionServer(){ return m_pSessionServer; };
inline CAMClient* getAMClient() { return m_pAMClient; }
inline CSessionCenter* getSessionCenter() {return m_pSessionCenter;}
inline TICKCOUNT getSessionQueryCharTimeOut(){ return m_dwQueryCharTimeOut; }
inline TICKCOUNT getSessionEntryGameTimeOut(){ return m_dwEntryGameTimeOut; }
inline bool isFcmOpen(){return m_isFcmOpen;} //防沉迷是否开启
inline void SetFcmOpen(bool flag){m_isFcmOpen =flag;} //设置防沉迷是否开启
inline int GetPhpTime() {return m_phpTime;} //获取php时间
inline void SetPhpTime(int nTime) {m_phpTime= nTime;} //设置php时间
//获取是否需要检测服务器index
inline bool GetCheckServerIndex() { return m_bCheckServerIndex ; }
//获取是否需要检测服务器index
inline void SetCheckServerIndex(bool bFlag) { m_bCheckServerIndex =bFlag; }
//是否使用utf8编码
inline bool IsUtf8(){return m_bUtf8;}
//是否检查php传入的参数
inline bool isCheckPhpSign()
{
return m_bIsPhpSignCheck;
}
//设置是否开启php验证
inline void SetCheckPhpSign(bool flag)
{
m_bIsPhpSignCheck =flag;
}
//读取key
inline void SetPhpKey(char *pStr)
{
_tcscpy(m_sPhpKey,pStr);
}
//获取key
inline char *GetPhpKey()
{
return m_sPhpKey;
}
//获取卡是否开启md5
inline bool GetCardMd5()
{
return m_bCardmd5;
}
//是否是自动账户
inline bool IsAutoAccount()
{
return m_bAutoAccount;
}
//是否是自动封IP的
inline bool IsAutoSealIp()
{
return m_autoSealIp;
}
//设置是否自动封IP
inline void SetAutoSealIp(bool flag)
{
m_autoSealIp = flag;
}
//设置自动账户功能
inline void SetAutoAccount(bool flag)
{
m_bAutoAccount =flag;
}
//设置卡是否开启md5
inline void SetCardMd5(bool bFlag)
{
m_bCardmd5 =bFlag;
}
//返回spid的md5的值
inline unsigned char * GetSpidMd5()
{
return m_spidMd5;
}
//单ip登陆超过多少个就记录日志
inline int GetIpLogCount()
{
return m_logIpCount;
}
//设置单ip的登陆个数
inline void SetIpLogCount(int nCount)
{
m_logIpCount = nCount;
}
//设置gm只能在特定的ip登陆
inline void SetGmIpLogin(bool flag)
{
m_gmIpLogin = flag;
}
//获取GM是否只能在特定的IP登陆
inline bool GetGmIpLogin()
{
return m_gmIpLogin;
}
//设置封账户直接封IP
inline void SetSealAccountSealIp(bool flag)
{
m_sealAccountSealIp = flag;
}
//返回封停账户直接封IP
inline bool GetSealAccountSealIp()
{
return m_sealAccountSealIp;
}
//GM登陆的IP列表
CBaseList<unsigned long long>& GetGmIpList(){return m_gmIps;}
//能够创建账户的ip列表
CBaseList<unsigned long long>& GetCreateAcountIpList(){return m_createAccountIps;}
//黑名ip限制
CBaseList<unsigned long long>& GetBlackIpList(){return m_blackIps;}
//获取白名ip限制
CBaseList<unsigned long long>& GetWhiteIpList(){return m_whiteIps;}
//获取1个ip能够登陆多少个用户
inline int GetIpLoginCount(){return m_nLoginIpLimit;}
//设置1个ip能登陆多少个
inline void SetIpLoginCount(int nCount) {m_nLoginIpLimit =nCount;}
//设置是否只要白名单的才能登陆
inline void SetWhitePass(bool bFlag){ m_bOnlyWhitePass = bFlag ;}
//获取是否只要白名单才能登陆
inline bool GetWhitePass() {return m_bOnlyWhitePass;}
//设置禁止的间隔
inline void SetForbidInterval(int nInterval)
{
m_forbidIpInterval = nInterval;
}
//返回禁止的间隔
inline int GetForbidInterval()
{
return m_forbidIpInterval;
}
//设置禁止的间隔
inline void SetKickCount(int nInterval)
{
m_kickCount = nInterval;
}
//返回禁止的间隔
inline int GetKickCount()
{
return m_kickCount;
}
//配置数据库连接对象
VOID SetupSQLConnection(CSQLConenction *lpConnection);
//依据会话ID关闭连接到网关中的用户
/*
inline VOID PostCloseGateUserBySessionId(const int nSessionId)
{
m_pGateManager->PostCloseGateUserByGlobalSessionId(nSessionId);
}
*/
//会话服务器回应网关用户确认会话是否在线的结果
/*
inline VOID PostGateUserConfimSessionResult(const int nSessionId, const BOOL boOnline)
{
m_pGateManager->PostInternalMessage(GTIM_CONFIM_SESSION_RESULT, nSessionId, boOnline, 0);
}
*/
//网关向SessionServer投递改变会话状态的消息
inline VOID PostChangeSessionState(const int nSessionId, const jxSrvDef::GSSTATE nState)
{
return m_pSessionServer->PostInternalMessage(SSIM_CHANGE_SESSION_STATE, nSessionId, nState, 0);
}
//当网关用户关闭的时候,向会话模块投递用户关闭的消息,以便决定是否应该删除会话
inline VOID PostSessionServerUserClosed(const INT_PTR nSessionId)
{
return m_pSessionServer->PostInternalMessage(SSIM_GATE_USER_CLOSED, nSessionId, 0, 0);
}
//设置服务器名称
VOID SetServerName(LPCSTR sSrvName);
// 设置运营商ID
VOID SetSPID(LPCTSTR sName);
//设置运营商的唯一的编号
inline void SetSpGUID(INT_PTR nguid){m_nSpGuid= nguid;}
//获取运营商的唯一编号
inline INT_PTR GetSPGUID(){return m_nSpGuid;}
// 获取运营商ID
inline char* GetSPID() { return m_sSPID;}
//设置网关服务器的监听地址和端口
VOID SetGateServiceAddress(LPCTSTR sHost, const int nPort);
//设置会话服务器地址和端口
VOID SetSessionServiceAddress(LPCTSTR sHost, const int nPort);
// 设置AMServer服务器地址和端口
VOID SetAMServerAddr(LPCTSTR sHost, const int nPort);
//设置日志服务器地址和端口
VOID SetLogServerAddress(LPCTSTR sHost, const int nPort);
//设置数据库连接配置
VOID SetSQLConfig(LPCSTR sHost, const int nPort, LPCSTR sDBName, LPCSTR sDBUser, LPCSTR sUserPassword,bool bUtf8);
//设置会话查询角色的超时时间
inline VOID SetSessionQueryCharTimeOut(TICKCOUNT dwTimeOutMilSec){ m_dwQueryCharTimeOut = dwTimeOutMilSec; };
//设置会话进入游戏的超时时间
inline VOID SetSessionEntryGameTimeOut(TICKCOUNT dwTimeOutMilSec){ m_dwEntryGameTimeOut = dwTimeOutMilSec; };
//加载角色网关路由表,函数返回加载的路由信息数量
INT_PTR LoadCharGateRouteTable();
//加载管理员登录表,函数返回加载的记录数量
INT_PTR LoadAdministLoginTable();
//为网关用户选择角色网关路由地址选择路由地址成功则返回TRUE并将地址保存在lpGateHost中会添加终止字符将端口保存在lpGatePort中
BOOL SelectCharGateRoute(const INT_PTR nServerIndex, LPSTR lpGateHost, const SIZE_T dwHostLen, PINT lpGatePort);
//判断用户是否属于管理员登录列表中的用户
BOOL IsAdministLogin(LPCSTR sAccount, LPCSTR sIPAddr);
/*
* Comments: 加载逻辑服务器列表信息
* @Return INT_PTR: 返回已经加载的逻辑服务器信息数量
* @Remark: 读取数据库serverinfo表
*/
INT_PTR LoadLogicServerInfoList();
/*
* Comments: 获取指定逻辑服务器配置信息
* Param const int nServerId: 要查询的逻辑服务器ID
* Param LOGICSERVERINFO &info: 返回查询的逻辑服务器信息。这里返回的结果是数据拷贝过的,线程安全
* @Return bool: 如果找到对一个服务器的信息返回true否则返回false
* @Remark:
*/
bool GetLogicServerInfo(const int nServerId, LOGICSERVERINFO &info);
/*
* Comments: 获取连接到指定公共逻辑服务器的普通逻辑服务器ID列表
* Param const int nCommServerId: 公共服务器ID
* Param CBaseList<int> & clientList: 返回连接到nCommServerId公共服务器的普通逻辑服务器列表
* @Return void:
* @Remark:
*/
void GetClientLogicServerList(const int nCommServerId, CBaseList<int> &clientList);
BOOL Startup();
VOID Shutdown();
VOID UpdateAMC();
VOID UpdateTask();
};
#endif

View File

@@ -0,0 +1,264 @@
#ifndef _SS_PROTO_H_
#define _SS_PROTO_H_
//账号状态标志位
/*
enum tagSessionCmd
{
//效验用户名和密码,以及是否能够登陆 角色名称shortString,密码shortString
cLoginSyn = 1,
//选择服务器(erroridShort int)
cSelectServer =2,
//创建一个账户,用于创建账户测试的,账户的名字和密码
cCreateAccount =3,
//效验用户名和密码,以及是否能够登陆的结果 (serveridint)
sLoginAck = 1,
//选择服务器的结果 (serveridint,resshort int,Host: short string, port:short int)
sSelectServer = 2,
//创建一个账户的结果
sCreateAccount =3,
};
*/
/**
全局会话结构
在修改此结构的时候需要注意一下结构大小通过内存池申请的中等包的大小是256字节
如果此结构大于256字节且小于64K则会造成较多的内存浪费
**/
typedef struct tagGameSession
{
Uint64 nSessionID; //会话ID
int nServerIndex; //会话登录的服务器ID
int nIsRawLogin; //是否在原始服务器登录
LONGLONG nIPAddr; //会话登录的IP地址支持IPv6
TICKCOUNT dwSessionTick; //会话建立的时间
jxSrvDef::GSSTATE nState; //会话状态(登录、查询角色还是已经进入游戏)
jxSrvDef::ACCOUNT sAccount; //会话账号
TICKCOUNT dwTimeOut; //会话超时时间(在等待查询角色以及等待进入游戏状态下有效)
int nConfimSrvCount;//确认会话是否登录,需要等待回应的服务器数量
int nGmLevel; //GM等级
UINT64 lKey; //登陆的随机key
}GAMESESSION, *PGAMESESSION;
/**
角色网关路由地址结构
**/
typedef struct tagCharGateRoute
{
int nServerIndex; //服务器ID
int nRouteCount; //路由地址数量
struct
{
char sHost[124]; //服务器地址(客户端支持域名)
int nPort; //服务器端口
} RouteTable[16]; //路由表
}CHARGATEROUTE, *PCHARGATEROUTE;
/**
管理员登录结构
管理员登录不受服务器人员已满的限制且会自动剔除已经在线的会话
**/
typedef struct tagAdminLoginRecord
{
enum eRecordType
{
alAccount = 0, //记录是一个账号
alIPAddress, //记录是一个IP地址
} eRecType;
char sRecData[124]; //如果eRecType为alAccount则表示账号为alIPAddress则表示IP地址
}ADMINLOGINRECORD, *PADMINLOGINRECORD;
/*
** 记录逻辑服务器ID、服务器名称以及连接的公共服务器ID等信息
*/
typedef struct tagLogicServerInfo
{
int server_id; // 服务器ID
int cserver_id; // 连接的公共服务器ID
char serverName[32]; // 服务器名称
}LOGICSERVERINFO, *PLOGICSERVERINFO;
/*
** 定义公共服务器连接的普通逻辑服务器列表
*/
class CommServerClient
{
public:
CommServerClient()
{
}
~CommServerClient()
{
Clear();
}
void Clear()
{
ClientList.trunc(0);
}
void Add(const int nClientServerId)
{
bool bRepeat = false;
for (INT_PTR i = 0; i < ClientList.count(); i++)
{
if (nClientServerId == ClientList[i])
{
OutputMsg(rmError, _T("发现重复的ClientServerId配置[cserverid=%d serverid=%d]"),
cserver_id,
nClientServerId);
bRepeat = true;
break;
}
}
if (!bRepeat)
ClientList.add(nClientServerId);
}
void Trace()
{
//OutputMsg(rmTip, _T("公共服务器[%d]连接的客户端数量为:"), cserver_id, (int)ClientList.count());
for (INT_PTR i = 0; i < ClientList.count(); i++)
{
OutputMsg(rmTip, _T("客户端_%2d服务器ID:%d"), (int)(i+1), (int)ClientList[i]);
}
}
int cserver_id; // 公共服务器ID
CBaseList<int> ClientList; // 连接的客户逻辑服务器ID列表
};
class CommServerClientList
{
public:
~CommServerClientList()
{
Clear();
}
void Clear()
{
for (INT_PTR i = 0; i < m_ClientList.count(); i++)
{
m_ClientList[i].Clear();
}
}
void AddClient(const int nCommServerId, const int nClientServerId)
{
if (nCommServerId == nClientServerId)
return;
CommServerClient *pServerClient = GetServerClient(nCommServerId);
if (!pServerClient)
{
CommServerClient sc;
sc.cserver_id = nCommServerId;
INT_PTR nIdx = m_ClientList.add(sc);
pServerClient = (CommServerClient *)&m_ClientList.get(nIdx);
}
pServerClient->Add(nClientServerId);
}
CommServerClient* GetServerClient(const int nCommServerId) const
{
for (INT_PTR i = 0; i < m_ClientList.count(); i++)
{
if (nCommServerId == m_ClientList[i].cserver_id)
return &m_ClientList[i];
}
return NULL;
}
void Trace()
{
for (INT_PTR i = 0; i < m_ClientList.count(); i++)
{
m_ClientList[i].Trace();
}
}
private:
CBaseList<CommServerClient> m_ClientList;
};
//客户端登录失败错误号
#define LOGINERR_USRNOTEXISTS -1 //用户不存在
#define LOGINERR_PSWDFAILURE -2 //密码错误
#define LOGINERR_USERDISABLED -3 //账号已被禁用
#define LOGINERR_USERNOTAVAILABLE -4 //尚未激活游戏
#define LOGINERR_LOGINLOCKCHECKFAIL -5 //
#define LOGINERR_DISABLELOGINTHISGAME -6 //
#define LOGINERR_ALREADYLOGIN -7
#define LOGINERR_SERVERBUSY -8
#define LOGINERR_LOGINONWAITING -9
#define LOGINERR_INPUT_SECURENUMBER -10
#define LOGINERR_USERFULL -11
/* 网关模块内部消息定义
*******************************************/
#define GTIM_CONFIM_SESSION_RESULT 10001 //会话服务器向网关用户投递确认会话是否在线的结果(Param1=会话IDParam2=是否在线(0:1))
#define GTIM_CONFIRM_OPEN_SESSION 10012 //确认已经打开了会话
/* 会话服务器模块内部消息定义
*******************************************/
#define SSIM_POST_CLOSE_SESSION 20001 //按会话ID关闭会话(Param1=会话ID,Param2=会话连续在线时间(用于防沉迷中统计在线时间))
#define SSIM_USER_EXISTS_OF_SESSION_RESULT 20002 //网关按会话ID检查用户是否存在后向DBSSClient返回的消息(Param1=会话ID,Param2=BOOL)
#define SSIM_CHANGE_SESSION_STATE 20003 //网关向SessionServer投递改变会话状态的消息(Param1=会话ID,Param2=会话状态)
#define SSIM_GATE_USER_CLOSED 20004 //网关向SessionServer投递网关用户已关闭的消息(Param1=会话ID)
#define SSIM_POST_ALL_CLIENT_MSG 20005 //向所有会话服务器的客户端发送消息(Param1=服务器类型,Param2=数据包,Param3=数据包大小)
#define SSIM_CONFIM_SESSION_ONLINE 20006 //确认会话是否在线(Param1=会话ID,Param2=服务器ID)
#define SSIM_CONFIM_SESSION_RESULT 20007 //数据或引擎客户端返回会话是否在线(Param1=会话ID,Param2=是否在线0:1)
#define SSIM_CLOSE_SESSION_BY_ACCOUNT 20008 //通过账号字符串查找并关闭会话(Param1=字符串指针)
#define SSIM_DEBUG_PRINT_SESSIONS 20009 //调试消息:打印全局会话(Param1=会话数量)
#define SSIM_QUERY_YUANBAO_COUNT 20010 // 查询元宝数量
#define SSIM_WITHDRAW_YUANBAO 20011 // 提取元宝
#define SSIM_CLOSE_SESSION_BY_ACCOUNTID 20012 //通过accountid关闭会话
#define SSIM_KICK_ONLINE_CROSSSERVER_ACTOR 20013 //踢掉在线的跨服用户
/* SQL查询语句定义
*******************************************/
// 此处定义各种SQL查询语句使用存储过程调用SQL查询
//加载角色网关路由表(QUERY)
static LPCSTR szLoadCharGateRouteTable = "call loadcharactorserveraddress()";
//加载管理员登录表(QUERY)
static LPCSTR szLoadAdministLoginTable = "call loadadministlogintable()";
// 加载服务器信息列表
static LPCSTR szLoadServerInfoList = "call loadlogicserverinfolist()";
static LPCSTR szUserLoginGetGlobalUser = "call logingetglobaluser(\"%s\")";//用户登录时依据账号查询数据(QUERY)
static LPCSTR szUpdateUserLogin= "call updateGlobaluserLogin(%u,%lu)";
static LPCSTR szUpdateUsernlineTime="call updateGlobaluserOnlineTime(%u,%u)";
static LPCSTR szGetFcmTime= "call getFcmTime(%u)"; //获取防沉迷的时间
static LPCSTR szCreateAccount= "call createglobaluser(\"%s\",\"%s\",\"%s\")"; //创建一个账户,参数为名字,密码和身份证号码
static LPCSTR szSessionLoadUserItem = "call loaduseritem(%u,%u,%d)";//获取角色的活动背包内容,[账户id角色id,serverindex]
static LPCSTR szSessionGetUserItem = "call getuseritem(%u,%u,%lld,%d)";//领取物品[账户id角色id,消息id]
static LPCSTR szSessionDelUserItem = "call deleteuseritem(%lld)";//删除用户的活动背包
static LPCSTR szGetSASeriesInfo = "call getvaseriesinfo(%llu)"; // 查询增值服务器序列号信息
static LPCSTR szDeleteSASeries = "call deletevaseries(%llu, %u, %u, \"%s\")"; // 删除增值序列号
static LPCSTR szDeleteCSRank = "call deletecsrank(%d)"; //删除跨服排行[客户端服务器ID]
static LPCSTR szSaveCsRank = "insert into csrank(actorid,actorname,sex,job,serverindex,value) values"; //更新跨服战力排行[角色ID,服务器ID,职业,战力]
static LPCSTR szLoadCsRank = "call loadcsrank()"; //获取每个职业战力第一名单
#endif

View File

@@ -0,0 +1,681 @@
#include "StdAfx.h"
#include "SessionCenter.h"
CSessionCenter::CSessionCenter(jxSrvDef::SERVERTYPE ServerType,INT ServerIndex,char* ServerName,CSSManager *lpSSManager)
{
m_pSManager = lpSSManager;
this->ServerType = ServerType;
this->ServerIndex = ServerIndex;
strcpy(this->ServerName,ServerName);
this->SetClientName(_T("会话中心服"));
m_pSqlConect = m_pSManager->getSessionServer()->GetSql();
memset(sCommonPaltformIp,0,sizeof(sCommonPaltformIp));
nCommonPort = 0;
}
CSessionCenter::CSessionCenter()
{
this->SetClientName(_T("会话中心服"));
memset(sCommonPaltformIp,0,sizeof(sCommonPaltformIp));
nCommonPort = 0;
m_pSManager = NULL;
m_pSqlConect = 0;
}
CSessionCenter::~CSessionCenter()
{
}
VOID CSessionCenter::OnDispatchRecvPacket(const jxSrvDef::INTERSRVCMD nCmd, CDataPacketReader &inPacket)
{
switch(nCmd)
{
case jxInterSrvComm::SessionServerProto::sReqestPlatformAck: //返回跨平台消息
{
OnRecvRequsetCommonPlat(inPacket);
break;
}
case jxInterSrvComm::SessionServerProto::cLogicCheckPasswd: //校验密码
{
CheckPlatformUserPassword(inPacket);
break;
}
case jxInterSrvComm::SessionServerProto::CTransToCommonPlatform: //请求返回原来服
{
OnReqestRawServer(inPacket);
break;
}
default:
{
break;
}
}
}
VOID CSessionCenter::OnConnected()
{
CDataPacket &pdata = allocProtoPacket(cSendSpid); //分配一个 网络包
pdata << (int)(m_pSManager->GetSPGUID());
flushProtoPacket(pdata);
}
VOID CSessionCenter::SetServerName(LPCTSTR sServerName)
{
_tcsncpy(ServerName, sServerName, ArrayCount(ServerName) - 1);
ServerName[ArrayCount(ServerName) - 1] = 0;
}
jxSrvDef::SERVERTYPE CSessionCenter::getLocalServerType()
{
return ServerType;
}
LPCSTR CSessionCenter::getLocalServerName()
{
return ServerName;
}
int CSessionCenter::getLocalServerIndex()
{
return ServerIndex;
}
void CSessionCenter::OnSendConnectCommonPlatform(LPCTSTR sIp,int nPort)
{
if(sIp == NULL) return;
_asncpyt(sCommonPaltformIp, sIp);
nCommonPort = nPort;
if(connected())
{
if(sCommonPaltformIp && sIp && strcmp(sCommonPaltformIp,sIp)==0 && nPort > 0 && nPort == nCommonPort) return;
SetServerHost(sCommonPaltformIp);
SetServerPort(nCommonPort);
if(nCommonPort >0)
{
Inherited::Startup();
}
}
else
{
SetServerHost(sCommonPaltformIp);
SetServerPort(nCommonPort);
if(nCommonPort >0)
{
Inherited::Startup();
}
}
}
void CSessionCenter::OnRequesTranCommonPlatform(CDataPacketReader &inPacket)
{
unsigned int nAccountId = 0, nActorId = 0;
int nServerIndex = 0,nDestServerId = 0, nType = 0;
inPacket >> nDestServerId >> nAccountId >> nActorId;
inPacket >> nServerIndex >> nType;
//nServerIndex = MAKELONG(nServerIndex,m_pSManager->GetSPGUID()) //spgid为服务器的高字节
CDataPacket &pdata = allocProtoPacket(jxInterSrvComm::SessionServerProto::CTransToCommonPlatform); //分配一个 网络包
pdata << (int)nDestServerId << (int)nServerIndex;
pdata << (unsigned int)nAccountId << (unsigned int)nActorId;
pdata << (int)nType;
flushProtoPacket(pdata);
}
void CSessionCenter::OnRecvRequsetCommonPlat(CDataPacketReader &inPacket)
{
int nServerIndex = 0;
inPacket >> nServerIndex;
//nServerIndex = LOWORD(nServerIndex);
m_pSManager->getSessionServer()->OnSendPlatformResultToClient(nServerIndex,inPacket);
}
//判断是否可以返回原来服
void CSessionCenter::OnReqestRawServer(CDataPacketReader &inPacket)
{
unsigned int nAccountId = 0, nActorId = 0;
int nServerIndex = 0,nDestServerId = 0, nType = 0;
inPacket >> nDestServerId >> nAccountId >> nActorId;
inPacket >> nServerIndex >> nType;
nDestServerId = LOWORD(nDestServerId);
int nResult = 0;
if (m_pSManager->getSessionServer() && m_pSManager->getSessionServer()->UserCanLoginToServer(nDestServerId) == 0)
{
nResult = 1;
}
CDataPacket &pdata = allocProtoPacket(jxInterSrvComm::SessionServerProto::sReqestPlatformAck);
pdata << (unsigned int)nActorId << (BYTE)jxInterSrvComm::SessionServerProto::neSuccess;
pdata << (unsigned int)nAccountId << (int)nDestServerId << (int)nResult << (int)nType;
flushProtoPacket(pdata);
}
//检测用户名密码
VOID CSessionCenter::CheckPlatformUserPassword(CDataPacketReader &reader)
{
BYTE len =0;
TCHAR name[ACCOUNT_NAME_BUFF_LENGTH];
TCHAR passwd[MAX_PASSWD_LENGTH];
int nLoginServerId =0; // 要登陆的服务器的编号
int nRawServerId =0; // 源的服务器的编号
int nGateIndex =0; //这个玩家在哪个
UINT64 lKey =0;
reader >> lKey ;
unsigned long long lIp =0; //玩家登陆的ip
reader.readString(name,sizeof(name));
reader.readString(passwd,sizeof(passwd));
reader >> nLoginServerId >> nRawServerId >>nGateIndex ; //要登陆的服务器,以及原始的服务器,在网关的编号
reader >> lIp;
TCHAR md5[128];
TCHAR currentTime[32];
TCHAR identity[64]; //身份证号码
md5[0]=0; //md5的值
currentTime[0] =0; //当前的时间
identity[0] =0; //身份证号码
BYTE bCheck =0;
reader >>bCheck;
//if(bCheck) //如果需要
{
}
if( reader.getAvaliableLength() >0 )
{
reader.readString( md5,sizeof(md5) -1);
}
if( reader.getAvaliableLength() >0 )
{
reader.readString( currentTime,sizeof(currentTime)-1);
}
if( reader.getAvaliableLength() >0)
{
reader.readString( identity,sizeof(identity)-1); //读取身份证号码
}
/*
enPasswdError =1, //密码错误
enNoAccount=2, //没有这个账号
enIsOnline =3, //已经在线
enServerBusy =4, //服务器忙
enServerClose =5, //服务器没有开放
enSessionServerError =6 , //session服务器有问题比如db没有连接好
enServerNotExisting =7, //不存在这个服务器
enFcmLimited =8 , //账户纳入防沉迷
enSessionServerClose =9, //会话服务器处于关闭状态
enDbServerClose =10, //数据服务器处于关闭状态
enGMLoginFailError =11, //gm在非法的ip登陆
*/
GLOBALSESSIONOPENDATA sessionData;// 玩家的登陆的账户
sessionData.nClientIPAddr = lIp;
bool isLoginCommonSrv = (nRawServerId == nLoginServerId); //是否在普通服登陆
bool isWhiteIpLogin =false;
int nErrorID = CheckPlatformUserValid(name,passwd,sessionData,md5,currentTime,bCheck?true:false,isLoginCommonSrv,identity,isWhiteIpLogin);
if(nErrorID)
{
static char* s_erroMsg[]=
{
"NoError",
"password error",
"No such account",
"is Real Online",
"Server busy",
"Server close",
"Session Server Error",
"Server Not exist ",
"Fcm Limited ",
"Session Server Closeed",
"Db Server Close",
"gm login in invalid ip",
"ip forbid login",
"ip login too many",
"md5 error",
"php time is expired",
"time format error",
"Account Seal",
};
static int s_nErrorCount =ArrayCount(s_erroMsg);
if(nErrorID < s_nErrorCount)
{
char *sIp =inet_ntoa(*((in_addr*)&lIp)); //这个是IP
OutputMsg( rmWaning, _T("CheckPlatformUserValid name=%s,pw=%serrorcode=%d,errormsg=%s,serverid=%d,ip=%s"),name, passwd,nErrorID,s_erroMsg[nErrorID],nLoginServerId,sIp);
if(( nErrorID ==enIpMd5Error || nErrorID == enSignOutofDate || nErrorID == enTimeFormatError)&&
md5[0] != 0 && currentTime[0] !=0)
{
OutputMsg(rmWaning, _T("md5=%s,time=%s"),md5,currentTime );
}
}
//pSSGateUser->nUserState = CSSGateUser::guLoginFail;//登陆失败
//ResponseUserLoginState(pSSGateUser,nErrorID); //如果不成功,可以告诉客户端现在的错误码了
//如果失败了,则向客户端发一个消息,登陆失败了
CDataPacket &out = allocProtoPacket(jxInterSrvComm::SessionServerProto::sCheckPasswdResult);
out << int (nGateIndex); //1字节的结果
out << (Uint64)lKey;
out << BYTE (nErrorID); //1字节的结果
flushProtoPacket(out);
//如果登陆的IP特别多则进行自动封号和封账户处理 (跨平台不处理)
OutputMsg(rmTip,_T("[Login] 验证账号失败 AccountName(%s), CurrentThreadId(%d)。"),name,GetCurrentThreadId());
}
else //成功了要做进一步的检测,检测是否已经登录过了,等等,这里可以做顶号的处理
{
sessionData.nServerIndex = nLoginServerId; //当前登陆的服务器id
GAMESESSION cuRuentSession;
//如果当前存在一个会话,那么就发消息去删除这么一条消息
//如果在本服登陆,并且在跨服登陆,先踢下跨服的账户
//if(nRawServerId == nLoginServerId) //如果是在普通服登陆
//{
// //把公共服的踢掉
// if( m_pSSServer->GetSpecialServerSession(sessionData.nSessionId,m_nCommServerId))
// {
// OutputMsg(rmTip,"Kick cross server actor,accountid=%d,serverindex=%d",(int)sessionData.nSessionId,(int)m_nCommServerId);
// m_pSSServer->PostKickCrossActor(sessionData.nSessionId,m_nCommServerId);
// }
//}
int nSrcSrv = LOWORD(nRawServerId);
if ( m_pSManager->getSessionServer()->GetSession( sessionData.nSessionId ,&cuRuentSession,nSrcSrv) )
{
m_pSManager->getSessionServer()->PostCloseSessionByAccountId(sessionData.nSessionId,cuRuentSession.lKey);
}
m_pSManager->getSessionServer()->PostOpenSession(nLoginServerId,nRawServerId,sessionData.sAccount,
sessionData.nSessionId,sessionData.nClientIPAddr,sessionData.dwFCMOnlineSec,sessionData.nGmLevel,lKey,nGateIndex,isWhiteIpLogin,true);
OutputMsg(rmTip,_T("[Login] 验证账号成功 AccountName(%s), CurrentThreadId(%d)。"),name,GetCurrentThreadId());
}
}
int CSessionCenter::CheckPlatformUserValid(PCHAR name, PCHAR passwd,GLOBALSESSIONOPENDATA & sessiDonata,PCHAR md5,PCHAR sCurrentTime,bool checkMd5,bool bCommonSrvLogin,PCHAR iIndentity,bool &isWhiteIpLogin)
{
if (m_pSqlConect ==NULL || m_pSqlConect->Connected() ==FALSE)
{
OutputMsg( rmError, "无法连接数据库");
return enSessionServerError;
}
int nColumnCount =0;
int nRowCount =0;
char sSqlStr[512];
static bool bPhpCheck = m_pSManager->isCheckPhpSign(); //是否要监测php的秘钥
static char * sPguid = m_pSManager->GetSPID(); //获取用户的spguid
static char * sKey = m_pSManager->GetPhpKey(); //获得这个php的key
char sServerId[24];
sprintf(sServerId,"%d",sessiDonata.nRawServerId);
//是不是通过白名单的IP登陆的
isWhiteIpLogin =false;
int nResult = enSuccess;
unsigned long long lLoginIp =sessiDonata.nClientIPAddr; //登陆的ip
bool isWhite =false; //是否在白名单中
CBaseList<unsigned long long > &whiteips = m_pSManager->GetWhiteIpList();
bool flag =false;
if(whiteips.count() >0)
{
//判断是否在合法的ip范围里
for(INT_PTR i=0;i < whiteips.count(); i++)
{
if(whiteips[i]== lLoginIp)
{
isWhite =true;
isWhiteIpLogin =true;
break;
}
}
}
//进行校验才进行验证
if(!isWhite && bPhpCheck && checkMd5 && bCommonSrvLogin ) //如果开启了监测php的并且需要兼容一起的版本
{
//这里发生了错误
if(sCurrentTime ==NULL || sCurrentTime[0]==0 )
{
nResult = enTimeFormatError;
}
else
{
size_t nNumLen = strlen(sCurrentTime);
for(size_t j=0; j< nNumLen; j++)
{
if(sCurrentTime[j] > '9' || sCurrentTime[j] <'0')
{
nResult = enTimeFormatError;
break;
}
}
}
if(!nResult)
{
if( md5==NULL || md5[0] ==0)
{
nResult = enIpMd5Error;
}
}
if( !nResult )
{
char buff[1024];
strcpy(buff,sCurrentTime);
strcat(buff,sServerId); //数字化的服务器的id
strcat(buff,sPguid); //spguid
strcat(buff,name);
strcat(buff,sKey);
unsigned char mdkey[64];
MD5_CTX ctx;
//使用 MD5加密玩家的密码
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *)buff, (unsigned int)strlen(buff) );
MD5Final(mdkey,&ctx);
mdkey[32]=0;
if( strcmp(md5,(char*)mdkey) != 0 )
{
OutputMsg(rmError,"Local raw string=%s,md5 error",buff);
nResult = enIpMd5Error; //md5错误了
}
else
{
unsigned int nCurrentTime = strtoul(sCurrentTime,NULL,10);
time_t sSrvTime;
//struct tm * timeInfo;
time(&sSrvTime); //取了当前的时间
unsigned int nDif = (unsigned int)(abs(sSrvTime -nCurrentTime)); //服务器的时间减去传入的时间
static unsigned int s_timeDif = m_pSManager->GetPhpTime(); //获取php的时间
if(nDif > s_timeDif) //如果超过了3分钟
{
OutputMsg(rmError,"%s login ,time dif=%u seconds",name,nDif);
nResult = enSignOutofDate; //md5错误了
}
}
}
}
//////////////////下面判断是否在合法的ip里访问了
bool bWhitePass = m_pSManager->GetWhitePass(); //是否只要白名单的才能通过
if(bWhitePass && isWhite ==false)
{
nResult =enIpError;
}
//如果在白名单中,则不需要判断,否则需要判断是否在黑名单中
if(!nResult && !isWhite )
{
CBaseList<unsigned long long > &blackips = m_pSManager->GetBlackIpList();
bool flag =false;
if(blackips.count() >0)
{
//判断是否在合法的ip范围里
for(INT_PTR i=0;i < blackips.count(); i++)
{
if(blackips[i] == lLoginIp)
{
flag =true;
break;
}
}
}
if(flag)
{
nResult =enIpError;
}
else
{
//判断登陆的个数是否超过了限制
//int nLoginLimitCount= m_pSSServer->GetLoginAccountCount(lLoginIp);
//if(nLoginLimitCount > pMgr->GetIpLoginCount())
//{
// //nResult =enIpTooManyConnect;
// OutputMsg(rmTip,"IP=%s,connect count=%d,limit=%d",
// inet_ntoa(*((in_addr*)&lLoginIp)),nLoginLimitCount,(int) pMgr->GetIpLoginCount());
// nResult =enIpTooManyConnect;
//}
}
}
if(nResult) return nResult; //先做下判断,如果超过了,直接不让注册,避免数据库大量垃圾数据
if(m_pSManager->IsAutoAccount())
{
char *sIndentity = NULL;
if(iIndentity != NULL && iIndentity[0] !=0)
{
sIndentity = iIndentity;
}
else
{
sIndentity="000000198010100000";
}
sprintf(sSqlStr,"call djimportspuser(\"%s\",\"%s\",%d,\"%s\"),%lld",name,passwd,sServerId,sIndentity, lLoginIp);
if(nResult != enSuccess)
{
return nResult;
}
//先都调用一下
if( m_pSqlConect->RealQuery( sSqlStr,strlen(sSqlStr) ) )
{
OutputMsg( rmError, "数据库执行sql操作%s失败",sSqlStr);
nResult = enSessionServerError;
return nResult;
}
else
{
m_pSqlConect->ResetQuery();
}
}
//__try
{
_snprintf(sSqlStr,sizeof(sSqlStr),szUserLoginGetGlobalUser,name);
unsigned int nAccountId = 0; //账户的ID
if ( m_pSqlConect->RealQuery( sSqlStr,strlen(sSqlStr) ) )
{
OutputMsg( rmError, "数据库执行sql操作%s失败",sSqlStr);
nResult = enSessionServerError;
}
else
{
nColumnCount = m_pSqlConect->GetFieldCount(); //获取列数
nRowCount = m_pSqlConect->GetRowCount(); //获取行数
//读取角色网关路由表
//OutputMsg( rmTip, _T("Read user data from Db"),sSqlStr);
MYSQL_ROW pRow = m_pSqlConect->CurrentRow();
if ( pRow && nRowCount >=1 )
{
if(pRow[0] && nColumnCount >=1)
{
sscanf(pRow[0], "%u", &nAccountId); //账户名字
}
TCHAR sDbPasswd[ACTOR_NAME_BUFF_LENGTH];
if(pRow[1] && nColumnCount >=2)
{
_asncpytA(sDbPasswd,pRow[1]);
}
else
{
sDbPasswd[0] ='\0';
}
if (!isWhite && 0 != strcmp(sDbPasswd,passwd) )
{
OutputMsg( rmError, "%sdbpasswd=%s,inputwd=%s",name,sDbPasswd,passwd);
if(sDbPasswd[0] =='@')
{
nResult =enAccountSeal; //账户被封停
}
else
{
nResult = enPasswdError;
}
}
else
{
//OutputMsg( rmNormal, "%s密码确认成功,accountID =%d",name,nActorId);
strncpy(sessiDonata.sAccount,name,sizeof(sessiDonata.sAccount));
sessiDonata.nSessionId = nAccountId;
if(pRow[6] && nColumnCount >=7)
{
sscanf(pRow[6], "%d", &sessiDonata.nGmLevel);
}
else
{
sessiDonata.nGmLevel = 0;
}
bool flag = m_pSManager->GetGmIpLogin(); //是否限制了IP登陆
//GM登陆需要判断是否是在合法的ip范围里登陆
if(sessiDonata.nGmLevel >0 && flag )
{
//获得ip列表
CBaseList<unsigned long long > &ips = m_pSManager->GetGmIpList();
bool isGMinvalid =false;
//判断是否在合法的ip范围里
for(INT_PTR i=0;i < ips.count(); i++)
{
if(ips[i]== lLoginIp)
{
isGMinvalid =true;
break;
}
}
if(!isGMinvalid)
{
nResult =enGMLoginFailError;
}
}
}
}
else
{
//OutputMsg(rmWaning,_T("No Account %s Found on db"),name);
nResult = enNoAccount;
}
m_pSqlConect->ResetQuery();
}
if(nResult == enSuccess)
{
//只要在防沉迷关闭的时候才去判断防沉迷的时间,否则不判断
if(m_pSManager->isFcmOpen() )
{
int nTime = -1;
char sSqlStr[200];
sprintf(sSqlStr,szGetFcmTime,nAccountId);
if ( m_pSqlConect->RealQuery( sSqlStr, strlen(sSqlStr)) )
{
OutputMsg( rmError, "数据库执行sql操作%s失败",sSqlStr);
nTime = -1;
}
else
{
MYSQL_ROW pRow = m_pSqlConect->CurrentRow();
nColumnCount = m_pSqlConect->GetFieldCount(); //获取列数
nRowCount = m_pSqlConect->GetRowCount(); //获取行数
if ( pRow && nColumnCount >=1 && nRowCount >=1 )
{
sscanf(pRow[0], "%d", &nTime);
}
m_pSqlConect->ResetQuery();
}
sessiDonata.dwFCMOnlineSec = nTime;
}
else //否则全部的玩家都纳入防沉迷
{
sessiDonata.dwFCMOnlineSec =-1;
}
}
}
//__except( CustomExceptHandler(GetExceptionInformation() ))
{
//OutputMsg(rmError,"ACCOUNT=%s",name);
//return nResult;
}
return nResult;
}
int CSessionCenter::SendSSCommonMsg(const int nServerIndex, LPCSTR sMsg, const size_t dwSize)
{
AppendSendBuffer(sMsg, dwSize );
return 0;
}

View File

@@ -0,0 +1,84 @@
#ifndef _CENTER_SENDER_H_
#define _CENTER_SENDER_H_
//跨平台连接会话中心服
//与会话中心服消息定义
typedef enum eCommonSessionMsgCmd
{
cSendSpid = 50, //发送spgid给会话中心服
cRequestTranPlatform = 2, //请求跨平台
sRecvRequsestPlatform = 1, //收到返回请求跨平台消息
};
//class CNetworkDataHandler;
class CCustomJXClientSocket;
class CSSManager;
class CSessionCenter:
public CCustomJXClientSocket
{
public:
CSessionCenter();
CSessionCenter(jxSrvDef::SERVERTYPE ServerType,INT ServerIndex,char* ServerName,CSSManager *lpSSManager);
~CSessionCenter();
VOID SetServerName(LPCTSTR sServerName);
//连接会话中心服
void OnSendConnectCommonPlatform(LPCTSTR sIp,int nPort);
//发送给会话中心判断是否可以跨服
void OnRequesTranCommonPlatform(CDataPacketReader &inPacket);
//收到回话中心服返回是否可以跨服的消息
void OnRecvRequsetCommonPlat(CDataPacketReader &inPacket);
//跨平台登陆检查用户密码
void CheckPlatformUserPassword(CDataPacketReader &reader);
int CheckPlatformUserValid(PCHAR name, PCHAR passwd,GLOBALSESSIONOPENDATA & sessiDonata,PCHAR md5,PCHAR sCurrentTime,bool checkMd5,bool bCommonSrvLogin,PCHAR iIndentity,bool &isWhiteIpLogin);
//向指定ID的逻辑户端发送消息消息将被立刻追加到客户端发的发送缓冲中。数据包必须是完成的格式包含包头和包尾
int SendSSCommonMsg(const int nServerIndex, LPCSTR sMsg, const size_t dwSize);
//请求返回原来逻辑服
void OnReqestRawServer(CDataPacketReader &reader);
protected:
/*** 子类需覆盖的函数集 ***/
/* 处理单个通信数据包
* nCmd 通信消息命令
* inPacket 已经读取出通信命令的数据包,数据包的读取位置指向命令数据后的内容
*/
virtual VOID OnDispatchRecvPacket(const jxSrvDef::INTERSRVCMD nCmd, CDataPacketReader &inPacket);
/*** 下列函数为子类可能有必要覆盖的函数集 ***/
/* ★查询本地服务器的类型,以便正确的发送注册数据 */
virtual jxSrvDef::SERVERTYPE getLocalServerType();
/* ★查询本地服务器的名称,以便正确的发送注册数据 */
virtual LPCSTR getLocalServerName();
/* ★查询本地服务器ID以便正确的发送注册数据默认的返回值是0 */
virtual int getLocalServerIndex();
//提供向最外层逻辑通知连接建立的事件
virtual VOID OnConnected();
private:
jxSrvDef::SERVERTYPE ServerType; //服务器类型值为SERVERTYPE枚举类型中的枚举值
INT ServerIndex; //服务器唯一编号(服务器编号仅对游戏服务器有意义)
CHAR ServerName[128]; //服务器名称需包含0终止符
char sCommonPaltformIp[64]; //连接中心会话服的ip
int nCommonPort; //连接中心会话服的端口
CSSManager* m_pSManager; //所属会话管理器
CSQLConenction* m_pSqlConect; //数据库连接程序
};
#endif

View File

@@ -0,0 +1,88 @@
#include "StdAfx.h"
using namespace jxSrvDef;
using namespace jxInterSrvComm;
CSessionCenterClient::CSessionCenterClient()
{
SetClientName(_T("SessionCenterClient"));
m_vFreeList.setLock(&m_vFreeListLock);
}
CSessionCenterClient::~CSessionCenterClient()
{
m_vFreeList.flush();
for (INT_PTR i = 0; i < m_vFreeList.count(); i++)
{
CDataPacket* dp = m_vFreeList[i];
dp->setPosition(0);
flushSendPacket(*dp);
}
m_vFreeList.clear();
}
VOID CSessionCenterClient::DispatchInternalMessage(UINT uMsg, UINT64 uParam1, UINT64 uParam2, UINT64 uParam3, UINT64 uParam4)
{
}
VOID CSessionCenterClient::OnDispatchRecvPacket(const jxSrvDef::INTERSRVCMD nCmd, CDataPacketReader &inPacket)
{
}
void CSessionCenterClient::HandleLogicRequest(CDataPacketReader &inPacket)
{
}
SERVERTYPE CSessionCenterClient::getLocalServerType()
{
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!修改
return DBServer;
}
int CSessionCenterClient::getLocalServerIndex()
{
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!修改
return 1;
}
LPCSTR CSessionCenterClient::getLocalServerName()
{
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!修改
return "";
}
CDataPacket* CSessionCenterClient::AllocSendPacket()
{
if (m_vFreeList.count() <= 0)
{
m_vFreeList.flush();
}
if (m_vFreeList.count() <= 0)
{
allocSendPacketList(m_vFreeList,512);
}
CDataPacket* m_TempData = m_vFreeList.pop();
m_TempData->setLength(0);
return m_TempData;
}
void CSessionCenterClient::FreeBackUserDataPacket(CDataPacket *pPacket)
{
m_vFreeList.append(pPacket);
}

View File

@@ -0,0 +1,83 @@
#ifndef SESSION_CENTER_CLIENT_H_
#define SESSION_CENTER_CLIENT_H_
/*
连接DBCenter的Client封装类。
*/
class CSessionCenterClient : public CCustomJXClientSocket,
public CSessionDataHandle
{
public:
typedef CCustomJXClientSocket Inherited;
public:
CSessionCenterClient();
virtual ~CSessionCenterClient();
/*
* Comments: 回收空闲的CDataPacket类
* Param CDataPacket * pPacket:
* @Return void:
* @Remark: CommonClient收到来自CommonServer的数据包之后本地分配数据包对象将内容缓存起来然后通过逻辑线程处理。
逻辑线程处理完数据后,调用此接口释放数据包对象。
*/
void FreeBackUserDataPacket(CDataPacket* pPacket);
virtual CDataPacket& AllocDataPacket(const jxSrvDef::INTERSRVCMD nCmd)
{
return allocProtoPacket(nCmd);
}
void FlushDataPacket(CDataPacket &packet)
{
return flushProtoPacket(packet);
}
protected:
////////////////////////////////////////////////////////////////////////////////////////////////////
// Virtual Function Of CCustomJXClientSocket
virtual LPCSTR getLocalServerName();
virtual jxSrvDef::SERVERTYPE getLocalServerType();
//TODO. 临时测试用。DBServer不需要这个而是需要自己维护DB连接的逻辑服务器ID的列表
virtual int getLocalServerIndex();
virtual VOID OnDispatchRecvPacket(const jxSrvDef::INTERSRVCMD nCmd, CDataPacketReader &inPacket);
virtual VOID DispatchInternalMessage(UINT uMsg, UINT64 uParam1, UINT64 uParam2, UINT64 uParam3, UINT64 uParam4);
/*
* Comments: 处理DBCenter转发的逻辑请求。
* Param CDataPacketReader & inPacket:
* @Return void:
* @Remark:
*/
void HandleLogicRequest(CDataPacketReader &inPacket);
/*
* Comments: 分配数据包,用于存储接收到的数据
* @Return CDataPacket*:
* @Remark: 接收线程接收到数据并非立即处理,而是缓存起来,交给逻辑线程统一处理
*/
CDataPacket* AllocSendPacket();
private:
static const int DBC_INTERNAL_UPDATECLIENTLIST = 101; // 更新连接的逻辑客户端列表内部消息
private:
CSQLConenction *m_pSQLConn;
CQueueList<CDataPacket*> m_vFreeList;
CCSLock m_vFreeListLock;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
#ifndef _SESSION_CLIENT_H_
#define _SESSION_CLIENT_H_
using namespace wylib::sync::lock;
class CSSManager;
class CSessionServer;
#include "AMProcto.h"
#include "AMClient_tx.h"
/************************************************************
*
* 数据引擎连接到会话服务器的客户端类
*
***********************************************************/
using namespace jxSrvDef;
class CSessionClient
: public CCustomJXServerClientSocket,
public CSessionDataHandle
{
friend class CSessionServer;
public:
typedef CCustomJXServerClientSocket Inherited;
typedef CSessionDataHandle InHandle;
static const size_t MaxSSDataSize = 4096;//向会话服务器发送的单个数据包大小的最大值
typedef VOID (CSessionClient::*OnHandleSockPacket)(CDataPacketReader &packet);
static const size_t MaxForwardLogicDataSize = 40960; // 最大数据包为40k
//大型SQL查询语句缓冲长度
static const SIZE_T dwHugeSQLBufferSize = 1024 * 1024 * 2;
private:
TICKCOUNT m_dwDisconnectedTick;//断开连接的时间
protected:
//VOID ProcessRecvBuffers(PDATABUFFER pDataBuffer);
VOID DispatchRecvMsg(CDataPacketReader & reader);
//实现虚接口
VOID OnDispatchRecvPacket(const jxSrvDef::INTERSRVCMD nCmd, CDataPacketReader &inPacket);
bool OnValidateRegData(const jxSrvDef::PSERVER_REGDATA pRegData) ;
virtual void OnRegDataValidated();
protected:
VOID OnDisconnected();
VOID OnError(INT errorCode);
//覆盖父类例行执行的函数
VOID OnRun();
//由SessionServer调用的例行执行函数
inline VOID Run(){ SingleRun(); }
protected:
//重写收 发包的函数
virtual CDataPacket& AllocDataPacket(const jxSrvDef::INTERSRVCMD nCmd)
{
return Inherited::allocProtoPacket(nCmd);
}
virtual void FlushDataPacket(CDataPacket &packet)
{
return Inherited::flushProtoPacket(packet);
}
public:
CSessionClient(){}
~CSessionClient()
{
}
//反馈是否可以跨平台的消息给逻辑服
void OnSendReqCommonPlatformResult(CDataPacketReader &inPacket);
};
#endif

View File

@@ -0,0 +1,30 @@
#ifndef LOGIC_SESSION_REQUEST_HOST_INTERFACE_H
#define LOGIC_SESSION_REQUEST_HOST_INTERFACE_H
/*
逻辑DB请求处理容器接口。派生类需要实现分配数据包对象和发送数据包接口用于
处理DB请求后给逻辑回的处理结果应答。
*/
class ISessionRequestHost
{
public:
/*
* Comments: 分配数据包
* Param const jxSrvDef::INTERSRVCMD nCmd:
* @Return CDataPacket&:
* @Remark:
*/
virtual CDataPacket& AllocDataPacket(const jxSrvDef::INTERSRVCMD nCmd) = 0;
/*
* Comments: 刷新数据包到发送队列
* Param CDataPacket &packet
* @Return void:
* @Remark:
*/
virtual void FlushDataPacket(CDataPacket &packet) = 0;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,268 @@
#ifndef _SESSION_HANDLE_H_
#define _SESSION_HANDLE_H_
using namespace wylib::sync::lock;
class CSSManager;
class CSessionServer;
#include "AMProcto.h"
#include "AMClient_tx.h"
/************************************************************
*
* 数据引擎连接到会话服务器的客户端类
*
***********************************************************/
using namespace jxSrvDef;
class CSessionDataHandle :
public ISessionRequestHost
{
friend class CSessionServer;
public:
static const size_t MaxSSDataSize = 4096;//向会话服务器发送的单个数据包大小的最大值
typedef VOID (CSessionDataHandle::*OnHandleSockPacket)(CDataPacketReader &packet);
static const size_t MaxForwardLogicDataSize = 40960; // 最大数据包为40k
//大型SQL查询语句缓冲长度
static const SIZE_T dwHugeSQLBufferSize = 1024 * 1024 * 2;
char *m_pForwardDataBuff; // 公共逻辑服务器SessionClient用于转发公共服务器消息的Buff长度固定MaxForwardLogicDataSize
private:
int m_nCommServerId; // 公共逻辑服务器Id如果自己是公共服务器那么此ID设置为0
int m_nSelfServerId; //自身的服务器ID,用于数据转发
INT m_nUserCount; //在线人数
INT m_nUserLimit; //人数上限
INT m_nMaxUserCount; //在本次日志记录中的最高在线人数记录人数日志后此值被还原为m_nUserCount
CSessionServer* m_pSSServer; //所属会话服务器
CSQLConenction* m_pSQLConnection; //数据库连接程序
TICKCOUNT m_dwDisconnectedTick;//断开连接的时间
PCHAR m_pHugeSQLBuffer; //大型SQL查询语句缓冲长度为dwHugeSQLBufferSize
char m_sTrServerIndex[24] ; //格式化的服务器的index用于连接的时候快速计算
bool m_bIsCrossSession; //是否是跨服的会话传输的client跨服的会话有些东西要特殊处理下
protected:
//VOID ProcessRecvBuffers(PDATABUFFER pDataBuffer);
VOID DispatchRecvMsg(CDataPacketReader & reader);
//VOID SendKeepAlive();
//实现虚接口
VOID OnPacket(const jxSrvDef::INTERSRVCMD nCmd, CDataPacketReader &inPacket);
protected:
/*
* Comments: 分配数据包
* Param const jxSrvDef::INTERSRVCMD nCmd:
* @Return CDataPacket&:
* @Remark:
*/
//virtual CDataPacket& AllocDataPacket(const jxSrvDef::INTERSRVCMD nCmd)
//{
//}
/*
* Comments: 刷新数据包到发送队列
* Param CDataPacket &packet
* @Return void:
* @Remark:
*/
//virtual void FlushDataPacket(CDataPacket &packet) {}
/*
* Comments: 是否是1个合法的新手卡
* Parameter: unsigned int nAccountId
* Parameter: UINT64 lCard:卡的号码
* Parameter: char * sAccountName:账户的名字,如果不传入将会去查找
* @Return int:返回结果,0表示完全匹配-1表示是新手卡但是卡号不对-2表示不是新手卡
*/
int isInvalidNewUserCard(unsigned int nAccountId, UINT64 lCard,char * sAccountName =NULL);
private:
static const OnHandleSockPacket SSSockPacketHandlers[]; //结构化网络数据包处理函数列表
public:
CSessionDataHandle( );
~CSessionDataHandle();
void SetParam(CSessionServer *pSessionSrv,CSQLConenction *pSqlConn, bool isSessonConnect );
//获取公共服的id
inline int GetCommonServerId() const
{
if( m_nCommServerId == 0)
{
return m_nSelfServerId;
}
else
{
return m_nCommServerId;
}
}
//获取服务器的id
inline int GetServerId()
{
return m_nSelfServerId;
}
VOID CatchDefaultPacket(CDataPacketReader &inPacket);
VOID CatchCloseSession(CDataPacketReader &inPacket);
VOID CatchUpdateSession(CDataPacketReader &inPacket);
VOID CatchQuerySessionResult(CDataPacketReader &inPacket);
VOID CatchOnlineCount(CDataPacketReader &inPacket);
VOID CatchLoadUserItem(CDataPacketReader &inPacket);
VOID CatchGetUserItem(CDataPacketReader &inPacket);
VOID CatchRemoveUserItem(CDataPacketReader &inPacket);
VOID CatchAddValueCard(CDataPacketReader &inPacket);
VOID CatchQueryAddValueCard(CDataPacketReader &inPacket);
// 查询元宝数量
VOID CatchQueryYuanbaoCount(CDataPacketReader &inPacket);
// 提取元宝
VOID CatchWithdrawYuanbao(CDataPacketReader &inPacket);
//确认登陆了
VOID CatchConformOpenSession(CDataPacketReader &inPacket);
/*
* Comments: 处理来自逻辑服务器的请求传送到目标服务器消息
* Param CatchDefaultPacket:
* Param & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatchRequestTransmit(CDataPacketReader &inPacket);
/*
* Comments: 收到战区的数据
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatchGroupMessage(CDataPacketReader &inPacket);
//检测用户名密码
VOID CatchCheckUserPassword(CDataPacketReader &inPacket);
//创建账户
VOID CatchCreateAccount(CDataPacketReader &inPacket);
// 发送AMC应答消息给逻辑服务器
void sendAMCMsgAck(const CAMClient::AMOPDATA & data);
//发送任务给逻辑服务器应答
void SendAmTaskAck(const CAMClient::TASKMSG & data);
/*
* Comments: 公告消息
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatchBroadcastMessage(CDataPacketReader &inPacket);
/*
* Comments: 保存跨服排行榜
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatchSaveCsRank(CDataPacketReader &inPacket);
/*
* Comments: 获取跨服排行榜
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatchLoadCsRank(CDataPacketReader &inPacket);
/*
* Comments: 清除跨服排行数据
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatchClearCsRank(CDataPacketReader &inPacket);
//设置跨服的数据库ID
VOID SetCommonServerId(CDataPacketReader &inPacket);
//检测玩家是否合法,返回错误码
int CheckUserValid(PCHAR name, PCHAR passwd, GLOBALSESSIONOPENDATA & sessiDonata,PCHAR md5,PCHAR sCurrentTime,bool checkMd5,bool bCommonSrvLogin,PCHAR identity,bool &isWhiteIpLogin,int nRawServerindex=0);
/*
* Comments: 收到后台的消息
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatGetContrlCenterMsg(CDataPacketReader &inPacket);
/*
* Comments: 收到腾讯平台的消息
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatQQMsg(CDataPacketReader &inPacket);
/*
* Comments: 收到连接会话公告服的数据
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatSendCommonPlatformData(CDataPacketReader &inPacket);
/*
* Comments: 请求传送到跨平台
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatRetranToCommonPlatform(CDataPacketReader &inPacket);
/*
* Comments: 封禁IP并且把这个区的玩家全部踢下线
* Param CDataPacketReader & inPacket:
* @Return VOID:
* @Remark:
*/
VOID CatchSealIp(CDataPacketReader &inPacket);
/*
* Comments: 解封玩家的IP
* Parameter: CDataPacketReader & inPacket:
* @Return VOID:
*/
VOID CatchUnSealIp(CDataPacketReader &inPacket);
//字符串的ip转整型的
long long GetIntIp(char *sIp);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,296 @@
#ifndef _SESSION_SERVER_H_
#define _SESSION_SERVER_H_
#include "AMProcto.h"
#include "AMClient_tx.h"
class CSessionClient;
class CSSManager;
class CRankMgr;
using namespace jxSrvDef;
class CSessionServer
: public CCustomServerSocket
{
public:
friend class CSessionClient;
typedef CCustomServerSocket Inherited;
//定义枚举客户连接的回调函数类型第一个LPVOID类型的参数是一个穿透性的参数。函数返回0表示继续枚举否则表示终止枚举
typedef UINT (__stdcall *EnumConnectionFn) (LPCVOID, CSessionClient*);
private:
CQueueList<PGAMESESSION> m_SessionList; //全局会话列表
CCSLock m_SessionListLock; //全局会话列表锁
CSSManager* m_pSSManager; //所属会话管理器
TICKCOUNT m_dwReconnectSQLTick;//下次重新连接数据的时间
CSQLConenction m_SQLConnection; //数据库连接对象
INT_PTR m_nDBClientCount; //数据客户端数量
INT_PTR m_nEngineClientCount;//引擎客户端数量
TICKCOUNT m_dwCheckOnlineLogTick;//下次检查记录在线人数的时间
TICKCOUNT m_dwSaveRankTick; //保存rank的tick
BOOL m_boOnlineLoged; //是否已经记录在线人数
BOOL m_boIpLoged; //是否记录了IP在线
CRankMgr m_rankMgr; //获取排名管理器
const static int SAVE_RANK_INTERVAL= 120*3600*1000; //2个小时存盘1次吧
struct IPCount
{
long long lIp; //用户的IP
int nCount; //禁止登陆的次数
};
CBaseList<IPCount> m_ipForbidCount; //IP违规的次数违规多次以后就需要封IP,封账户
private:
//发送记录各个服务器的在线人数
VOID SendLogOnlineCount();
protected:
//覆盖创建连接对象的函数
CCustomServerClientSocket* CreateClientSocket(SOCKET nSocket, PSOCKADDR_IN pAddrIn);
//覆盖处理客户端连接的函数
VOID ProcessClients();
//覆盖的开启服务的函数
BOOL DoStart();
//覆盖的停止服务的函数
VOID DoStop();
//覆盖内部消息分派函数
VOID DispatchInternalMessage(UINT uMsg, UINT64 uParam1, UINT64 uParam2, UINT64 uParam3,UINT64 uParam4);
//覆盖例行执行函数
VOID SingleRun();
private:
//连接数据库
BOOL ConnectSQL();
//关闭会话操作的依据是会话在列表中的索引而非会话ID或账号字符串
BOOL CloseSessionAtListIndex(const INT_PTR nIndex);
private:
//向所有DB客户端以及指定ID的引擎客户端发送消息消息将被立刻追加到客户端发的发送缓冲中。数据包必须是完成的格式包含包头和包尾
INT_PTR SendAllDBAndIndexEngineMsg(const INT_PTR nServerIndex, LPCSTR sMsg, const size_t dwSize);
//广播会话状态变更的消息
INT_PTR BroadCastUpdateSessionState(PGAMESESSION pSession);
/*
* Comments:广播删除一个会话如果nServerIndex=-1则所有的广播否则只向特定的服务器广播
* Param const UINT64 nSessionId:会话的id
* Param const int nServerIndex:服务器的编号
* @Return INT_PTR:
*/
INT_PTR BroadCastCloseSession(const UINT64 nSessionId,Uint64 lKey, const int nServerIndex=-1 );
//广播确认会话是否在线
INT_PTR BroadCastSessionConfim(const UINT64 nSessionId, const INT_PTR nServerIndex);
//广播要删除这个玩家,玩家登陆的时候,如果在线,直接踢出这个角色
//INT_PTR BroadcastKickUser(const INT_PTR nSessionId,const INT_PTR nServerIndex);
//初始化账户的唯一为了保证账户的唯一account的最小值为 spguid << 24 +1 ,这样保证全球所有的账户都是唯一的
bool InitACCountId();
//初始化所有的数据
bool InitRankMsg();
//保存所有的rank数据
bool SaveRankMsg();
//向日志服发送当前ip的登陆情况
void SendOnlineIpStatus();
//获取int类型的ip
long long GetIntIp(char *sIp); //
public:
//通过账号字符串获取会话指针如果lpIndex参数非空则会向指针指向的内存填充值为会话在列表中的索引
//此函数非常的慢!
PGAMESESSION GetSessionPtrByAccount(LPCSTR sAccount, PINT_PTR lpIndex = NULL);
// 给连接到指定公共服务器的逻辑服务器广播消息
INT_PTR SendGroupLogicClientMsg(const int nCommServerId, LPVOID data, const SIZE_T nSize);
//向所有客户端送消息,消息将被立刻追加到客户端发的发送缓冲中。数据包必须是完成的格式(包含包头和包尾)
//参数eServerType表示服务器类型InvalidServer表示向所有类型的服务器发送否则向类型为eServerType的所有服务器发送
INT_PTR SendAllClientMsg(const SERVERTYPE eServerType, LPCSTR sMsg, const size_t dwSize);
//向指定ID的逻辑户端发送消息消息将被立刻追加到客户端发的发送缓冲中。数据包必须是完成的格式包含包头和包尾
INT_PTR SendLogicClientMsg(const INT_PTR nServerIndex, LPCSTR sMsg, const size_t dwSize);
//获取会话指针如果lpIndex参数非空则会向指针指向的内存填充值为会话在列表中的索引
PGAMESESSION GetSessionPtr(const unsigned int nSessionId,PINT_PTR lpIndex = NULL,Uint64 lKey= (Uint64)-1,int nServerIndex =-1);
CSessionServer(CSSManager *lpSSManager);
~CSessionServer();
//向所有服务器投递消息,消息将在逻辑循环中被发送而不是立即发送。数据包必须是完成的格式(包含包头和包尾)
//参数eServerType表示服务器类型stInvalid表示向所有类型的服务器发送否则向类型为eServerType的所有服务器发送
VOID PostAllClientMsg(const SERVERTYPE eServerType, LPCSTR sMsg);
//获取会话数据如果会话存在则返回TRUE并为pSession填充会话数据内容
BOOL GetSession(const INT_PTR nSessionId,OUT PGAMESESSION pSession,int nServerIndex =-1);
//查找某个特定服会话的指针
PGAMESESSION GetSpecialServerSession(const INT_PTR nSessionId, const int nServerIndex);
//踢掉在线的用户
VOID PostKickCrossActor(const INT_PTR nSessionId, const int nServerIndex);
//处理剔除跨服用户
void ProcessKickCrossActor(const unsigned int nSessionId, const int nServerIndex);
//获取1个ip登陆的个数
int GetLoginAccountCount(LONGLONG lIp);
//获取当前全局会话数量
inline INT_PTR GetSessionCount(){ return m_SessionList.count(); }
//获取已经连接的数据客户端数量
inline INT_PTR GetDBClientCount(){ return m_nDBClientCount; };
//获取已经连接的逻辑服务器客户端数量如果nServerIndex参数为0则统计所有逻辑客户端数量
INT_PTR GetLogicClientCount(const INT_PTR nServerIndex);
//判断用户是否可以登录到目的服务器返回0表示可以登录。如果服务器的会话客户端未连接则返回-1如果服务器人员已满则返回-2,
INT_PTR UserCanLoginToServer(const INT_PTR nServerIndex);
//投递开启新会话的消息
BOOL PostOpenSession(const INT_PTR nServerIndex, // 登录的逻辑服务器ID
const INT_PTR nRawServerIndex, // 原始的服务器ID
LPCSTR sAccount, // 登录用户名
const unsigned int nSessionId, // 会话ID账号ID
const INT_PTR nIPAddr, // 登录IP地址
const INT_PTR dwTodayOnlineSec, // 今天在线时间
INT_PTR nGmLevel, // GM等级
UINT64 lKey , // 在逻辑服的key
INT_PTR nGateIndex, //在网关的编号 ,
bool bIsWhiteLogin, // 是否是白名单登陆的
bool bCommonMsg=false //是否中心会话服转发过来的消息
);
//投递按账号字符串关闭会话的消息,用于管理用
VOID PostCloseSessionByAccount(const LPCSTR sAccount);
//关闭一个会话
VOID PostCloseSessionByAccountId(Uint64 nAccountId,UINT64 lKey);
//遍历所有的连接,lpFn是毁掉函数指针lpParam是穿透参数会传递给对调函数。
VOID EnumConnections(EnumConnectionFn lpFn, LPCVOID lpParam);
CSSManager* GetSSManager() { return m_pSSManager; }
void PostAMCMsg(const CAMClient::AMOPData &data);
//转发集市任务的消息给逻辑服
void PostAMCTaskMsg(CAMClient::tagTASKMsg &data);
CSQLConenction* GetSql() {return &m_SQLConnection;}
/*
* Comments: 往列表里添加1个成员
* Parameter: CRankItem & rankItem:rank的值
* Parameter: int nRankItemCount:排行榜最大的数额限制,
* @Return void:
*/
void PostRankMsg(CRankItem& rankItem,int nRankItemCount=1)
{
m_rankMgr.AddRankItem(rankItem,nRankItemCount);
}
/*
* Comments: 获取某个排行榜
* Parameter: int nKey:排行榜的id,如果是所有的,可以传入-1
* Parameter: wylib::container::CBaseList<CRankItem> & itemList:元素列表
* @Return void:
*/
void GetRankMsg(int nKey,wylib::container::CBaseList<CRankItem> & itemList)
{
m_rankMgr.GetRankList(nKey,itemList);
}
/*
* Comments: 封掉 ip
* Parameter: long long lIp:ip的整数
* @Return void:
*/
void SealIp(char *sIp);
/*
* Comments: 解封ip
* Parameter: long long lIp:
* @Return void:
*/
void UnSealIp(char *sIp);
/*
* Comments: 禁止ip并且封掉所有的账户
* Parameter: long long lIP:IP
* Parameter: bool bDirectSeal:是不是直接封号
* @Return void:
*/
void ForbidIpAndSealAll(long long lIP,bool bDirectSeal );
//获取IP禁止的次数
inline INT_PTR GetIpForbidCount(long long lIp)
{
for( INT_PTR i=m_ipForbidCount.count() -1; i>=0 ; i -- )
{
if(m_ipForbidCount[i].lIp == lIp)
{
return m_ipForbidCount[i].nCount;
}
}
return 0;
}
//设置IP禁止的次数
inline void SetIpForbidCount(long long lIp,int nCount)
{
for( INT_PTR i=m_ipForbidCount.count() -1; i>=0 ; i -- )
{
if(m_ipForbidCount[i].lIp == lIp)
{
m_ipForbidCount[i].nCount = nCount;
return ;
}
}
IPCount data;
data.lIp = lIp;
data.nCount =nCount;
m_ipForbidCount.add(data);
}
//从会话中心服回来的跨平台请求结果
void OnSendPlatformResultToClient(int nServerIndex,CDataPacketReader &inPacket);
};
#endif

View File

@@ -0,0 +1,2 @@
//预编译头
#include "StdAfx.h"

View File

@@ -0,0 +1,90 @@
#include <stdio.h>
#include <stdlib.h>
#include <string>
#ifdef WIN32
#include <crtdbg.h>
#include <tchar.h>
#include <Windows.h>
#include <CommCtrl.h>
#endif
#include <_ast.h>
#include <_memchk.h>
#include <Lock.h>
#include <Tick.h>
#include <QueueList.h>
#include <Thread.h>
#include <CustomSocket.h>
#include <Stream.h>
#include <ClassedWnd.h>
#include <RefString.hpp>
extern "C"
{
#include <lua.h>
#include <lauxlib.h>
}
#define StrToInt _StrToInt
#define NO_USE_AMSERVER
#include "md5.h"
#include "ShareUtil.h"
#include "BufferAllocator.h"
#include "AppItnMsg.h"
#include "DataPacket.hpp"
#include "SQL.h"
#include "DataPacketReader.hpp"
#include "DataPacket.hpp"
//#include "EDPass.h"
#include "CustomLuaMyLoad.h"
#include "CustomLuaScript.h"
#include "CustomLuaConfig.h"
#include "SendPackPool.h"
#include "CustomWorkSocket.h"
#include "CustomClientSocket.h"
#include "CustomServerClientSocket.h"
#include "CustomServerSocket.h"
#include "CustomServerClientSocketEx.h"
#include "ServerDef.h"
#include "CommonDef.h"
#include "InterServerComm.h"
#include "CustomJXClientSocket.h"
#include "CustomJXServerClientSocket.h"
#include "GateProto.h"
#include "LogType.h"
#include "LogSender.h"
#include "FileLogger.h"
#include "CustomExceptHander.h"
//#include "AMClient.h"
#include "SSProto.h"
#include "RankMgr.h"
//#include "SSGateUser.h"
//#include "SSGate.h"
//#include "SSGateManager.h"
#include "SessionDBRequestHostInterface.h"
#include "SessionDataHandle.h"
#include "SessionClient.h"
#include "SessionServer.h"
#include "SessionCenter.h"
#include "SessionCenterClient.h"
#include "SSManager.h"
#include "ObjectCounter.h"
#include "TimeStat.h"
#include "PerformanceWatcher.h"
#include "PerformanceWatcher.h"
#include "SSConfig.h"
#include "wrand.h"
#include "FDOP.h"
using namespace jxSrvDef;
using namespace jxInterSrvComm;

View File

@@ -0,0 +1,14 @@
#! /bin/bash
if [ -n "$1" ]; then
BuiltType=$1
else
BuiltType=Release
fi
rm -rf CMakeCache.txt cmake_install.cmake CMakeFiles/
cmake -DCMAKE_BUILD_TYPE=${BuiltType} ./
make -j4
rm -rf CMakeCache.txt CMakeFiles/

View File

@@ -0,0 +1,358 @@
#include "StdAfx.h"
//#include "WinService.h"
#include "FileLogger.h"
#include <iostream>
#ifdef WIN32
#include <dbghelp.h>
#include <mbctype.h>
#endif
#include "PathThreadLocale.h"
#include <string>
using namespace std;
std::string g_ConfigPath;
extern const TCHAR szExceptionDumpFile[] = _T("./SessionManager.dmp");
BOOL SetupSessionManagerConfig(CSSManager*);
VOID ServerMain();
VOID ServiceMain(int argc, char** argv);
#ifdef WIN32
int initLocalePath()
{
//_MB_CP_SBCS 视所有字符均作为单字节字符以便同时支持UTF8以及MBCS
//Use single-byte code page.
//When the code page is set to _MB_CP_SBCS, a routine such as _ismbblead always returns false.
_setmbcp(_MB_CP_SBCS);
//★关键★ 设置"C"locale视所有字符均作为单字节字符以便同时支持UTF8以及MBCS
return InstallThreadLocalePath("C");
}
#endif
//会话管理器版本号
#define SS_MGR_KN_VERION MAKEFOURCC(17, 3, 24,1)
/*
class CSessionService : public CWinService
{
public:
CSessionService(LPCSTR pServiceName, DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS):CWinService(pServiceName, dwServiceType){};
int AppMain()
{
SetCurrentDirectory("../");
CSSManager *pSSManager;
CFileLogger flog(_T("SessionServer_%s.log"), getCurrentTimeDesc());
pSSManager = new CSSManager();
if ( SetupSessionManagerConfig(pSSManager) )
{
if ( pSSManager->Startup() )
{
in_addr ia;
ia.S_un.S_addr = SS_MGR_KN_VERION;
OutputMsg( rmTip, _T("-------------------------------------------") );
OutputMsg( rmTip, _T("会话管理器启动成功,核心版本号是%s"), inet_ntoa(ia) );
OutputMsg( rmTip, _T("quit - 停止服务并退出程序") );
OutputMsg( rmTip, _T("spfw - 显示性能状态窗口") );
OutputMsg( rmTip, _T("sscw - 显示服务器连接窗口") );
OutputMsg( rmTip, _T("lgr - 重新加载角色网关路由表") );
OutputMsg( rmTip, _T("lal - 重新加载管理员登录表") );
OutputMsg( rmTip, _T("kks - 踢账号下线") );
OutputMsg( rmTip, _T("fcmclose - 关闭fcm") );
OutputMsg( rmTip, _T("fcmopen - 开启fcm") );
OutputMsg( rmTip, _T("-------------------------------------------") );
//CPerformanceWatcher watcher(pSSManager);
//watcher.resume();
while (!m_boServiceExit)
{
Sleep(1000);
}
//watcher.terminate();
//watcher.waitFor();
pSSManager->Shutdown();
}
}
else
{
OutputMsg(rmError, _T("读取会话管理器配置失败"));
}
delete pSSManager;
return 0;
}
};
*/
int main(int argc, char** argv)
{
CTimeProfMgr::getSingleton().InitMgr();
#ifdef WIN32
SetUnhandledExceptionFilter( DefaultUnHandleExceptionFilter );
if (initLocalePath())
{
OutputMsg( rmError, _T("can not set locale path") );
getc(stdin);
return -2;
}
#endif
InitDefMsgOut();
#ifdef WIN32
//flog.SetNeedOutput(true);
#else
if (argc >=2)
{
//flog.SetNeedOutput(true);
}
else
{
//flog.SetNeedOutput(false);
}
#endif
//unsigned long long ip1= inet_addr("111.170.68.213");
//unsigned long long ip2= inet_addr("111.170.68.214");
//char *sIp =inet_ntoa(*((in_addr*)&ip1));
//char *sIp2 =inet_ntoa(*((in_addr*)&ip2));
#ifndef _SERVICE
//if (argc == 2 && _tcsncicmp("/cmd",argv[1],4)==0)//平时调试用
{
#ifdef WIN32
SetCurrentDirectory("./");
#else
string filename(argv[1]);
size_t found = filename.find_last_of("/\\");
filename = filename.substr(0, found);
if( filename[0] == '.' && filename.length()==1 )
filename = "./" ;
SetCurrentDirectory(filename.c_str());
#endif
if(argc >=2)
{
g_ConfigPath = argv[1];
}else
{
g_ConfigPath="SessionServerLinux.txt";
}
ServerMain();
}
#else
//else
{
//ServiceMain(argc, argv);
}
#endif
UninitDefMsgOut();
#ifdef _MLIB_DUMP_MEMORY_LEAKS_
_CrtDumpMemoryLeaks();
#endif
return 0;
}
BOOL SetupSessionManagerConfig(CSSManager *lpSSManager)
{
CSSConfig config;
return config.loadConfig(lpSSManager);
}
/*
VOID ServiceMain(int argc, char** argv)
{
LPTSTR sCmd = NULL;
if (argc >= 2)
{
sCmd = argv[1];
}
CSessionService service("SessionService");
service.Run(sCmd);
}
*/
VOID ServerMain()
{
if (!FDOP::IsDirectory(_T("log")))
{
FDOP::DeepCreateDirectory(_T("log"));
}
CFileLogger flog(_T("./log/SessionServer_%s.log"), getCurrentTimeDesc());
INT_PTR nError;
TCHAR sCmdBuf[512];
CSSManager *pSSManager;
pSSManager = new CSSManager();
#ifdef WIN32
if (initLocalePath())
{
OutputMsg( rmError, _T("can not set locale path") );
getc(stdin);
return ;
}
#endif
if ( SetupSessionManagerConfig(pSSManager) )
{
if ( pSSManager->Startup() )
{
in_addr ia;
ia.s_addr= SS_MGR_KN_VERION;
OutputMsg( rmTip, _T("-------------------------------------------") );
OutputMsg( rmTip, _T("会话管理器启动成功,核心版本号是%s"), inet_ntoa(ia) );
OutputMsg( rmTip, _T("quit - 停止服务并退出程序") );
OutputMsg( rmTip, _T("spfw - 显示性能状态窗口") );
OutputMsg( rmTip, _T("sscw - 显示服务器连接窗口") );
OutputMsg( rmTip, _T("lgr - 重新加载角色网关路由表") );
OutputMsg( rmTip, _T("lal - 重新加载管理员登录表") );
OutputMsg( rmTip, _T("kks - 踢账号下线") );
OutputMsg( rmTip, _T("fcmclose - 关闭fcm") );
OutputMsg( rmTip, _T("fcmopen - 开启fcm") );
OutputMsg( rmTip, _T("-------------------------------------------") );
char pBuff[256] ;
strcpy(pBuff,"lcwl-");
strcat(pBuff, pSSManager->getServerName());
strcat(pBuff,"-V");
strcat(pBuff,inet_ntoa(ia));
SetConsoleTitle( pBuff );
//CPerformanceWatcher watcher(pSSManager);
//watcher.resume();
while ( TRUE )
{
//_getts(sCmdBuf);
std::cin >> (sCmdBuf);
//滤掉末尾的换行符
nError = (int)strlen(sCmdBuf);
while ( nError > 0 && sCmdBuf[nError-1] < 0x20 )
{
nError--;
sCmdBuf[nError] = 0;
}
//重新加载路由命令
if ( _tcsncicmp(sCmdBuf, _T("lgr"), 3) == 0 )
{
nError = pSSManager->LoadCharGateRouteTable();
if ( nError >= 0 )
OutputMsg( rmTip, _T("已加载%d个角色网关路由数据"), nError);
else OutputMsg( rmError, _T("加载角色网关路由数据失败"));
continue;
}
//重新加载管理登录命令
if ( _tcsncicmp(sCmdBuf, _T("lal"), 3) == 0 )
{
nError = pSSManager->LoadAdministLoginTable();
if ( nError >= 0 )
OutputMsg( rmTip, _T("已加载%d个管理员登录记录"), nError);
else OutputMsg( rmError, _T("加载管理员登录记录数据失败"));
continue;
}
//踢账号下线
if ( _tcsncicmp(sCmdBuf, _T("kks"), 3) == 0 )
{
pSSManager->getSessionServer()->PostCloseSessionByAccount(&sCmdBuf[4]);
OutputMsg( rmTip, _T("发出关闭会话(%s)的消息"), &sCmdBuf[4] );
continue;
}
//显示性能状态窗口
if ( _tcsncicmp(sCmdBuf, _T("spfw"), 4) == 0 )
{
//watcher.ShowPerformanceWindow(TRUE);
continue;
}
if ( _tcsncicmp(sCmdBuf, _T("sscw"), 4) == 0 )
{
//watcher.ShowServerConnectionWindow(TRUE);
continue;
}
//测试打印会话
if ( _tcsncicmp(sCmdBuf, _T("pss"), 3) == 0 )
{
pSSManager->getSessionServer()->PostInternalMessage(SSIM_DEBUG_PRINT_SESSIONS, 10, 0, 0);
continue;
}
//开启防沉迷
if ( _tcsncicmp(sCmdBuf, _T("fcmopen"), 7) == 0 )
{
pSSManager->SetFcmOpen(true);
continue;
}
//关闭防沉迷
if ( _tcsncicmp(sCmdBuf, _T("fcmclose"), 8) == 0 )
{
pSSManager->SetFcmOpen(false);
continue;
}
//重新刷新下
if ( _tcsncicmp(sCmdBuf, _T("rgm"), 3) == 0 )
{
CSSConfig config;
config.readGMConfig(pSSManager);
continue;
}
if ( _tcsncicmp(sCmdBuf, _T("spf"), 3) == 0 )
{
CTimeProfMgr::getSingleton().dump();
CounterManager::getSingleton().logToFile();
continue;
}
//退出命令
if ( _tcsncicmp(sCmdBuf, _T("\\q"), 2) == 0
|| _tcsncicmp(sCmdBuf, _T("exit"), 4) == 0
|| _tcsncicmp(sCmdBuf, _T("quit"), 4) == 0 )
{
OutputMsg( rmTip, _T("正在停止网关管理器...") );
break;
}
Sleep(10);
}
//watcher.terminate();
//watcher.waitFor();
pSSManager->Shutdown();
}
else
{
OutputMsg(rmError, _T("pSSManager->Startup() 失败"));
system("pause");
}
}
else
{
OutputMsg(rmError, _T("读取会话管理器配置失败"));
system("pause");
}
delete pSSManager;
}