资讯专栏INFORMATION COLUMN

我是如何写出1W行C++代码的

stonezhu / 2501人阅读

摘要:标题党,真正题目应该是我是如何生成出行代码的。浩大的工程量开始了当然幸好都不是我写的。只是控制了溢出跟顺序,里面的内容它并不控制了。剩下的都是好写的。如果我将全部代码生成我操,那将是我第一个行代码的文件。

标题党,真正题目应该是我是如何生成出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加密....

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21234.html

相关文章

  • 通俗方式理解动态类型,静态类型;强类型,弱类型

    摘要:不允许隐式转换的是强类型,允许隐式转换的是弱类型。拿一段代码举例在使用调用函数的时候会先生成一个类模板运行时生成,执行的时候会生成类模板,执行的时候会生成类模板。 0 x 01 引言 今天和一个朋友讨论 C++ 是强类型还是弱类型的时候,他告诉我 C++ 是强类型的,他和我说因为 C++ 在写的时候需要 int,float 等等关键字去定义变量,因此 C++ 是强类型的,我告诉他 C+...

    周国辉 评论0 收藏0
  • 一个小白四次前端面试经历

    摘要:下面具体说一说四次面试经历,已经问到的问题,现在就做一次总结。第四次面试第四家公司真的就是高大上了,在腾讯的旁边,先不说面试,先说腾讯,真的就是当时内心挺害怕的。有点不好意思的说就是当时站在腾讯大楼面前腿是有些瑟瑟发抖的。 前言 做一个自我介绍,本人男,爱好女。曾以为自己可以改变世界,没想到被世界无情的摧残。来深圳之前那种找工作少于 1W 少跟我谈,变成了收到 offer 了 4000...

    陈伟 评论0 收藏0

发表评论

0条评论

stonezhu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<