KBEngine warring项目源码阅读(一) 项目简介和注册

首先介绍下warring项目,是kbe自带的一个演示示例,大部分人了解kbe引擎也是从warring项目开始的。

项目地址:https://github.com/kbengine/kbengine_unity3d_warring

项目截图:

 

项目的下载和安装不再多说,现在开始进入代码讲解阶段:

注册:

流程图:

可以看到控件绑定代码为reg_ok,点进去

 1 void reg_ok()
 2     {
 3         log_label.obj.text = "请求连接服务器...";
 4         log_label.obj.color = UnityEngine.Color.green;
 5         
 6         if(reg_username.input.text == "" || reg_username.input.text.Length > 30)
 7         {
 8             log_label.obj.color = UnityEngine.Color.red;
 9             log_label.obj.text = "用户名或者邮箱地址不合法, 最大长度限制30个字符。";
10             Common.WARNING_MSG("ui::reg_ok: invalid username!");
11             return;
12         }
13         
14         if(reg_password.input.text.Length < 6 || reg_password.input.text.Length > 16)
15         {
16             log_label.obj.color = UnityEngine.Color.red;
17             log_label.obj.text = "密码不合法, 长度限制在6~16位之间。";
18             Common.WARNING_MSG("ui::reg_ok: invalid reg_password!");
19             return;
20         }
21         
22         if(reg_password.input.text != reg_passwordok.input.text)
23         {
24             log_label.obj.color = UnityEngine.Color.red;
25             log_label.obj.text = "二次输入密码不匹配。";
26             Common.WARNING_MSG("ui::reg_ok: reg_password != reg_passwordok!");
27             return;
28         }
29         
30         KBEngine.Event.fireIn("createAccount", reg_username.input.text, reg_passwordok.input.text, System.Text.Encoding.UTF8.GetBytes("kbengine_unity_warring"));
31         log_label.obj.text = "连接成功,等待处理请稍后...";
32     }

 

  可以看到接下来是fireIn("createAccount",xxxx,...)

  这里需要讲解一下客户端的fireIn和fireOut是怎么一回事,fireIn是指u3d脚本层触发一个事件给kbe插件执行,fireOut是是插件向u3d脚本层触发的事件,总之是从unity到kbe插件的一个交互过程。既然是插件层层,那么我们打开KBEngine.cs去找对应的registerIn,可以找到下面的代码

 1         void installEvents()
 2         {
 3             Event.registerIn("createAccount", this, "createAccount");
 4             Event.registerIn("login", this, "login");
 5             Event.registerIn("reloginBaseapp", this, "reloginBaseapp");
 6             Event.registerIn("resetPassword", this, "resetPassword");
 7             Event.registerIn("bindAccountEmail", this, "bindAccountEmail");
 8             Event.registerIn("newPassword", this, "newPassword");
 9             
10             // 内部事件
11             Event.registerIn("_closeNetwork", this, "_closeNetwork");
12         }

 然后在同一文件的第727行,找到对应的消息,可以看到下一步是调用的createAccount_loginapp(false)函数

点开进去

 1         /*
 2             创建账号,通过loginapp
 3         */
 4         public void createAccount_loginapp(bool noconnect)
 5         {
 6             if(noconnect)
 7             {
 8                 reset();
 9                 _networkInterface.connectTo(_args.ip, _args.port, onConnectTo_createAccount_callback, null);
10             }
11             else
12             {
13                 Bundle bundle = Bundle.createObject();
14                 bundle.newMessage(Message.messages["Loginapp_reqCreateAccount"]);
15                 bundle.writeString(username);
16                 bundle.writeString(password);
17                 //string imei = 'AET89766-124';
18                 //bundle.writeString(imei);
19                 bundle.writeBlob(KBEngineApp.app._clientdatas);
20                 bundle.send(_networkInterface);
21             }
22         }

可以看到这里开始给后端发了一个消息,消息关键字是Loginapp_reqCreateAccount。我们打开kbe的C++部分源码

 在loginapp项目中,找到loginapp.cpp的reqCreateAccount方法,为什么要找这个方法,因为在代码底层识别的时候将关键字变为了前半段代表的节点名,后半段代表消息。

 1 //-------------------------------------------------------------------------------------
 2 void Loginapp::reqCreateAccount(Network::Channel* pChannel, MemoryStream& s)
 3 {
 4     std::string accountName, password, datas;
 5 
 6     s >> accountName >> password;
 7     s.readBlob(datas);
 8     
 9     if(!_createAccount(pChannel, accountName, password, datas, ACCOUNT_TYPE(g_serverConfig.getLoginApp().account_type)))
10         return;
11 }

点开_createAccount

  1 //-------------------------------------------------------------------------------------
  2 bool Loginapp::_createAccount(Network::Channel* pChannel, std::string& accountName, 
  3                                  std::string& password, std::string& datas, ACCOUNT_TYPE type)
  4 {
  5     AUTO_SCOPED_PROFILE("createAccount");
  6 
  7     ACCOUNT_TYPE oldType = type;
  8 
  9     if(!g_kbeSrvConfig.getDBMgr().account_registration_enable)
 10     {
 11         ERROR_MSG(fmt::format("Loginapp::_createAccount({}): not available! modify kbengine[_defs].xml->dbmgr->account_registration.\n",
 12             accountName));
 13 
 14         std::string retdatas = "";
 15         Network::Bundle* pBundle = Network::Bundle::createPoolObject();
 16         (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
 17         SERVER_ERROR_CODE retcode = SERVER_ERR_ACCOUNT_REGISTER_NOT_AVAILABLE;
 18         (*pBundle) << retcode;
 19         (*pBundle).appendBlob(retdatas);
 20         pChannel->send(pBundle);
 21         return false;
 22     }
 23 
 24     accountName = KBEngine::strutil::kbe_trim(accountName);
 25     password = KBEngine::strutil::kbe_trim(password);
 26 
 27     if(accountName.size() > ACCOUNT_NAME_MAX_LENGTH)
 28     {
 29         ERROR_MSG(fmt::format("Loginapp::_createAccount: accountName too big, size={}, limit={}.\n",
 30             accountName.size(), ACCOUNT_NAME_MAX_LENGTH));
 31 
 32         return false;
 33     }
 34 
 35     if(password.size() > ACCOUNT_PASSWD_MAX_LENGTH)
 36     {
 37         ERROR_MSG(fmt::format("Loginapp::_createAccount: password too big, size={}, limit={}.\n",
 38             password.size(), ACCOUNT_PASSWD_MAX_LENGTH));
 39 
 40         return false;
 41     }
 42 
 43     if(datas.size() > ACCOUNT_DATA_MAX_LENGTH)
 44     {
 45         ERROR_MSG(fmt::format("Loginapp::_createAccount: bindatas too big, size={}, limit={}.\n",
 46             datas.size(), ACCOUNT_DATA_MAX_LENGTH));
 47 
 48         return false;
 49     }
 50     
 51     std::string retdatas = "";
 52     if(shuttingdown_ != SHUTDOWN_STATE_STOP)
 53     {
 54         WARNING_MSG(fmt::format("Loginapp::_createAccount: shutting down, create {} failed!\n", accountName));
 55 
 56         Network::Bundle* pBundle = Network::Bundle::createPoolObject();
 57         (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
 58         SERVER_ERROR_CODE retcode = SERVER_ERR_IN_SHUTTINGDOWN;
 59         (*pBundle) << retcode;
 60         (*pBundle).appendBlob(retdatas);
 61         pChannel->send(pBundle);
 62         return false;
 63     }
 64 
 65     PendingLoginMgr::PLInfos* ptinfos = pendingCreateMgr_.find(const_cast<std::string&>(accountName));
 66     if(ptinfos != NULL)
 67     {
 68         WARNING_MSG(fmt::format("Loginapp::_createAccount: pendingCreateMgr has {}, request create failed!\n", 
 69             accountName));
 70 
 71         Network::Bundle* pBundle = Network::Bundle::createPoolObject();
 72         (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
 73         SERVER_ERROR_CODE retcode = SERVER_ERR_BUSY;
 74         (*pBundle) << retcode;
 75         (*pBundle).appendBlob(retdatas);
 76         pChannel->send(pBundle);
 77         return false;
 78     }
 79     
 80     {
 81         // 把请求交由脚本处理
 82         SERVER_ERROR_CODE retcode = SERVER_SUCCESS;
 83         SCOPED_PROFILE(SCRIPTCALL_PROFILE);
 84 
 85         PyObject* pyResult = PyObject_CallMethod(getEntryScript().get(), 
 86                                             const_cast<char*>("onRequestCreateAccount"), 
 87                                             const_cast<char*>("ssy#"), 
 88                                             accountName.c_str(),
 89                                             password.c_str(),
 90                                             datas.c_str(), datas.length());
 91 
 92         if(pyResult != NULL)
 93         {
 94             if(PySequence_Check(pyResult) && PySequence_Size(pyResult) == 4)
 95             {
 96                 char* sname;
 97                 char* spassword;
 98                 char *extraDatas;
 99                 Py_ssize_t extraDatas_size = 0;
100                 
101                 if(PyArg_ParseTuple(pyResult, "H|s|s|y#",  &retcode, &sname, &spassword, &extraDatas, &extraDatas_size) == -1)
102                 {
103                     ERROR_MSG(fmt::format("Loginapp::_createAccount: {}.onReuqestLogin, Return value error! accountName={}\n", 
104                         g_kbeSrvConfig.getLoginApp().entryScriptFile, accountName));
105 
106                     retcode = SERVER_ERR_OP_FAILED;
107                 }
108                 else
109                 {
110                     accountName = sname;
111                     password = spassword;
112 
113                     if (extraDatas && extraDatas_size > 0)
114                         datas.assign(extraDatas, extraDatas_size);
115                     else
116                         SCRIPT_ERROR_CHECK();
117                 }
118             }
119             else
120             {
121                 ERROR_MSG(fmt::format("Loginapp::_createAccount: {}.onReuqestLogin, Return value error, must be errorcode or tuple! accountName={}\n", 
122                     g_kbeSrvConfig.getLoginApp().entryScriptFile, accountName));
123 
124                 retcode = SERVER_ERR_OP_FAILED;
125             }
126             
127             Py_DECREF(pyResult);
128         }
129         else
130         {
131             SCRIPT_ERROR_CHECK();
132             retcode = SERVER_ERR_OP_FAILED;
133         }
134             
135         if(retcode != SERVER_SUCCESS)
136         {
137             Network::Bundle* pBundle = Network::Bundle::createPoolObject();
138             (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
139             (*pBundle) << retcode;
140             (*pBundle).appendBlob(retdatas);
141             pChannel->send(pBundle);
142             return false;
143         }
144         else
145         {
146             if(accountName.size() == 0)
147             {
148                 ERROR_MSG(fmt::format("Loginapp::_createAccount: accountName is empty!\n"));
149 
150                 retcode = SERVER_ERR_NAME;
151                 Network::Bundle* pBundle = Network::Bundle::createPoolObject();
152                 (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
153                 (*pBundle) << retcode;
154                 (*pBundle).appendBlob(retdatas);
155                 pChannel->send(pBundle);
156                 return false;
157             }
158         }
159     }
160 
161     if(type == ACCOUNT_TYPE_SMART)
162     {
163         if (email_isvalid(accountName.c_str()))
164         {
165             type = ACCOUNT_TYPE_MAIL;
166         }
167         else
168         {
169             if(!validName(accountName))
170             {
171                 ERROR_MSG(fmt::format("Loginapp::_createAccount: invalid accountName({})\n",
172                     accountName));
173 
174                 Network::Bundle* pBundle = Network::Bundle::createPoolObject();
175                 (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
176                 SERVER_ERROR_CODE retcode = SERVER_ERR_NAME;
177                 (*pBundle) << retcode;
178                 (*pBundle).appendBlob(retdatas);
179                 pChannel->send(pBundle);
180                 return false;
181             }
182 
183             type = ACCOUNT_TYPE_NORMAL;
184         }
185     }
186     else if(type == ACCOUNT_TYPE_NORMAL)
187     {
188         if(!validName(accountName))
189         {
190             ERROR_MSG(fmt::format("Loginapp::_createAccount: invalid accountName({})\n",
191                 accountName));
192 
193             Network::Bundle* pBundle = Network::Bundle::createPoolObject();
194             (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
195             SERVER_ERROR_CODE retcode = SERVER_ERR_NAME;
196             (*pBundle) << retcode;
197             (*pBundle).appendBlob(retdatas);
198             pChannel->send(pBundle);
199             return false;
200         }
201     }
202     else if (!email_isvalid(accountName.c_str()))
203     {
204         /*
205         std::string user_name, domain_name;
206         user_name = regex_replace(accountName, _g_mail_pattern, std::string("$1") );
207         domain_name = regex_replace(accountName, _g_mail_pattern, std::string("$2") );
208         */
209         WARNING_MSG(fmt::format("Loginapp::_createAccount: invalid mail={}\n", 
210             accountName));
211 
212         Network::Bundle* pBundle = Network::Bundle::createPoolObject();
213         (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
214         SERVER_ERROR_CODE retcode = SERVER_ERR_NAME_MAIL;
215         (*pBundle) << retcode;
216         (*pBundle).appendBlob(retdatas);
217         pChannel->send(pBundle);
218         return false;
219     }
220 
221     DEBUG_MSG(fmt::format("Loginapp::_createAccount: accountName={}, passwordsize={}, type={}, oldType={}.\n",
222         accountName.c_str(), password.size(), type, oldType));
223 
224     ptinfos = new PendingLoginMgr::PLInfos;
225     ptinfos->accountName = accountName;
226     ptinfos->password = password;
227     ptinfos->datas = datas;
228     ptinfos->addr = pChannel->addr();
229     pendingCreateMgr_.add(ptinfos);
230 
231     Components::COMPONENTS& cts = Components::getSingleton().getComponents(DBMGR_TYPE);
232     Components::ComponentInfos* dbmgrinfos = NULL;
233 
234     if(cts.size() > 0)
235         dbmgrinfos = &(*cts.begin());
236 
237     if(dbmgrinfos == NULL || dbmgrinfos->pChannel == NULL || dbmgrinfos->cid == 0)
238     {
239         ERROR_MSG(fmt::format("Loginapp::_createAccount: create({}), not found dbmgr!\n", 
240             accountName));
241 
242         Network::Bundle* pBundle = Network::Bundle::createPoolObject();
243         (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
244         SERVER_ERROR_CODE retcode = SERVER_ERR_SRV_NO_READY;
245         (*pBundle) << retcode;
246         (*pBundle).appendBlob(retdatas);
247         pChannel->send(pBundle);
248         return false;
249     }
250 
251     pChannel->extra(accountName);
252 
253     Network::Bundle* pBundle = Network::Bundle::createPoolObject();
254     (*pBundle).newMessage(DbmgrInterface::reqCreateAccount);
255     uint8 uatype = uint8(type);
256     (*pBundle) << accountName << password << uatype;
257     (*pBundle).appendBlob(datas);
258     dbmgrinfos->pChannel->send(pBundle);
259     return true;
260 }

可以看到,进行了一堆繁琐的验证以后,最后将解析出来的用户名密码等其他数据

我们打开dbmgr,找到reqCreateAccount函数

 1 //-------------------------------------------------------------------------------------
 2 void Dbmgr::reqCreateAccount(Network::Channel* pChannel, KBEngine::MemoryStream& s)
 3 {
 4     std::string registerName, password, datas;
 5     uint8 uatype = 0;
 6 
 7     s >> registerName >> password >> uatype;
 8     s.readBlob(datas);
 9 
10     if(registerName.size() == 0)
11     {
12         ERROR_MSG("Dbmgr::reqCreateAccount: registerName is empty.\n");
13         return;
14     }
15 
16     pInterfacesAccountHandler_->createAccount(pChannel, registerName, password, datas, ACCOUNT_TYPE(uatype));
17     numCreatedAccount_++;
18 }

然后点开createAccount,因为一般情况下配置文件会填写host和port,所以我们进入InterfacesHandler_Dbmgr::createAccount的方法查看

 1 //-------------------------------------------------------------------------------------
 2 bool InterfacesHandler_Dbmgr::createAccount(Network::Channel* pChannel, std::string& registerName,
 3                                           std::string& password, std::string& datas, ACCOUNT_TYPE uatype)
 4 {
 5     std::string dbInterfaceName = Dbmgr::getSingleton().selectAccountDBInterfaceName(registerName);
 6 
 7     thread::ThreadPool* pThreadPool = DBUtil::pThreadPool(dbInterfaceName);
 8     if (!pThreadPool)
 9     {
10         ERROR_MSG(fmt::format("InterfacesHandler_Dbmgr::createAccount: not found dbInterface({})!\n",
11             dbInterfaceName));
12 
13         return false;
14     }
15 
16     // 如果是email,先查询账号是否存在然后将其登记入库
17     if(uatype == ACCOUNT_TYPE_MAIL)
18     {
19         pThreadPool->addTask(new DBTaskCreateMailAccount(pChannel->addr(),
20             registerName, registerName, password, datas, datas));
21 
22         return true;
23     }
24 
25     pThreadPool->addTask(new DBTaskCreateAccount(pChannel->addr(),
26         registerName, registerName, password, datas, datas));
27 
28     return true;
29 }

可以看到,这里是用了一个异步任务队列的形式,进行的数据库写入,点开DBTaskCreateAccount,事实上邮件账号的原理是一样的

我们简单的看下DBTaskCreateAccount这个类,头文件

 1 /**
 2     创建一个账号到数据库
 3 */
 4 class DBTaskCreateAccount : public DBTask
 5 {
 6 public:
 7     DBTaskCreateAccount(const Network::Address& addr, std::string& registerName, std::string& accountName, 
 8         std::string& password, std::string& postdatas, std::string& getdatas);
 9     virtual ~DBTaskCreateAccount();
10     virtual bool db_thread_process();
11     virtual thread::TPTask::TPTaskState presentMainThread();
12 
13     static bool writeAccount(DBInterface* pdbi, const std::string& accountName, 
14         const std::string& passwd, const std::string& datas, ACCOUNT_INFOS& info);
15 
16 protected:
17     std::string registerName_; 
18     std::string accountName_;
19     std::string password_;
20     std::string postdatas_, getdatas_;
21     bool success_;
22     
23 };

CPP文件

  1 //-------------------------------------------------------------------------------------
  2 DBTaskCreateAccount::DBTaskCreateAccount(const Network::Address& addr, 
  3                                          std::string& registerName,
  4                                          std::string& accountName, 
  5                                          std::string& password, 
  6                                          std::string& postdatas, 
  7                                         std::string& getdatas):
  8 DBTask(addr),
  9 registerName_(registerName),
 10 accountName_(accountName),
 11 password_(password),
 12 postdatas_(postdatas),
 13 getdatas_(getdatas),
 14 success_(false)
 15 {
 16 }
 17 
 18 //-------------------------------------------------------------------------------------
 19 DBTaskCreateAccount::~DBTaskCreateAccount()
 20 {
 21 }
 22 
 23 //-------------------------------------------------------------------------------------
 24 bool DBTaskCreateAccount::db_thread_process()
 25 {
 26     ACCOUNT_INFOS info;
 27     success_ = DBTaskCreateAccount::writeAccount(pdbi_, accountName_, password_, postdatas_, info) && info.dbid > 0;
 28     return false;
 29 }
 30 
 31 //-------------------------------------------------------------------------------------
 32 bool DBTaskCreateAccount::writeAccount(DBInterface* pdbi, const std::string& accountName, 
 33                                        const std::string& passwd, const std::string& datas, ACCOUNT_INFOS& info)
 34 {
 35     info.dbid = 0;
 36     if(accountName.size() == 0)
 37     {
 38         return false;
 39     }
 40 
 41     // 寻找dblog是否有此账号, 如果有则创建失败
 42     // 如果没有则向account表新建一个entity数据同时在accountlog表写入一个log关联dbid
 43     EntityTables& entityTables = EntityTables::findByInterfaceName(pdbi->name());
 44     KBEAccountTable* pTable = static_cast<KBEAccountTable*>(entityTables.findKBETable("kbe_accountinfos"));
 45     KBE_ASSERT(pTable);
 46 
 47     ScriptDefModule* pModule = EntityDef::findScriptModule(DBUtil::accountScriptName());
 48     if(pModule == NULL)
 49     {
 50         ERROR_MSG(fmt::format("DBTaskCreateAccount::writeAccount(): not found account script[{}], create[{}] error!\n", 
 51             DBUtil::accountScriptName(), accountName));
 52 
 53         return false;
 54     }
 55 
 56     if(pTable->queryAccount(pdbi, accountName, info) && (info.flags & ACCOUNT_FLAG_NOT_ACTIVATED) <= 0)
 57     {
 58         if(pdbi->getlasterror() > 0)
 59         {
 60             WARNING_MSG(fmt::format("DBTaskCreateAccount::writeAccount(): queryAccount error: {}\n", 
 61                 pdbi->getstrerror()));
 62         }
 63 
 64         return false;
 65     }
 66 
 67     bool hasset = (info.dbid != 0);
 68     if(!hasset)
 69     {
 70         info.flags = g_kbeSrvConfig.getDBMgr().accountDefaultFlags;
 71         info.deadline = g_kbeSrvConfig.getDBMgr().accountDefaultDeadline;
 72     }
 73 
 74     DBID entityDBID = info.dbid;
 75     
 76     if(entityDBID == 0)
 77     {
 78         // 防止多线程问题, 这里做一个拷贝。
 79         MemoryStream copyAccountDefMemoryStream(pTable->accountDefMemoryStream());
 80 
 81         entityDBID = EntityTables::findByInterfaceName(pdbi->name()).writeEntity(pdbi, 0, -1,
 82                 &copyAccountDefMemoryStream, pModule);
 83     }
 84 
 85     KBE_ASSERT(entityDBID > 0);
 86 
 87     info.name = accountName;
 88     info.email = accountName + "@0.0";
 89     info.password = passwd;
 90     info.dbid = entityDBID;
 91     info.datas = datas;
 92     
 93     if(!hasset)
 94     {
 95         if(!pTable->logAccount(pdbi, info))
 96         {
 97             if(pdbi->getlasterror() > 0)
 98             {
 99                 WARNING_MSG(fmt::format("DBTaskCreateAccount::writeAccount(): logAccount error:{}\n", 
100                     pdbi->getstrerror()));
101             }
102 
103             return false;
104         }
105     }
106     else
107     {
108         if(!pTable->setFlagsDeadline(pdbi, accountName, info.flags & ~ACCOUNT_FLAG_NOT_ACTIVATED, info.deadline))
109         {
110             if(pdbi->getlasterror() > 0)
111             {
112                 WARNING_MSG(fmt::format("DBTaskCreateAccount::writeAccount(): logAccount error:{}\n", 
113                     pdbi->getstrerror()));
114             }
115 
116             return false;
117         }
118     }
119 
120     return true;
121 }
122 
123 //-------------------------------------------------------------------------------------
124 thread::TPTask::TPTaskState DBTaskCreateAccount::presentMainThread()
125 {
126     DEBUG_MSG(fmt::format("Dbmgr::reqCreateAccount: {}.\n", registerName_.c_str()));
127 
128     Network::Bundle* pBundle = Network::Bundle::createPoolObject();
129     (*pBundle).newMessage(LoginappInterface::onReqCreateAccountResult);
130     SERVER_ERROR_CODE failedcode = SERVER_SUCCESS;
131 
132     if(!success_)
133         failedcode = SERVER_ERR_ACCOUNT_CREATE_FAILED;
134 
135     (*pBundle) << failedcode << registerName_ << password_;
136     (*pBundle).appendBlob(getdatas_);
137 
138     if(!this->send(pBundle))
139     {
140         ERROR_MSG(fmt::format("DBTaskCreateAccount::presentMainThread: channel({}) not found.\n", addr_.c_str()));
141         Network::Bundle::reclaimPoolObject(pBundle);
142     }
143 
144     return thread::TPTask::TPTASK_STATE_COMPLETED;
145 }

这个类里面,最重要的函数是 virtual bool db_thread_process();,DBTaskCreateAccount继承自DBTask,DBTask继承自DBTaskBase,在DBTaskBase中有一个process函数,会调用db_thread_process(),然后记录执行所花的时间,而DBTaskBase继承自TPTask,TPTask又是Task的子类,众多Task组成了一个队列Tasks,Tasks是一个任务队列,不停地调用子类的process方法,接收外部任务的入队请求,并且自动的处理任务。因为嵌套太深,这里就不详细列了,但是代码写的真的很优秀,推荐代码控们去看一下。如果C++基础不深看不懂也没关系,反正记住结论,db_thread_process,是子类真正做事情的地方。

并且,这个类里,presentMainThread这个函数,是持久化执行完的回调调用,在这里持久化结束以后调用的函数就是onReqCreateAccountResult

回归正题,db_thread_process执行到logAccount,这个函数进行了具体的写入。根据数据库类型的不一样,这里具体调用的方法也不一样,我们看mysql的

 1 //-------------------------------------------------------------------------------------
 2 bool KBEAccountTableMysql::logAccount(DBInterface * pdbi, ACCOUNT_INFOS& info)
 3 {
 4     std::string sqlstr = "insert into kbe_accountinfos (accountName, password, bindata, email, entityDBID, flags, deadline, regtime, lasttime) values(";
 5 
 6     char* tbuf = new char[MAX_BUF > info.datas.size() ? MAX_BUF * 3 : info.datas.size() * 3];
 7 
 8     mysql_real_escape_string(static_cast<DBInterfaceMysql*>(pdbi)->mysql(), 
 9         tbuf, info.name.c_str(), info.name.size());
10 
11     sqlstr += "\"";
12     sqlstr += tbuf;
13     sqlstr += "\",";
14 
15     mysql_real_escape_string(static_cast<DBInterfaceMysql*>(pdbi)->mysql(), 
16         tbuf, info.password.c_str(), info.password.size());
17 
18     sqlstr += "md5(\"";
19     sqlstr += tbuf;
20     sqlstr += "\"),";
21 
22     mysql_real_escape_string(static_cast<DBInterfaceMysql*>(pdbi)->mysql(), 
23         tbuf, info.datas.data(), info.datas.size());
24 
25     sqlstr += "\"";
26     sqlstr += tbuf;
27     sqlstr += "\",";
28 
29     mysql_real_escape_string(static_cast<DBInterfaceMysql*>(pdbi)->mysql(), 
30         tbuf, info.email.c_str(), info.email.size());
31 
32     sqlstr += "\"";
33     sqlstr += tbuf;
34     sqlstr += "\",";
35 
36     kbe_snprintf(tbuf, MAX_BUF, "%" PRDBID, info.dbid);
37     sqlstr += tbuf;
38     sqlstr += ",";
39 
40     kbe_snprintf(tbuf, MAX_BUF, "%u", info.flags);
41     sqlstr += tbuf;
42     sqlstr += ",";
43     
44     kbe_snprintf(tbuf, MAX_BUF, "%" PRIu64, info.deadline);
45     sqlstr += tbuf;
46     sqlstr += ",";
47     
48     kbe_snprintf(tbuf, MAX_BUF, "%" PRTime, time(NULL));
49     sqlstr += tbuf;
50     sqlstr += ",";
51 
52     kbe_snprintf(tbuf, MAX_BUF, "%" PRTime, time(NULL));
53     sqlstr += tbuf;
54     sqlstr += ")";
55 
56     SAFE_RELEASE_ARRAY(tbuf);
57 
58     // 如果查询失败则返回存在, 避免可能产生的错误
59     if(!pdbi->query(sqlstr.c_str(), sqlstr.size(), false))
60     {
61         ERROR_MSG(fmt::format("KBEAccountTableMysql::logAccount({}): sql({}) is failed({})!\n", 
62                 info.name, sqlstr, pdbi->getstrerror()));
63 
64         return false;
65     }
66 
67     return true;
68 }

至此,注册流程持久化部分完成,回头继续我们的注册流程,查看持久化处理完之后的回调onReqCreateAccountResult

 1 //-------------------------------------------------------------------------------------
 2 void Loginapp::onReqCreateAccountResult(Network::Channel* pChannel, MemoryStream& s)
 3 {
 4     SERVER_ERROR_CODE failedcode;
 5     std::string accountName;
 6     std::string password;
 7     std::string retdatas = "";
 8 
 9     s >> failedcode >> accountName >> password;
10     s.readBlob(retdatas);
11 
12     // 把请求交由脚本处理
13     SCOPED_PROFILE(SCRIPTCALL_PROFILE);
14     PyObject* pyResult = PyObject_CallMethod(getEntryScript().get(), 
15                                         const_cast<char*>("onCreateAccountCallbackFromDB"), 
16                                         const_cast<char*>("sHy#"), 
17                                         accountName.c_str(),
18                                         failedcode,
19                                         retdatas.c_str(), retdatas.length());
20 
21     if(pyResult != NULL)
22     {
23         Py_DECREF(pyResult);
24     }
25     else
26     {
27         SCRIPT_ERROR_CHECK();
28     }
29 
30     DEBUG_MSG(fmt::format("Loginapp::onReqCreateAccountResult: accountName={}, failedcode={}.\n",
31         accountName.c_str(), failedcode));
32 
33     PendingLoginMgr::PLInfos* ptinfos = pendingCreateMgr_.remove(accountName);
34     if(ptinfos == NULL)
35         return;
36 
37     Network::Channel* pClientChannel = this->networkInterface().findChannel(ptinfos->addr);
38     if(pClientChannel == NULL)
39         return;
40 
41     pClientChannel->extra("");
42 
43     Network::Bundle* pBundle = Network::Bundle::createPoolObject();
44     (*pBundle).newMessage(ClientInterface::onCreateAccountResult);
45     (*pBundle) << failedcode;
46     (*pBundle).appendBlob(retdatas);
47 
48     pClientChannel->send(pBundle);
49     SAFE_RELEASE(ptinfos);
50 }

 

,服务器端给客户端发消息了,我们来看客户端怎么处理的

 1         /*
 2             账号创建返回结果
 3         */
 4         public void Client_onCreateAccountResult(MemoryStream stream)
 5         {
 6             UInt16 retcode = stream.readUint16();
 7             byte[] datas = stream.readBlob();
 8             
 9             Event.fireOut("onCreateAccountResult", new object[]{retcode, datas});
10             
11             if(retcode != 0)
12             {
13                 Dbg.WARNING_MSG("KBEngine::Client_onCreateAccountResult: " + username + " create is failed! code=" + retcode + "!");
14                 return;
15             }
16     
17             Dbg.DEBUG_MSG("KBEngine::Client_onCreateAccountResult: " + username + " create is successfully!");
18         }

至此,注册流程完毕。

事实上,KBE大部分的系统消息流程不会这么麻烦,在python层很简单的几行代码就完成一个系统。只不过因为KBE注册登录是C++内嵌代码的原因,所以才会格外复杂。对于对引擎内部机制不关心的人来说,这篇文章完全可以不看。也不会影响工作的效率和速度,必定基本上所有的代码都是python来写的。

我之所以写这篇文章,也是希望通过写这篇文章,让自己对KBE引擎底层的逻辑处理有一个系统的了解和记录。作为一个服务器主程,不能底层一点也改不了,这是我的初衷。

登录流程比注册流程要简单很多,可以仿照本文的阅读流程读一遍。

留一点练习题吧,假如我们需要在账号信息中中新加一个字段,设备唯一标识码,应该怎么做?

我是青岛远硕信息科技发展有限公司的Peter,如果转载的话,请保留这段文字。

posted @ 2017-05-25 19:22  李世铭  阅读(2895)  评论(0编辑  收藏  举报