原本不打算把登录拿出来写的,但是阅读登录部分的代码的时候发现登录和注册还不太一回事,因为登录涉及到分配baseapp的ip,负载均衡的实现,所以水一下。
流程图:

和上次一样,先是找unity控件

找到ui.cs下的login

1 void login()
2 {
3 Common.DEBUG_MSG("login is Click, name=" + username.input.text + ", password=" + password.input.text + "!");
4
5 log_label.obj.text = "请求连接服务器...";
6 log_label.obj.color = UnityEngine.Color.green;
7 if(username.input.text == "" || username.input.text.Length > 30)
8 {
9 log_label.obj.text = "用户名或者邮箱地址不合法。";
10 log_label.obj.color = UnityEngine.Color.red;
11 Common.WARNING_MSG("ui::login: invalid username!");
12 return;
13 }
14
15 if(password.input.text.Length < 6 || password.input.text.Length > 16)
16 {
17 log_label.obj.text = "密码不合法, 长度应该在6-16位之间。";
18 log_label.obj.color = UnityEngine.Color.red;
19 Common.WARNING_MSG("ui::login: invalid reg_password!");
20 return;
21 }
22
23 KBEngine.Event.fireIn("login", username.input.text, password.input.text, System.Text.Encoding.UTF8.GetBytes("kbengine_unity_warring"));
24 log_label.obj.text = "连接成功,等待处理请稍后...";
25 }

根据上篇文章思路找到Kbengine.cs下的login_loginapp

/*
登录到服务端(loginapp), 登录成功后还必须登录到网关(baseapp)登录流程才算完毕
*/
public void login_loginapp(bool noconnect)
{
if(noconnect)
{
reset();
_networkInterface.connectTo(_args.ip, _args.port, onConnectTo_loginapp_callback, null);
}
else
{
Dbg.DEBUG_MSG("KBEngine::login_loginapp(): send login! username=" + username);
Bundle bundle = Bundle.createObject();
bundle.newMessage(Message.messages["Loginapp_login"]);
bundle.writeInt8((sbyte)_args.clientType);
bundle.writeBlob(KBEngineApp.app._clientdatas);
bundle.writeString(username);
bundle.writeString(password);
bundle.send(_networkInterface);
}
}

去服务器的loginapp项目找login

//-------------------------------------------------------------------------------------
void Loginapp::login(Network::Channel* pChannel, MemoryStream& s)
{
AUTO_SCOPED_PROFILE("login");
COMPONENT_CLIENT_TYPE ctype;
CLIENT_CTYPE tctype = UNKNOWN_CLIENT_COMPONENT_TYPE;
std::string loginName;
std::string password;
std::string datas;
// 前端类别
s >> tctype;
ctype = static_cast<COMPONENT_CLIENT_TYPE>(tctype);
// 附带数据
s.readBlob(datas);
// 帐号登录名
s >> loginName;
// 密码
s >> password;
loginName = KBEngine::strutil::kbe_trim(loginName);
if(loginName.size() == 0)
{
INFO_MSG("Loginapp::login: loginName is NULL.\n");
_loginFailed(pChannel, loginName, SERVER_ERR_NAME, datas, true);
s.done();
return;
}
if(loginName.size() > ACCOUNT_NAME_MAX_LENGTH)
{
INFO_MSG(fmt::format("Loginapp::login: loginName is too long, size={}, limit={}.\n",
loginName.size(), ACCOUNT_NAME_MAX_LENGTH));
_loginFailed(pChannel, loginName, SERVER_ERR_NAME, datas, true);
s.done();
return;
}
if(password.size() > ACCOUNT_PASSWD_MAX_LENGTH)
{
INFO_MSG(fmt::format("Loginapp::login: password is too long, size={}, limit={}.\n",
password.size(), ACCOUNT_PASSWD_MAX_LENGTH));
_loginFailed(pChannel, loginName, SERVER_ERR_PASSWORD, datas, true);
s.done();
return;
}
if(datas.size() > ACCOUNT_DATA_MAX_LENGTH)
{
INFO_MSG(fmt::format("Loginapp::login: bindatas is too long, size={}, limit={}.\n",
datas.size(), ACCOUNT_DATA_MAX_LENGTH));
_loginFailed(pChannel, loginName, SERVER_ERR_OP_FAILED, datas, true);
s.done();
return;
}
// 首先必须baseappmgr和dbmgr都已经准备完毕了。
Components::ComponentInfos* baseappmgrinfos = Components::getSingleton().getBaseappmgr();
if(baseappmgrinfos == NULL || baseappmgrinfos->pChannel == NULL || baseappmgrinfos->cid == 0)
{
datas = "";
_loginFailed(pChannel, loginName, SERVER_ERR_SRV_NO_READY, datas, true);
s.done();
return;
}
Components::ComponentInfos* dbmgrinfos = Components::getSingleton().getDbmgr();
if(dbmgrinfos == NULL || dbmgrinfos->pChannel == NULL || dbmgrinfos->cid == 0)
{
datas = "";
_loginFailed(pChannel, loginName, SERVER_ERR_SRV_NO_READY, datas, true);
s.done();
return;
}
if(!g_kbeSrvConfig.getDBMgr().allowEmptyDigest)
{
std::string clientDigest;
if(s.length() > 0)
s >> clientDigest;
if(clientDigest.size() > 0)
{
if(clientDigest != digest_)
{
INFO_MSG(fmt::format("Loginapp::login: loginName({}), digest not match. curr({}) != dbmgr({})\n",
loginName, clientDigest, digest_));
datas = "";
_loginFailed(pChannel, loginName, SERVER_ERR_ENTITYDEFS_NOT_MATCH, datas, true);
return;
}
}
else
{
//WARNING_MSG(fmt::format("Loginapp::login: loginName={} no check entitydefs!\n", loginName));
}
}
s.done();
if(shuttingdown_ != SHUTDOWN_STATE_STOP)
{
INFO_MSG(fmt::format("Loginapp::login: shutting down, {} login failed!\n", loginName));
datas = "";
_loginFailed(pChannel, loginName, SERVER_ERR_IN_SHUTTINGDOWN, datas, true);
return;
}
if(initProgress_ < 1.f)
{
datas = fmt::format("initProgress: {}", initProgress_);
_loginFailed(pChannel, loginName, SERVER_ERR_SRV_STARTING, datas, true);
return;
}
// 把请求交由脚本处理
SCOPED_PROFILE(SCRIPTCALL_PROFILE);
PyObject* pyResult = PyObject_CallMethod(getEntryScript().get(),
const_cast<char*>("onReuqestLogin"),
const_cast<char*>("ssby#"),
loginName.c_str(),
password.c_str(),
tctype,
datas.c_str(), datas.length());
if(pyResult != NULL)
{
bool login_check = true;
if(PySequence_Check(pyResult) && PySequence_Size(pyResult) == 5)
{
char* sname;
char* spassword;
char *extraDatas;
Py_ssize_t extraDatas_size = 0;
SERVER_ERROR_CODE error;
if(PyArg_ParseTuple(pyResult, "H|s|s|b|y#", &error, &sname, &spassword, &tctype, &extraDatas, &extraDatas_size) == -1)
{
ERROR_MSG(fmt::format("Loginapp::login: {}.onReuqestLogin, Return value error! loginName={}\n",
g_kbeSrvConfig.getLoginApp().entryScriptFile, loginName));
login_check = false;
_loginFailed(pChannel, loginName, SERVER_ERR_OP_FAILED, datas, true);
}
if(login_check)
{
loginName = sname;
password = spassword;
if (extraDatas && extraDatas_size > 0)
datas.assign(extraDatas, extraDatas_size);
else
SCRIPT_ERROR_CHECK();
}
if(error != SERVER_SUCCESS)
{
login_check = false;
_loginFailed(pChannel, loginName, error, datas, true);
}
if(loginName.size() == 0)
{
INFO_MSG("Loginapp::login: loginName is NULL.\n");
_loginFailed(pChannel, loginName, SERVER_ERR_NAME, datas, true);
s.done();
return;
}
}
else
{
ERROR_MSG(fmt::format("Loginapp::login: {}.onReuqestLogin, Return value error, must be errorcode or tuple! loginName={}\n",
g_kbeSrvConfig.getLoginApp().entryScriptFile, loginName));
login_check = false;
_loginFailed(pChannel, loginName, SERVER_ERR_OP_FAILED, datas, true);
}
Py_DECREF(pyResult);
if(!login_check)
return;
}
else
{
SCRIPT_ERROR_CHECK();
_loginFailed(pChannel, loginName, SERVER_ERR_OP_FAILED, datas, true);
}
PendingLoginMgr::PLInfos* ptinfos = pendingLoginMgr_.find(loginName);
if(ptinfos != NULL)
{
datas = "";
_loginFailed(pChannel, loginName, SERVER_ERR_BUSY, datas, true);
return;
}
ptinfos = new PendingLoginMgr::PLInfos;
ptinfos->ctype = ctype;
ptinfos->datas = datas;
ptinfos->accountName = loginName;
ptinfos->password = password;
ptinfos->addr = pChannel->addr();
pendingLoginMgr_.add(ptinfos);
if(ctype < UNKNOWN_CLIENT_COMPONENT_TYPE || ctype >= CLIENT_TYPE_END)
ctype = UNKNOWN_CLIENT_COMPONENT_TYPE;
INFO_MSG(fmt::format("Loginapp::login: new client[{0}], loginName={1}, datas={2}.\n",
COMPONENT_CLIENT_NAME[ctype], loginName, datas));
pChannel->extra(loginName);
// 向dbmgr查询用户合法性
Network::Bundle* pBundle = Network::Bundle::createPoolObject();
(*pBundle).newMessage(DbmgrInterface::onAccountLogin);
(*pBundle) << loginName << password;
(*pBundle).appendBlob(datas);
dbmgrinfos->pChannel->send(pBundle);
}

这个函数进行了一系列的检查,确定合法后向dbmgr发送一个登陆请求包“(*pBundle).newMessage(DbmgrInterface::onAccountLogin);
然后在dbmgr.cpp中

//-------------------------------------------------------------------------------------
void Dbmgr::onAccountLogin(Network::Channel* pChannel, KBEngine::MemoryStream& s)
{
std::string loginName, password, datas;
s >> loginName >> password;
s.readBlob(datas);
if(loginName.size() == 0)
{
ERROR_MSG("Dbmgr::onAccountLogin: loginName is empty.\n");
return;
}
pInterfacesAccountHandler_->loginAccount(pChannel, loginName, password, datas);
}

转到interfaces_handler.cpp中

1 //-------------------------------------------------------------------------------------
2 bool InterfacesHandler_Dbmgr::loginAccount(Network::Channel* pChannel, std::string& loginName,
3 std::string& password, std::string& datas)
4 {
5 std::string dbInterfaceName = Dbmgr::getSingleton().selectAccountDBInterfaceName(loginName);
6
7 thread::ThreadPool* pThreadPool = DBUtil::pThreadPool(dbInterfaceName);
8 if (!pThreadPool)
9 {
10 ERROR_MSG(fmt::format("InterfacesHandler_Dbmgr::loginAccount: not found dbInterface({})!\n",
11 dbInterfaceName));
12
13 return false;
14 }
15
16 pThreadPool->addTask(new DBTa

本文详细解析了KBEngine项目的登录过程,包括客户端登录请求、服务器数据库查询、BaseApp负载均衡策略的实现。在负载均衡中,首先确保BaseApp进程存活并初始化,然后选择负载最小的进程分配登录请求。服务器BaseApp接收到消息后,创建或查询实体,并通过mailbox进行后续通信。最后在客户端完成mailbox绑定,启动角色列表请求。
最低0.47元/天 解锁文章
1230

被折叠的 条评论
为什么被折叠?



