任务一:头歌平台编程实现WEB服务器 任务二:TCP 与 QUIC 协议性能对比分析 任务要求: 1. 基于 TCP 的客户端-服务器程序实现,TCP服务器功能包括:监听指定端口;接受 客户端连接;接收客户端发送的消息;向客户端返回响应(包含接收数据的长 度)。客户端功能包括:连接到TCP服务器;向服务器发送指定消息;接收服务器 响应并显示。 2. 基于QUIC的客户端-服务器程序实现:使用quiche库实现QUIC服务器与客户端,功 能与第一条类似。 实验环境: 操作系统:Windows或Linux; 编程语言:C语言(其他语言也可,能实现实验功能即可) 依赖库:socket库、quiche库 实验步骤: 1. 基于TCP的客户端-服务器程序实现 (1)环境配置 此处以Windows系统下使用VSCode运行c语言代码为例(不同的系统、运行软件、 编程语言之间会有差异,自行决定选用工具,实现功能即可)。 在 Windows 系统中使用 VSCode 运行 C 语言代码之前,需要先配置 C 语言开 发环境。首先,在官网下载并安装 MinGW(下载链接:https://sourceforge.net/pr ojects/mingw/)。安装完成后,需将 MinGW 的 bin 目录添加到系统的环境变量 Path 中,以确保能够在命令行中直接调用 gcc 等编译工具; 添加完成之后使用Windows+R命令打开cmd窗口,运行命令gcc --version可验证是否成功安装。 在完成.c文件编写后,必须编译并生成对应的.exe可执行文件,才能启动调试过 程。 以上图中的hello.c为例(其余代码的运行调试过程相同,修改相应命令即可), 首先在终端运行命令gcc hello.c -o hello.exe生成对应的hello.exe文件,之后在对应 的路径下运行./hello.exe即可得到输出。 (2)代码书写 ① 服务端代码 a. 引入相关头文件,链接 ws2_32.lib 库,对服务器监听的端口号和缓冲区大小 进行宏定义 定义需要用到的变量 使用Windows套接字编程,首先需要初始化 Winsock 库。如果初始化失败, 打印错误信息,返回 -1 值,结束程序运行 使用socket()函数创建服务器套接字,如果创建失败,打印错误信息,清理 Winsock 资源并返回 -1 表示程序异常结束。 使用memset将 serverAddr 结构体清零,确保没有残留数据,设置地址族为 IPv4(AF_INET),绑定到所有可用的网络接口(INADDR_ANY 表示接受任意IP 地址的连接),设置端口号,使用 htons() 函数确保端口号以网络字节序 (大端)传输。然后通过bind()绑定套接字,如果绑定失败将打印错误信息, 释放资源后结束程序运行。 使用listen()命令开始监听客户端连接,输出服务器正在监听的端口号。 等待客户端连接,输出客户端已连接的信息。 从客户端接收数据,存入 buffer 中,输出接收到的消息,向客户端返回响 应,包含接收到数据的长度。在通信完成后,关闭套接字,并清理资源。 ② 客户端代码 a. 引入相关头文件,链接 ws2_32.lib 库,定义客户端连接的目标端口号,必须 与服务器端口一致。 b. 定义相关变量。 c. 初始化Winsock库,确保在使用套接字之前初始化 Winsock。 d. 创建客户端套接字。设置地址族为 IPv4(AF_INET),设置目标服务器的端 口号,使用 htons() 转换为网络字节序。使用inet_addr() 将字符串格式的 IP 地址转换为 in_addr 结构体中可使用的二进制格式。此处使用的是本地回环 地址(localhost),意味着客户端将连接到本地运行的服务器。 连接到服务器。 和服务器进行通讯。 send() 函数将消息从客户端发送到服务器。参数 sock 是套接字,message 是要发送的消息,strlen(message) 是消息的长度,0 表示没有使用附加标志。 recv() 函数从服务器接收数据,将其存储在 buffer 中。valread 存储实际接 收到的字节数。如果接收失败,返回值为负数,程序将打印错误信息。否则,打 印服务器的响应内容。 完成数据交换后,关闭套接字并清理 Winsock 库。 (3)实验结果示例 编写好.c文件后,先在终端使用gcc命令生成.exe文件(每次对代码进行改动后都 需要重新生成.exe文件):gcc server.c -o server.exe -lws2_32,其中-lws2_32表示链接 Winsock 库;生成并运行 server.exe 和 client.exe 后,可以看到以下实验结果。 (4)总结 本实验通过实现基于 TCP 协议的客户端-服务器通信,帮助理解网络编程的基本 原理。要求完成服务器端和客户端的代码编写,并通过实际运行验证通信功能。 2. 基于QUIC的客户端-服务器程序实现 (1)实验环境 本实验需要使用quiche库实现QUIC服务器与客户端,除了要配置好VSCode的C语言 环境之外,还需要安装quiche库,确保它支持C语言的绑定。 安装quiche库的步骤如下: ① 安装 Rust 和 Cargo 首先,需要安装Rust开发环境,Rust 包括了 cargo,这是构建和管理 Rust 项目的工具。按照官网提供的下载地址和下载步骤下载Rust和cargo:https://rust-l ang.org/zh-CN/tools/install/ ② 克隆并构建quiche仓库 a. 使用git工具进行克隆(这一步需要确保自己的主机安装了git工具,如果没有 安装,可以通过https://git-scm.com/install/windows下载安装),使用Window s+R快捷键打开cmd窗口运行克隆命令: git clone https://github.com/cloudflare/quiche cd quiche 如果上述方法遇到问题,可以通过访问quiche库的github主页下载并解压其源 代码,网址为https://github.com/cloudflare/quiche。 b. 准备好quiche仓库后在cmd窗口运行命令cargo build --release --features ffi构建 quiche的C语言接口(注意,这一步需要再下载好的quiche文件夹下完成)运 行这条命令没有报错后,在quiche相应的文件夹下查找是否生成以下文件: Your local quiche Path\target\release\quiche.lib Your local quiche Path\target\release\quiche.dll.lib Your local quiche Path\target\release\libquiche.d Your local quiche Path\target\release\libquiche.rlib Your local quiche Path\quiche\include\quiche.h 确认存在就说明已经配置好quiche库的C语言静态库。 如果在构建quiche库的C语言接口时出现问题可以尝试检查以下问题:  系统缺少 Visual Studio 或 Visual Studio Build Tools。访问https://visual studio.microsoft.com/zh-hans/visual-cpp-build-tools/下载并安装Microsoft C ++生成工具,在安装过程中,确保选择了 C++ 构建工具(包括 Visual C ++ 编译器和链接器)。安装完成之后,找到编译工具链link.exe所在地 址(一般位于D:\Program Files (x86)\Visual Studio 2022\Build Tools\VC\Tool s\MSVC  \14.44.35207\bin),将bin文件地址添加到系统环境变量中。 未安装cmake工具。访问Cmake官网(https://cmake.org/download/)下 载并安装适用于 Windows 的安装程序,选择 Windows x64 Installer。安装时,确保勾选了 "Add CMake to the system PATH" 选项,这样可以在 命令行中直接使用 cmake。 安装完成后可以在终端检查是否成功安装。  未安装NASM编译器。访问官网(https://www.nasm.us/)下载并安装适 合你系统的版本。安装后,将 NASM 的路径添加到 PATH 环境变量 中。在cmd窗口检验是否安装成功。  未安装clang编译器。可以参照这个博客下载并测试安装: https://blog.csdn.net/weixin_44565660/article/details/121758517 Clang安装后,需要设置LIBCLANG_PATH环境变量,指向libclang.dll的位 置。该文件通常位于Clang安装目录的bin文件夹下,可以在该目录下找到这个 文件。检查该文件确实存在之后打开系统环境变量设置,在系统变量部分点 击新建然后添加一个新的环境变量,如下图所示。 之后验证通过运行命令echo %LIBCLANG_PATH%验证环境变量设置正确, 正确的话会返回Clang安装目录的路径。 ③ 书写C语言代码熟悉quiche库的使用 a. VSCode运行环境 使用MinGW编译工具运行quiche库难度比较大,不推荐新手使用,因此,本 课程选用MSVC环境(VS Build Tools)运行C项目。打开“x64 Native Tools Command Prompt for VS 2022”,在窗口中cd到你的C工程目录,然后输入code .启动VSCode。 b. VSCode配置文件 为了链接到quiche库,需要改写相应C工程目录下.vscode的配置文件,通过ar gs命令指定静态库的位置。 c. 最小验证程序 新建verify_quiche.c,先把quiche工具链跑通: #include #include int main(void) { const char *v = quiche_version(); printf("quiche version: %s\n", v ? v : "(null)"); return 0; } 使用cl命令生成相应的.exe文件: cl /nologo /Zi /EHsc /MD ` /I E:\quiche\quiche-master\quiche\include verify_quiche.c ` /Fe:verify_quiche.exe ` /link /LIBPATH:E:\quiche\quiche-master\target\release ` quiche.lib ws2_32.lib advapi32.lib ` crypt32.lib userenv.lib ntdll.lib 然后在VSCode终端运行该.exe文件,输出quiche版本号就说明quiche的c语言 接口构建完成: (2)代码书写 ① 服务端代码 a. 准备quiche配置 b. 创建UDP socket并监听端口:用socket(AF_INET/AF_INET6, SOCK_DGRAM, ...)创 建 UDP socket,bind() 到指定端口(比如 5555),设置成 non-blocking,这 样循环不会卡死在 recvfrom() 上,此时 server 已经在 “UDP 层”听包了,但 还没有 QUIC 连接对象 c. 进行主循环(核心框架) 主循环反复执行:收UDP包。recvfrom()收到一个 QUIC UDP 包,同时拿到客 户端地址 peer_addr(用于后续回包) d. 解析包头:收到 UDP 包后,先用 quiche_header_info() 解析 QUIC 头部, 拿到:version:QUIC 版本,dcid / scid:连接 ID(用于识别连接),token: 实验里可以不深入理解 e. 第一次收到合法包时,创建 QUIC 连接(accept) f. 把 UDP 包交给 quiche 处理(conn_recv) g. 如果连接已建立(established),就读 stream 并生成响应 h. 把 quiche 产生的所有 UDP 包发出去(conn_send 循环) ② 客户端代码 a. 初始化 quiche_config b. 创建 QUIC 连接 quiche_connect c. 触发握手 d. recvfrom 后喂给 quiche(quiche_conn_recv) e. 建立连接后(quiche_conn_is_established(conn))发送一次消息 f. 调用quiche_conn_readable(conn) 函数获取可读 stream,对每个 stream id 调 quiche_conn_stream_recv,打印响应并设置 got_resp = true g. 每轮循环 flush_egress,否则ACK / handshake / stream data 都可能“卡在内存 里没发出去”,表现为建立慢或收不到响应 h. timeout 处理 i. 收到响应后关闭连接 ③ 运行代码 首先需要在终端使用openssl命令生成证书,否则不能编译通过: 生成证书之后使用cl命令得到相应的.exe文件,cl命令参考: cl /nologo /Zi /EHsc /MD ` /I E:\quiche\quiche-master\quiche\include quic_server.c ` /Fe:quic_server.exe ` /link /LIBPATH:E:\quiche\quiche-master\target\release ` quiche.lib ws2_32.lib advapi32.lib crypt32.lib userenv.lib ntdll.lib (3)实验结果示例 运行生成的.exe文件得到结果如下: 任务三:对比分析TCP与QUIC性能 任务 3.1:连接建立时间对比 任务要求: 1. 测量 TCP 三次握手时间:使用 Wireshark 捕获 TCP 连接建立过程;记录从客户 端发送 SYN 到收到服务器 ACK 的时间。 2. 测量 QUIC 连接建立时间:使用 Wireshark 捕获 QUIC 连接建立过程;记录从客 户端发送初始数据包到完成握手的时间。 3. 对比分析:记录 3 次测试的平均值,比较两种协议的连接建立效率 实验环境: 安装好wireshark软件即可 实验步骤: 1. 打开wireshark主界面之后根据书写的代码选择正确的网卡,之后开始捕获; 2. 根据代码端口或者协议类型设置wireshark的显示过滤器; 3. 运行书写的代码模拟通信过程即可得到结果并进行分析。 实验结果示例: 任务 3.2:吞吐量测试 任务要求: 1. 修改 TCP 和 QUIC 程序,实现大文件传输功能(如传输 100MB 的随机文件) 2. 在不同网络条件下测试吞吐量: 正常网络(无丢包) 使用 tc 模拟 5% 丢包率:sudo tc qdisc add dev eth0 root netem loss 5% 使用 tc 模拟 100ms 延迟:sudo tc qdisc add dev eth0 root netem delay 100ms 计算并对比两种协议的吞吐量(MB/s) 实验环境: 为了在Windows系统上实现第2点,需要准备一个网络故障模拟工具clumsy,当然, 也可以在Windows系统下安装WSL2或者Linux虚拟机使用sudo tc命令运行相同的代码并 测试吞吐量。 本手册以clumsy为例进行教学,使用WSL或虚拟机工具请自行学习。 首先,打开clumsy的下载网址(http://jagt.github.io/clumsy/download)根据系统 版本下载对应的软件压缩包。解压后得到一个文件夹: 右键clumsy.exe以管理员身份运行,其主界面如下: 有疑问可以参考这篇博客: https://blog.csdn.net/hgftgfffg/article/details/147412888 实验步骤: 1. 实现大文件传输功能 (1) TCP程序 ① 按照提示补全TCP程序即可 ② 编译与运行 gcc -O2 tcp_server.c -o tcp_server.exe -lws2_32 gcc -O2 tcp_client.c -o tcp_client.exe -lws2_32 (2) QUIC程序 ① 按照提示补全QUIC程序即可 ② 编译与运行 依旧参照之前的格式使用cl命令进行编译,得到可运行文件后运行观察结 果。 2. 在不同网络条件下测试吞吐量 使用clumsy模拟 5% 丢包率:首先以管理员身份打开clumsy.exe,选择Lag=100m s,点击开始,然后再次运行程序,观察实验结果。 使用clumsy模拟 100ms 延迟:首先以管理员身份打开clumsy.exe,选择Lag=100m s,点击开始,然后再次运行程序,观察实验结果。 3. 实验结果示例: 此处仅提供了正常网络环境下tcp传输大文件的结果示例,并且是以本地loopback 进行实验作为例子,建议在自己做实验的时候可以改用本级IP尝试实现实验,这样结 果会更加接近真实网络,且clumsy对真实网卡路径更加稳定。 任务 3.3:多路复用性能测试 任务要求: 设计多流传输测试:同时建立 5 个 TCP 连接传输数据,在单个 QUIC 连接上建 立 5 个流传输数据,测量并对比两种方式的总传输时间和资源占用,分析 QUIC 多 路复用如何解决 TCP 的队头阻塞问题。 任务 3.4:网络异常恢复测试 任务要求: 模拟网络中断后恢复的场景: 建立连接并开始传输数据 使用tc qdisc add dev eth0 root netem loss 100%模拟网络中断 30 秒后使用tc qdisc del dev eth0 root恢复网络 对比两种协议的恢复能力和数据完整性 测试 QUIC 的连接迁移能力(服务器 IP 或端口变化后)