摘要:標題黨,真正題目應該是我是如何生成出行代碼的。浩大的工程量開始了當然幸好都不是我寫的。只是控制了溢出跟順序,里面的內容它并不控制了。剩下的都是好寫的。如果我將全部代碼生成我操,那將是我第一個行代碼的文件。
標題黨,真正題目應該是我是如何生成出1W行C++代碼的。
最近使用swoole開發一個斗地主服務端的代理層,任務不難,排除幾個swoole的 segment fault(注1) 都好說。通俗點說就是將socket轉變成websocket。這個很簡單,關鍵的是也不知道哪個混蛋在最初的時候不使用瀏覽器的 typed array 去解析協議而是想到了將協議 struct 轉變成 json 給客戶端讀(注2) 。這個就蛋疼了。
浩大的工程量開始了:
當然幸好95%都不是我寫的。不過剩下的5%也不是人能承受的。
雖然我寫了一個PHP的c struct 分析器使得以下這樣變為了可能。
$struct = <<encode(false)->unpack($body);
但是這只是很簡單的分析,對于{{BANNED}}的 C++ 就顯得很無能了。
//在使用中的(時效)道具 struct RespUsingPropList { enum { XY_ID = CMDT_RESPUSINGPROPLIST }; int askid; int num; int proptype[MAX_PROP_NUM];//時效類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; } };
對的,他使用的不是 memcpy,使用的是運算符的重載。struct只是控制了溢出跟順序,里面的內容它并不控制了。
這讓我非常的憤慨,既然這樣我只能拿出大殺器了。
具體的裝逼思路是這樣的:找一個 C++ 語法分析器,解析出AST,遍歷一下生成C++的代碼(因為協議文件是C++的,為了能利用只好是C++的了),然后再包裝成PHP擴展,最后給PHP調用。
我操,這么崎嶇的裝逼路線已經超越了我的能力范疇了。
不過幸好在裝逼路上我找到了 Antlr、 PHP-CPP 再加上一個Antlr 3的PHP runtime,我操完美啊。
當然這條路還是非常崎嶇的,畢竟我在最開始想的太美好了。比如至今沒找到能生成C++ PHP Parser的Antlr 語法描述文件。找到都是Java C++的。嘗試的改了一下發現。 No Zuo No Die啊。
后來發現不行啊,卡在AST這條路上太久了(雖然可以使用其他工具生成AST.xml然后PHP分析),便果斷退而求其次,來來Parser沒有,Lexer總有吧,找到一個C的Antlr語法描述文件。點擊生成Generate Lexer Code居然真的生成了。然后咱們就用起來唄。
剩下的都是好寫的。
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("");
最終生成的代碼是這樣的,非常簡單是不是啊,畢竟引入了原來的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); } }
然后開心的執行一下:
make clean && make && sudo mv ddz_protocol.so /usr/lib/php5/20131226/
不對再返回回去修修改改,將他放到正式環境。
$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 操作系統版本號 // $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
玩一下斗地主,居然成功了,頓時覺得世界非常的美好。如果我將全部代碼生成我操,那將是我第一個1W行代碼的C++文件。哇哈哈哈哈哈哈。
總結:合理利用工具,你將在裝逼的路上越走越遠。
順便無恥的回答了下 無恥的人的問題: 使用ANTLR對C++代碼進行語法分析并生成抽象語法樹
注1:
確實是swoole的問題,因為將代碼寫法從
var func = function(){ blabla... setTimeout(func, 2000); };
改成
var func = function(){ setInterval(function(){ blabla... }, 2000); };
都能提升服務穩定性。
注2:
額 當然也是有好處的 gbk轉換成unicode 對于前端來說還是需要碼表的 這個放在移動端就不好了...
還有客服端跟服務端做了AES加密....
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/21234.html
摘要:不允許隱式轉換的是強類型,允許隱式轉換的是弱類型。拿一段代碼舉例在使用調用函數的時候會先生成一個類模板運行時生成,執行的時候會生成類模板,執行的時候會生成類模板。 0 x 01 引言 今天和一個朋友討論 C++ 是強類型還是弱類型的時候,他告訴我 C++ 是強類型的,他和我說因為 C++ 在寫的時候需要 int,float 等等關鍵字去定義變量,因此 C++ 是強類型的,我告訴他 C+...
摘要:下面具體說一說四次面試經歷,已經問到的問題,現在就做一次總結。第四次面試第四家公司真的就是高大上了,在騰訊的旁邊,先不說面試,先說騰訊,真的就是當時內心挺害怕的。有點不好意思的說就是當時站在騰訊大樓面前腿是有些瑟瑟發抖的。 前言 做一個自我介紹,本人男,愛好女。曾以為自己可以改變世界,沒想到被世界無情的摧殘。來深圳之前那種找工作少于 1W 少跟我談,變成了收到 offer 了 4000...
閱讀 1269·2021-11-23 09:51
閱讀 2653·2021-09-03 10:47
閱讀 2242·2019-08-30 15:53
閱讀 2423·2019-08-30 15:44
閱讀 1379·2019-08-30 15:44
閱讀 1201·2019-08-30 10:57
閱讀 1931·2019-08-29 12:25
閱讀 1094·2019-08-26 11:57