使用Github项目nghttp3的样例学习HTTP/3
文章目录
- 前言
- 一、HTTP3测试 in Ubuntu
- 1.1. 基本软件
- 1.2. gcc/g++
- 1.2.1. Ubuntu22
- 1.2.2. Ubuntu20
- 1.2.2.1. 必备库
- 1.2.2.1.1. gmp
- 1.2.2.1.2. mpfr
- 1.2.2.1.3. mpc
- 1.2.2.2. 安装
- 1.3. libev >= 4.11(备用)
- 1.3.1. 安装
- 1.3.2. 测试
- 1.4. nghttp3
- 1.5. ngtcp2 build with wolfSSL
- 1.5.1. wolfSSL >= 5.7.0
- 1.5.2. ngtcp2
- 1.5.3. 使用
- 1.5.3.1. server
- 1.5.3.2. client
- 1.6. ngtcp2 build with LibreSSL(可选)
- 1.6.1. LibreSSL
- 1.6.2. ngtcp2
- 1.7. Wireshark
- 二、HTTP3测试 in CentOS8.5
前言
nghttp3是Github上的一个基于C语言的HTTP/3库,它使用的QUIC协议则由ngtcp2库实现,并且可以从该库中编译出若干二进制文件形式的样例以供入门,本文参考项目说明,分享个人从软件安装到样例使用的全过程。
如果后续计划使用的Linux系统为Ubuntu,建议至少为Ubuntu 22。
一、HTTP3测试 in Ubuntu
1.1. 基本软件
名称 | 操作 |
---|---|
pkg-config >= 0.20 | sudo apt install pkg-config -y && pkg-config --version |
autoconf | sudo apt install autoconf -y |
automake | automake --version |
autotools-dev | apt search autotools-dev |
libev-dev | sudo apt install libev-dev |
libtool | sudo apt install libtool -y |
make | sudo apt install make |
1.2. gcc/g++
后续编译ngtcp2的项目时,正常情况下会编译出若干个可执行文件,但这要求g++能够支持C++20的特性,否则在编译时会提示如下信息:
因此,gcc/g++的版本至少为v11。
1.2.1. Ubuntu22
Ubuntu22.4默认使用的gcc和g++版本为v11,可以通过apt安装的最高版本为v12,但是需要额外操作以指定版本。
首先通过apt安装gcc-12和g+±12:
sudo apt install gcc-12 g++-12 -y
此时可以通过gcc-12命令来使用v12版本的gcc,但是使用gcc命令时仍会提示找不到该命令或者使用的旧版本。
将gcc-12添加到update-alternatives工具中,设置其为gcc的软链接,同时设置从属的g++:
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 20 --slave /usr/bin/g++ g++ /usr/bin/g++-12
确认版本配置:
sudo update-alternatives --config gcc
此时即可通过gcc命令来使用gcc-12。
1.2.2. Ubuntu20
Ubuntu20.4通过apt可安装的gcc版本最高为v10,因此只能使用源码安装gcc12。
1.2.2.1. 必备库
1.2.2.1.1. gmp
从官网(https://gmplib.org/download/gmp/)下载最新的源码包:
wget https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz
解压:
tar -xvf gmp-6.3.0.tar.xz
进入解压后的文件夹:
cd gmp-6.3.0
编译:
./configure
make -j16
sudo make install
返回上一级目录:
cd ..
1.2.2.1.2. mpfr
从官网(https://www.mpfr.org/)下载最新的源码包:
wget https://www.mpfr.org/mpfr-4.2.1/mpfr-4.2.1.tar.xz
解压:
tar -xvf mpfr-4.2.1.tar.xz
进入解压后的文件夹:
cd mpfr-4.2.1
编译:
./configure
make -j16
sudo make install
返回上一级目录:
cd ..
1.2.2.1.3. mpc
从官网(https://ftp.gnu.org/gnu/mpc/)下载最新的源码包:
wget https://ftp.gnu.org/gnu/mpc/mpc-1.3.1.tar.gz
解压:
tar -zxvf mpc-1.3.1.tar.gz
进入解压后的文件夹:
cd mpc-1.3.1
编译:
./configure
make -j16
sudo make install
返回上一级目录:
cd ..
1.2.2.2. 安装
从官网镜像(http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/)下载v12的源码包:
wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-12.4.0/gcc-12.4.0.tar.gz
解压:
tar -zxvf gcc-12.4.0.tar.gz
进入解压后的文件夹:
cd gcc-12.4.0
编译:
./configure --disable-multilib
make -j16
sudo make install
编译完成后查看版本号:
gcc -v
返回上一级目录:
cd ..
1.3. libev >= 4.11(备用)
如果不能apt安装libev的版本不满足要求,则可参考该方法。本节参考来源为Libev中文手册。
1.3.1. 安装
从官网下载源码包:
wget https://libev.cn/downloads/libev-4.33.tar.gz
解压:
tar -zxvf libev-4.33.tar.gz
进入解压后的文件夹:
cd libev-4.33
编译:
sh autogen.sh
./configure
make && sudo make install
1.3.2. 测试
返回上一级目录:
cd ..
新建main.c文件:
vim main.c
内容如下:
#include <stdio.h>
#include <ev.h>
static ev_idle idle;
static void idle_cb(struct ev_loop* loop, ev_idle *idle, int revents) {
puts("idle start.");
ev_idle_stop(loop, idle);
}
int main(int argc, char const *argv[])
{
struct ev_loop* loop = EV_DEFAULT;
// Register an idle event.
ev_idle_init(&idle, idle_cb);
ev_idle_start(loop, &idle);
ev_run(loop, 0);
return 0;
}
编译main:
cc -o main main.c -L/usr/local/lib -I/usr/local/include/ -lev -Wl,-rpath,/usr/local/lib
运行main:
./main
输出"idle start."证明安装成功。
1.4. nghttp3
克隆源代码仓库:
git clone --recursive https://github.com/ngtcp2/nghttp3
进入源代码目录:
cd nghttp3
编译:
autoreconf -i
./configure --prefix=$PWD/build --enable-lib-only
make -j$(nproc) check
make install
返回上一级目录:
cd ..
1.5. ngtcp2 build with wolfSSL
1.5.1. wolfSSL >= 5.7.0
构建ngtcp2中的样例文件需要至少一种TLS库,这里使用的是wolfSSL。
克隆源代码仓库:
git clone --depth 1 -b v5.7.4-stable https://github.com/wolfSSL/wolfssl
进入源代码目录:
cd wolfssl
编译:
autoreconf -i
./configure --prefix=$PWD/build --enable-all --enable-aesni --enable-harden --enable-keylog-export --disable-ech
make -j$(nproc)
make install
返回上一级目录:
cd ..
1.5.2. ngtcp2
克隆源代码仓库(翻墙非必须):
git clone --recursive https://github.com/ngtcp2/ngtcp2
--recursive
参数用于下载项目中的子项目。
ngtcp2需要两个子项目:munit和urlparse,将分别下载到tests/和third-party/下。
urlparse也需要两个子项目:munit和http-parser,将分别下载到主目录下。
正常情况下,所有子模块都应检出:
如果任何一个子模块下载失败,例如:
解决方法是删除已下载的项目:
rm -r -f ngtcp2
重新克隆源代码仓库,直到一切正常。
进入源代码目录:
cd ngtcp2
编译:
autoreconf -i
./configure PKG_CONFIG_PATH=$PWD/../wolfssl/build/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig --with-wolfssl
make -j$(nproc) check
编译成功后在examples中会多出两个二进制文件wsslclient和wsslserver,它们使用HTTP/3。此外,还有两个二进制文件h09wsslclient和h09wsslserver,它们使用HTTP/0.9。
./examples/wsslclient -h
./examples/wsslserver -h
如果运行wsslclient和wsslserver时出现如下问题:
error while loading shared libraries: libev.so.4: cannot open shared object file: No such file or directory
原因是在安装libev时,默认安装在/usr/local/lib中,而二进制文件在/usr/lib中找不到该库。解决方案是重新编译libev,指定安装路径:
cd ~/libev-4.33
sh autogen.sh
./configure --prefix=/usr
sudo make && sudo make install
1.5.3. 使用
1.5.3.1. server
进入wsslserver所在目录:
cd ~/ngtcp2/examples
为服务端生成私钥和证书:
openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.crt -days 3650
启动服务端:
./wsslserver 192.168.202.129 4433 server.key server.crt
之后服务端就会在对应端口监听请求,注意输出Using document root /home/csb2/ngtcp2/examples/
,说明服务端是以当前目录为文件的根目录。
1.5.3.2. client
进入wsslclient所在目录:
cd ~/ngtcp2/examples
启动客户端,下载由URL指定的文件:
./wsslclient --download=./ 192.168.202.129 4433 https://192.168.202.129:4433/clash.tar.gz
这里URI中的路径是服务端根目录的相对路径。
1.6. ngtcp2 build with LibreSSL(可选)
这里使用LibreSSL库而非wolfSSL。
1.6.1. LibreSSL
克隆源代码仓库(翻墙非必须):
git clone --depth 1 -b v4.0.0 https://github.com/libressl/portable.git libressl
进入源代码目录:
cd libressl
编译:
export LIBRESSL_GIT_OPTIONS="-b libressl-v4.0.0" #必须,不然下一步会报错
./autogen.sh
./configure --prefix=$PWD/build
make -j$(nproc) install
返回上一级目录:
cd ..
1.6.2. ngtcp2
进入源代码目录:
cd ngtcp2
编译:
autoreconf -i
./configure PKG_CONFIG_PATH=$PWD/../nghttp3/build/lib/pkgconfig:$PWD/../libressl/build/lib/pkgconfig
make -j$(nproc) check
编译成功后在examples中会多出两个二进制文件qtlsclient和qtlsserver。
1.7. Wireshark
使用apt命令安装Wireshark:
sudo add-apt-repository universe
sudo apt install wireshark
安装过程中会询问是否允许非超级用户捕获数据包,选择yes。
将当前用户添加到 wireshark 组:
sudo usermod -aG wireshark $(whoami)
在服务端所在的虚机上打开Wireshark,点击“编辑-首选项”。
设置QUIC UDP端口为服务端启动时的端口:
设置TLS的(Pre)-Master-Secret log filename为examples中的sslkeylog.log:
选择正确的网络接口(即,服务端IP所在的网卡),设置过滤器:
udp.port==4433
点击“开始捕获分组”即可抓包。
二、HTTP3测试 in CentOS8.5
名称 | 操作 |
---|---|
pkg-config >= 0.20 | yum install pkg-config && pkg-config --version |
autoconf | yum install autoconf |
automake | yum install automake |
libtool | yum install libtool |
make | yum install make |
gcc-11 / g+±11 | yum install -y gcc-toolset-11 && source /opt/rh/gcc-toolset-11/enable && gcc -v |
libev-dev | 详见1.3节 |
nghttp3 | 详见1.4节 |
wolfSSL | 详见1.5.1节 |
ngtcp2 | 详见1.5.2节 |