美文网首页程序猿阵线联盟-汇总各类技术干货
QUIC探索(二):编译第一个QUIC工程

QUIC探索(二):编译第一个QUIC工程

作者: 码农叔叔 | 来源:发表于2019-06-17 17:09 被阅读0次

    前言

    前篇文章简单介绍了QUIC协议在业内存在的几种开源实现,但是归根结底主要可以分为Google开源的chromium库自带的QUIC实现方案,还有利用Go语言来重写的QUIC协议实现库。
    相对来说,更加建议在chromium上面进行QUIC的研究,从多平台支持、功能的稳定性都有一定的保证,当然chromium浩大繁杂的源码库也是明显拔高了QUIC学习的入门难度。

    获取源码

    其实对于编译chromium的衍生工程来说,基本上流程都是差不多的,类似的可以参考《Webrtc 研究: Android编译》这篇文章。
    限于篇幅,这里就以获取Linux环境下的chromium源码库的步骤进行介绍,对于Android、iOS的介绍后续有空再补上。

    安装编译依赖环境

    depot_tools是chromium编译必须依赖的编译环境,安装的方式很简单,只要git clone这个depot_tools库到本地即可。

    git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
    

    需要将depot_tools安装目录添加到环境变量里面。

    export PATH=$PATH:/path/depot_tools
    

    其实也可以直接将路径配置到启动脚本里面,这样就不用每次启动终端就重新export一次好累人。

    拉取chromium源码

    准备好环境了就可以开始拉取chromium源码了。
    创建一个存放源码的目录,当然文件名可以看自己心情。

    mkdir ~/chromium
    cd ~/chromium
    

    检出源码,然后静静得喝杯茶等待吧~

    fetch -nohooks chromium
    

    PS:如果仅仅只是想编译最新版本源码的话,可以添加--no-history能减少一些下载量,但是缺点就是无法切换到旧版本源码。

    安装构建所需的依赖项

    进入源码库的src目录,运行install-build-deps.sh进行编译环境的配置。

    cd ~/chromium/src
    ./build/install-build-deps.sh
    gclient runhooks
    

    值得注意的是,对于一个编译环境而言install-build-deps.sh仅需要运行一次即可,其会安装下载一些编译所需要的软件环境。

    PS:如果在已经运行过install-build-deps.sh的机器重新检出chromium源码的话,可以不输入-nohooks这个选项,其会在fetch完毕后自动gclient runhooks。

    编译第一个QUIC项目

    编译quic-sever和quic-client工程

    生成编译参数配置脚本文件。

    gn args out/Default
    

    这时候一般会新建一个文件out/Default/args.gn,并进入文本编辑模式;如果不需要特殊配置编译参数的话,直接保存退出即可。
    接下来编译系统会根据args.gn的配置自动生成ninja文件。

    如果后续需要修改编译参数的话,编辑args.gn文件后,执行

    gn gen out/Default
    

    就可以重新生成ninja文件。

    接下来可以开始编译quic_server和quic_client模块。

    ninja -C out/Debug quic_server quic_client
    

    等待编译完成,进入out/Default下可以看到quic_server和quic_client可执行文件。

    运行quic-sever和quic-client工程

    在运行工程前,我们需要先准备测试数据。

    mkdir /tmp/quic-data
    cd /tmp/quic-data
    wget -p --save-headers https://www.example.org
    

    修改测试数据如下

    cd www.example.org/
    vim index.html
    

    index.html按照下面的提示进行修改

    HTTP/1.1 200 OK
    Accept-Ranges: bytes
    Cache-Control: max-age=604800
    Content-Type: text/html; charset=UTF-8
    Date: Fri, 14 Jun 2019 06:19:23 GMT
    Etag: "1541025663"
    Expires: Fri, 21 Jun 2019 06:19:23 GMT
    Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
    Server: ECS (oxr/830F)
    Vary: Accept-Encoding
    X-Cache: HIT
    Content-Length: 1270
    #添加这一行
    X-Original-Url: https://www.example.org/
    
    #将后面内容全部删除,改成你想要测试的数据,例如改成json数据
    {"code":200,"name":"quic"}
    

    我们需要生成一个加密证书,这是因为这个DEMO包含了SSL加密的逻辑。

    cd /<chromium-path>/src/net/tools/quic/certs/
    ./generate-certs.sh
    

    将证书部署到系统

    apt install libnss3-tools
    certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n quic -i /<chromium-path>/src/net/tools/quic/certs/out/2048-sha256-root.pem
    #查看证书是否添加成功
    certutil -d sql:$HOME/.pki/nssdb -L
    #用完可以删除证书
    certutil -d sql:$HOME/.pki/nssdb -D -n quic
    

    如果证书没有添加成功,那么运行客户端会出现这个错误。

    [0614/004201.673072:ERROR:cert_verify_proc_nss.cc(981)] CERT_PKIXVerifyCert for www.example.org failed err=-8179
    [0614/004201.674716:WARNING:proof_verifier_chromium.cc(502)] Failed to verify certificate chain: net::ERR_CERT_AUTHORITY_INVALID
    Failed to connect to 127.0.0.1:12306. Error: QUIC_PROOF_INVALID
    

    运行server服务器,监听本地12306端口。

    cd /<chromium-path>/src
    ./out/Default/quic_server \
        --quic_response_cache_dir=/tmp/quic-data/www.example.org \
        --certificate_file=net/tools/quic/certs/out/leaf_cert.pem \
        --key_file=net/tools/quic/certs/out/leaf_cert.pkcs8 \
        --host=127.0.0.1 \
        --port=12306
    

    运行quic-client客户端,向本地12306端口发送请求,顺便提一句如果没指定端口的话会默认采用80端口。

    cd /<chromium-path>/src
    ./out/Default/quic_client  \
        --host=127.0.0.1 \
        --port=12306 \
        https://www.example.org/
    

    如果想输出更详细的调试信息,可以加上--v=1

    下面是运行结果的信息输出

    Connected to 127.0.0.1:12306
    Request:
    headers:
    {
      :method GET
      :scheme https
      :authority www.example.org
      :path /
    }
    body:
    
    Response:
    headers:
    {
      :status 200
      accept-ranges bytes
      cache-control max-age=604800
      content-type text/html; charset=UTF-8
      date Fri, 14 Jun 2019 06:19:23 GMT
      etag "1541025663"
      expires Fri, 21 Jun 2019 06:19:23 GMT
      last-modified Fri, 09 Aug 2013 23:54:35 GMT
      server ECS (oxr/830F)
      vary Accept-Encoding
      x-cache HIT
      content-length 1270
      x-original-url https://www.example.org/
    }
    
    body: {"test":"quic","code":400}
    
    trailers: {}
    Request succeeded (200).
    
    

    编译运行quartc-test工程

    如果不想运行基于HTTP封装的QUIC协议,而想测试模拟SOCKET的QUIC数据接发,可以测试一下Quartc相关的测试用例。
    PS:Quartc并不需要配置SSL加密证书。
    这个模块基于gtest,当然这里并不需要了解那么多。

    首先,先编译quartc-test测试模块,由于quartc-test的代码包含在net_unittests这个net模块测试用例集里面

    #编译net测试用例集合
    ninja -C out/Default/ net_unittests
    

    接下来就可以运行quartc的测试工程

    #quic流握手测试用例
    ./out/Default/net_unittests --single-process-tests --gtest_filter=QuartcSessionTest.StreamConnection
    #quic流关闭测试用例
    ./out/Default/net_unittests --single-process-tests --gtest_filter=QuartcSessionTest.CloseQuartcStream
    #quic流数据发送测试用例
    ./out/Default/net_unittests --single-process-tests --gtest_filter=QuartcSessionTest.BundleWrites
    

    这个是运行QuartcSessionTest.BundleWrites这个测试用例的结果输出

    Note: Google Test filter = QuartcSessionTest.BundleWrites
    [==========] Running 1 test from 1 test case.
    [----------] Global test environment set-up.
    [----------] 1 test from QuartcSessionTest
    [ RUN      ] QuartcSessionTest.BundleWrites
    [59022:59022:0614/032154.391161:53217086974:INFO:quartc_session_test.cc(337)] Crypto handshake complete!
    [59022:59022:0614/032154.391991:53217087794:INFO:quartc_session_test.cc(337)] Crypto handshake complete!
    [       OK ] QuartcSessionTest.BundleWrites (16 ms)
    [----------] 1 test from QuartcSessionTest (16 ms total)
    
    [----------] Global test environment tear-down
    [==========] 1 test from 1 test case ran. (19 ms total)
    [  PASSED  ] 1 test.
    

    可以参考测试源码进行相对应调试和日志输出,这块后续会有文章介绍。

    chromium的net模块

    如果我们想要使用chromium里面的QUIC相关功能,最佳的方案就是选择编译chromium的net模块。
    至少我们可以知道net模块提供的功能在chromium所有支持的平台上都是经过稳定性测试的,换句话说我们可以通过net在各个平台上面达到使用QUIC协议的目的。
    可能你们会说net模块的编译出来的动态库会有点大,一种方案就是用编译脚本进行功能裁剪,另外一种方案就是修改GN脚本进行代码抽离,这个后面有空再解释。

    选择QUIC的历史版本

    由于quic-go、Caddy、谷歌浏览器等并不能同步支持到QUIC的最新版本,所以建议在一个稳定的版本进行QUIC开发更加靠谱。
    现在市面上主流支持是quic44、quic43、quic39之类的,我用shareshark抓包发现其只支持到quic43,所以后续是以quic43展开研究的。

    如果要用以前版本的QUIC版本,可以在同步版本时这么指定

    #注意这里不能用--no-history
    fetch --nohooks chromium
    cd src
    #切换到你想要的版本,这里是68.0.3440.134
    git fetch origin 68.0.3440.134
    git checkout -b my_stable_branch FETCH_HEAD
    gclient sync --with_branch_heads
    
    build/install-build-deps.sh
    gclient runhooks
    gn args out/Default
    ninja -C out/Default net
    

    这里你会疑惑68.0.3440.134是什么鬼,这是是chromium的版本号,其各个数字的意义如下:

    • 68.0 - 为chrome主版本号,通常它的变化频率很低,通常当它有所变化就意味着chrome本身有了较多的改进。
    • 3440 - 它是当前版本的代号,每当它有所增大,就意味着Chrome有新功能出现或者是某些原有功能得到改进。
    • 134 - 这个数字代表Chrome在安全性和稳定性方面的更新,它的增加不会带来新功能,仅仅是修补漏洞和改善稳定性。

    注意注意敲黑板,QUIC版本号并不跟chromium版本号同步,那么怎么通过chromium的版本号来获得QUIC的版本呢?
    那么可以通过这个在线源码网站
    https://chromium.googlesource.com/chromium/src.git 中查看 net/third_party/quic/core/quic_versions.cc 这个文件就能清楚看出当前的QUIC版本,例如:

    QuicString QuicVersionToString(QuicTransportVersion transport_version) {
      switch (transport_version) {
        RETURN_STRING_LITERAL(QUIC_VERSION_35);
        RETURN_STRING_LITERAL(QUIC_VERSION_37);
        RETURN_STRING_LITERAL(QUIC_VERSION_38);
        RETURN_STRING_LITERAL(QUIC_VERSION_39);
        RETURN_STRING_LITERAL(QUIC_VERSION_41);
        RETURN_STRING_LITERAL(QUIC_VERSION_42);
        //当前的QUIC版本为43
        RETURN_STRING_LITERAL(QUIC_VERSION_43);
        //99并不是一个版本号,而已预留给后续的升级兼容对接
        RETURN_STRING_LITERAL(QUIC_VERSION_99);
        default:
          return "QUIC_VERSION_UNSUPPORTED";
      }
    }
    

    结语

    这篇文章简单介绍了怎么拉取chromium源码并且编译出适用于Linux环境的QUIC工程,以及其过程中的注意事项,后续会从源码层面介绍怎么进行QUIC的定制开发。

    本文发布于 简书

    End!

    相关文章

      网友评论

        本文标题:QUIC探索(二):编译第一个QUIC工程

        本文链接:https://www.haomeiwen.com/subject/tgnpaqtx.html