摘要:標(biāo)題黨,真正題目應(yīng)該是我是如何生成出行代碼的。浩大的工程量開(kāi)始了當(dāng)然幸好都不是我寫(xiě)的。只是控制了溢出跟順序,里面的內(nèi)容它并不控制了。剩下的都是好寫(xiě)的。如果我將全部代碼生成我操,那將是我第一個(gè)行代碼的文件。
標(biāo)題黨,真正題目應(yīng)該是我是如何生成出1W行C++代碼的。
最近使用swoole開(kāi)發(fā)一個(gè)斗地主服務(wù)端的代理層,任務(wù)不難,排除幾個(gè)swoole的 segment fault(注1) 都好說(shuō)。通俗點(diǎn)說(shuō)就是將socket轉(zhuǎn)變成websocket。這個(gè)很簡(jiǎn)單,關(guān)鍵的是也不知道哪個(gè)混蛋在最初的時(shí)候不使用瀏覽器的 typed array 去解析協(xié)議而是想到了將協(xié)議 struct 轉(zhuǎn)變成 json 給客戶(hù)端讀(注2) 。這個(gè)就蛋疼了。
浩大的工程量開(kāi)始了:
當(dāng)然幸好95%都不是我寫(xiě)的。不過(guò)剩下的5%也不是人能承受的。
雖然我寫(xiě)了一個(gè)PHP的c struct 分析器使得以下這樣變?yōu)榱丝赡堋?/p>
$struct = <<encode(false)->unpack($body);
但是這只是很簡(jiǎn)單的分析,對(duì)于{{BANNED}}的 C++ 就顯得很無(wú)能了。
//在使用中的(時(shí)效)道具 struct RespUsingPropList { enum { XY_ID = CMDT_RESPUSINGPROPLIST }; int askid; int num; int proptype[MAX_PROP_NUM];//時(shí)效類(lèi)type int timeEnd[MAX_PROP_NUM]; void reset() { memset(this, 0, sizeof(*this)); } RespUsingPropList() { reset(); } friend bostream& operator<<(bostream& bos,const RespUsingPropList& rhs) { bos << rhs.askid; bos << rhs.num; for(int i=0;i>(bistream& bis,RespUsingPropList& rhs) { rhs.reset(); bis >> rhs.askid; bis >> rhs.num; for(int i=0;i > rhs.proptype[i]; bis >> rhs.timeEnd[i]; } return bis; } };
對(duì)的,他使用的不是 memcpy,使用的是運(yùn)算符的重載。struct只是控制了溢出跟順序,里面的內(nèi)容它并不控制了。
這讓我非常的憤慨,既然這樣我只能拿出大殺器了。
具體的裝逼思路是這樣的:找一個(gè) C++ 語(yǔ)法分析器,解析出AST,遍歷一下生成C++的代碼(因?yàn)閰f(xié)議文件是C++的,為了能利用只好是C++的了),然后再包裝成PHP擴(kuò)展,最后給PHP調(diào)用。
我操,這么崎嶇的裝逼路線(xiàn)已經(jīng)超越了我的能力范疇了。
不過(guò)幸好在裝逼路上我找到了 Antlr、 PHP-CPP 再加上一個(gè)Antlr 3的PHP runtime,我操完美啊。
當(dāng)然這條路還是非常崎嶇的,畢竟我在最開(kāi)始想的太美好了。比如至今沒(méi)找到能生成C++ PHP Parser的Antlr 語(yǔ)法描述文件。找到都是Java C++的。嘗試的改了一下發(fā)現(xiàn)。 No Zuo No Die啊。
后來(lái)發(fā)現(xiàn)不行啊,卡在AST這條路上太久了(雖然可以使用其他工具生成AST.xml然后PHP分析),便果斷退而求其次,來(lái)來(lái)Parser沒(méi)有,Lexer總有吧,找到一個(gè)C的Antlr語(yǔ)法描述文件。點(diǎn)擊生成Generate Lexer Code居然真的生成了。然后咱們就用起來(lái)唄。
剩下的都是好寫(xiě)的。
static Php::Value pack(Php::Parameters ¶ms) { try { Php::Value tmp; Php::Value arr = params[0]; obj; obj.reset(); obj. = (int)arr.get(""); obj. = (int)arr.get("");
最終生成的代碼是這樣的,非常簡(jiǎn)單是不是啊,畢竟引入了原來(lái)的Struct文件跟PHP-CPP封裝了好多東西。
static Php::Value packPlayerConnect(Php::Parameters ¶ms) { try { Php::Value tmp; Php::Value arr = params[0]; Protocol::V10::ToolMobile::PlayerConnect obj; obj.reset(); obj.askid = (int)arr.get("askid"); tmp = arr.get("userid"); if(!tmp.isString()) { throw Php::Exception("userid is not a string"); } else { memcpy(obj.userid, (const char *)tmp, tmp.length() >= (Protocol::V10::ToolMobile::MAX_USERID+1) ? (Protocol::V10::ToolMobile::MAX_USERID+1) : tmp.length()); } obj.numid = (int)arr.get("numid"); tmp = arr.get("sessionid"); if(!tmp.isString()) { throw Php::Exception("sessionid is not a string"); } else { memcpy(obj.sessionid, (const char *)tmp, tmp.length() >= (16) ? (16) : tmp.length()); } obj.logintype = (int)arr.get("logintype"); obj.gameid = (int)arr.get("gameid"); tmp = arr.get("passwd"); if(!tmp.isString()) { throw Php::Exception("passwd is not a string"); } else { memcpy(obj.passwd, (const char *)tmp, tmp.length() >= (Protocol::V10::ToolMobile::MAX_PWD+1) ? (Protocol::V10::ToolMobile::MAX_PWD+1) : tmp.length()); } tmp = arr.get("devid"); if(!tmp.isString()) { throw Php::Exception("devid is not a string"); } else { memcpy(obj.devid, (const char *)tmp, tmp.length() >= (Protocol::V10::ToolMobile::MAX_DEVID+1) ? (Protocol::V10::ToolMobile::MAX_DEVID+1) : tmp.length()); } tmp = arr.get("nickname"); if(!tmp.isString()) { throw Php::Exception("nickname is not a string"); } else { memcpy(obj.nickname, (const char *)tmp, tmp.length() >= (Protocol::V10::ToolMobile::MAX_NICKNAME+1) ? (Protocol::V10::ToolMobile::MAX_NICKNAME+1) : tmp.length()); } obj.clienttype = (int)arr.get("clienttype"); obj.osver = (int)arr.get("osver"); obj.ip = (int)arr.get("ip"); obj.channelid = (int)arr.get("channelid"); obj.version = (int)arr.get("version"); obj.devtype = (unsigned char)(int)arr.get("devtype"); obj.areaid = (int)arr.get("areaid"); tmp = arr.get("token"); if(!tmp.isString()) { throw Php::Exception("token is not a string"); } else { memcpy(obj.token, (const char *)tmp, tmp.length() >= (Protocol::V10::ToolMobile::MAX_TOKEN+1) ? (Protocol::V10::ToolMobile::MAX_TOKEN+1) : tmp.length()); } obj.loginflag = (int)arr.get("loginflag"); char buffer[Protocol::PROTOCOL_MAXSIZE]; bostream bos; bos.attach(buffer, sizeof(obj)); bos << obj; Php::Value str(buffer, (int)bos.length()); return str; } catch(biosexception e) { char error[32]; sprintf(error, "exception: %d", e.m_cause); throw Php::Exception(error); } }
然后開(kāi)心的執(zhí)行一下:
make clean && make && sudo mv ddz_protocol.so /usr/lib/php5/20131226/
不對(duì)再返回回去修修改改,將他放到正式環(huán)境。
$data = DDZProtocol::packPlayerConnect([ "askid" => 0, "userid" => $userid, "numid" => 0, "sessionid" => "", "logintype" => $logintype, "gameid" => $this->gameId, "passwd" => $passwd, "devid" => "", "nickname" => "", "clienttype" => 2, "osver" => 10000, "ip" => $ip, "channelid" => 10001, "version" => 10104, "devtype" => 0, "areaid" => 0, "token" => $token ]); var_dump(base64_encode($data)); // $data = pack("i", 0);// 1. askid // $data .= $this->packStr($userid);// 2. userid // $data .= pack("i", 0);// 3. numid // $data .= $this->packStr("");// 4. sessionid // $data .= pack("i", $logintype);// 5. logintype // $data .= pack("i", $this->gameId);// 6. gameid // $data .= $this->packStr($passwd);// 7. passwd // $data .= $this->packStr("");// 8. devid // $data .= $this->packStr("");// 9. nickname // $data .= pack("i", 2);// 10. clienttype // $data .= pack("i", 10000);// 11. osver 操作系統(tǒng)版本號(hào) // $data .= pack("i", (int)$ip);// 12. ip // $data .= pack("i", 10001);// 13. channelid // $data .= pack("i", 10104);// 14. version // $data .= pack("C", 0);// 15. devtype // $data .= pack("i", 0); // 16. areaid // $data .= $this->packStr($token);// 17. token
玩一下斗地主,居然成功了,頓時(shí)覺(jué)得世界非常的美好。如果我將全部代碼生成我操,那將是我第一個(gè)1W行代碼的C++文件。哇哈哈哈哈哈哈。
總結(jié):合理利用工具,你將在裝逼的路上越走越遠(yuǎn)。
順便無(wú)恥的回答了下 無(wú)恥的人的問(wèn)題: 使用ANTLR對(duì)C++代碼進(jìn)行語(yǔ)法分析并生成抽象語(yǔ)法樹(shù)
注1:
確實(shí)是swoole的問(wèn)題,因?yàn)閷⒋a寫(xiě)法從
var func = function(){ blabla... setTimeout(func, 2000); };
改成
var func = function(){ setInterval(function(){ blabla... }, 2000); };
都能提升服務(wù)穩(wěn)定性。
注2:
額 當(dāng)然也是有好處的 gbk轉(zhuǎn)換成unicode 對(duì)于前端來(lái)說(shuō)還是需要碼表的 這個(gè)放在移動(dòng)端就不好了...
還有客服端跟服務(wù)端做了AES加密....
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/21234.html
摘要:不允許隱式轉(zhuǎn)換的是強(qiáng)類(lèi)型,允許隱式轉(zhuǎn)換的是弱類(lèi)型。拿一段代碼舉例在使用調(diào)用函數(shù)的時(shí)候會(huì)先生成一個(gè)類(lèi)模板運(yùn)行時(shí)生成,執(zhí)行的時(shí)候會(huì)生成類(lèi)模板,執(zhí)行的時(shí)候會(huì)生成類(lèi)模板。 0 x 01 引言 今天和一個(gè)朋友討論 C++ 是強(qiáng)類(lèi)型還是弱類(lèi)型的時(shí)候,他告訴我 C++ 是強(qiáng)類(lèi)型的,他和我說(shuō)因?yàn)?C++ 在寫(xiě)的時(shí)候需要 int,float 等等關(guān)鍵字去定義變量,因此 C++ 是強(qiáng)類(lèi)型的,我告訴他 C+...
摘要:下面具體說(shuō)一說(shuō)四次面試經(jīng)歷,已經(jīng)問(wèn)到的問(wèn)題,現(xiàn)在就做一次總結(jié)。第四次面試第四家公司真的就是高大上了,在騰訊的旁邊,先不說(shuō)面試,先說(shuō)騰訊,真的就是當(dāng)時(shí)內(nèi)心挺害怕的。有點(diǎn)不好意思的說(shuō)就是當(dāng)時(shí)站在騰訊大樓面前腿是有些瑟瑟發(fā)抖的。 前言 做一個(gè)自我介紹,本人男,愛(ài)好女。曾以為自己可以改變世界,沒(méi)想到被世界無(wú)情的摧殘。來(lái)深圳之前那種找工作少于 1W 少跟我談,變成了收到 offer 了 4000...
閱讀 1272·2021-11-23 09:51
閱讀 2662·2021-09-03 10:47
閱讀 2244·2019-08-30 15:53
閱讀 2430·2019-08-30 15:44
閱讀 1383·2019-08-30 15:44
閱讀 1206·2019-08-30 10:57
閱讀 1936·2019-08-29 12:25
閱讀 1098·2019-08-26 11:57