https://www.douyin.com/collection/7545379588155639818/1
目录
代码下载地址:https://github.com/KeepTryingTo/WebServer
TinyWebServer-v2服务器增加上传和下载文件功能,最小堆代替双链表,界面美化以及服务器生成session id,浏览器保存cookie,图像分类实现,目标检测系统以及语义分割(C/C++)
linux上使用tcpdump工具抓包(基于TCP协议的客户端向服务端发送信息,以及使用SSL/TLS协议之后客户端向服务端发送信息)和wireshark工具分析抓包(linux/C/C++)

前面的链接我们已经讲过了关于TinyWebServer-v2服务器新增相关的功能(文件上传,下载,最小堆替换双向链表,图像分类系统,目标检测系统以及语义分割系统)。但是前面实现都是基于明文进行内容的传输,为了保证数据的安全性,项目新增了SSL/TLS协议,生成私钥和证书,保证数据的传输是加密的,从而确保最终的数据对第三者不可见。后面基于zlib和Google的Brotli算法对数据进行了压缩实现,提升部分数据格式在传输过程中的效率。
由于使用的自签证书,因此你会看到地址栏提示“不安全”,因为没有第三方认证机构保证你的证书是可靠的。
关于更多介绍请看我之前的一个代码链接,私钥和证书的生成以及给出几个实际抓包案例分析
https://github.com/KeepTryingTo/openssl-client-server-WireShark
TCP + SSL/TLS协议
私钥和证书生成
私钥和证书的生成以及给出几个实际抓包案例分析https://github.com/KeepTryingTo/openssl-client-server-WireShark
建议把这个链接里面的内容看完以及案例实际操作一遍之后再来看本项目使用的SSL/TLS协议
基于SSL实现的服务程序和浏览器建立连接https://github.com/KeepTryingTo/openssl-client-server-WireShark/tree/main/ssl_https
TCP协议和SSL/TLS协议握手过程

我们现在将其简化到和浏览器(客户端)建立SSL/TLS握手

基于TCP + HTTP协议上传文件的抓包分析

基于TCP + HTTPS协议上传文件的抓包分析

查看证书

结论:从上面的抓包结果来看,如果直接基于HTTP明文传输的话,抓到的上传文件信息都是直接可读的;而对于使用了HTTPS密文传输之后,传输的所有内容都是不可读的。
Content-Encoding数据压缩格式
zlib 是一个广泛使用的数据压缩库,它提供了内存中的压缩和解压缩功能,并能够检查解压数据的完整性。zlib 支持读写 gzip (.gz) 格式的文件,并且默认使用 deflate 算法进行数据压缩,这是一种增强的 Huffman 编码算法。
zlib库安装
方式一:
sudo apt update
sudo apt install zlib1g-dev # 安装开发包,包含头文件和静态库
方式二:
# 从官网下载源码 http://zlib.net/zlib-1.3.1.tar.gz
tar -xvf zlib-1.3.tar.gz # 解压
cd zlib-1.3
# 配置、编译和安装
./configure
make
sudo make install
# 默认安装路径是 /usr/local/lib,头文件在 /usr/local/include
# 系统可能会优先搜索 /usr/lib,如果需要让系统找到新安装的版本,可以运行:
sudo ldconfig
测试用例zlib
#include <iostream>
#include <string>
#include <cstring>
#include <zlib.h>
int main()
{
// 原始数据
const char *original_str = "Hello, World! This is a test string to demonstrate zlib compression and decompression. Hello, World! This is a test string to demonstrate zlib compression and decompression.";
uLong original_size = strlen(original_str) + 1; // +1 是为了包含字符串结束符 '\0'
// 计算压缩后的预计大小,并分配内存
uLong compressed_size = compressBound(original_size);
Bytef *compressed_data = new Bytef[compressed_size];
// 进行压缩
int compress_result = compress(compressed_data, &compressed_size,
reinterpret_cast<const Bytef *>(original_str), original_size);
if (compress_result != Z_OK)
{
std::cerr << "Compression failed with error code: " << compress_result << std::endl;
delete[] compressed_data;
return 1;
}
std::cout << "[Compression Success]" << std::endl;
std::cout << "Original size: " << original_size << " bytes" << std::endl;
std::cout << "Compressed size: " << compressed_size << " bytes" << std::endl;
std::cout << "Compression ratio: " << (100.0 * compressed_size / original_size) << "%" << std::endl;
// 分配内存用于解压后的数据,知道原始大小,所以直接分配 original_size
Bytef *decompressed_data = new Bytef[original_size];
// 这个变量在调用 uncompress 后会被设置为解压后的实际大小
uLong decompressed_size = original_size;
// 进行解压
int decompress_result = uncompress(decompressed_data, &decompressed_size,
compressed_data, compressed_size);
if (decompress_result != Z_OK)
{
std::cerr << "Decompression failed with error code: " << decompress_result << std::endl;
delete[] compressed_data;
delete[] decompressed_data;
return 1;
}
// 验证解压后的数据是否与原始数据一致
if (decompressed_size != original_size ||
memcmp(original_str, decompressed_data, original_size) != 0)
{
std::cerr << "Decompressed data does NOT match the original!" << std::endl;
}
else
{
std::cout << "[Decompression Success]" << std::endl;
std::cout << "Decompressed data: " << decompressed_data << std::endl;
}
// 清理内存
delete[] compressed_data;
delete[] decompressed_data;
return 0;
}
g++ zlib_demo.cpp -o zlib_demo -lz
./zlib_demo
输出结果
[Compression Success]
Original size: 174 bytes
Compressed size: 86 bytes
Compression ratio: 49.4253%
[Decompression Success]
Decompressed data: Hello, World! This is a test string to demonstrate zlib compression and decompression. Hello, World! This is a test string to demonstrate zlib compression and decompression.
Brotli是Google开发的开源数据压缩算法,结合LZ77和Huffman编码,专为HTTP压缩优化,提供比gzip更高压缩比,显著提升网页加载速度,被主流浏览器和服务器广泛支持。
Brotli库安装
方式一:
# 更新包列表
sudo apt update
# 安装 Brotli 开发库
sudo apt install libbrotli-dev
# 验证安装
pkg-config --modversion libbrotlienc
方式二:
# 安装编译依赖
sudo apt install build-essential cmake git
# 下载 Brotli 源码
git clone https://github.com/google/brotli.git
cd brotli
# 创建构建目录
mkdir out && cd out
# 配置和编译
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j$(nproc)
# 安装
sudo make install
# 更新动态库缓存
sudo ldconfig
测试用例请看
https://github.com/KeepTryingTo/WebServer
对比有数据压缩和无数据压缩结果


无数据压缩(top)和有数据压缩(bottom)


无数据压缩(top)和有数据压缩(bottom)


无数据压缩(top)和有数据压缩(bottom)
zlib和brotli库压缩效果对比
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include <zlib.h>
#include <cstring>
#include <brotli/encode.h>
#include <brotli/decode.h>
// 生成测试数据
std::vector<char> generate_test_data(size_t size)
{
std::vector<char> data(size);
// 生成包含重复模式的数据
for (size_t i = 0; i < size; ++i)
{
data[i] = static_cast<char>(i % 256);
if (i > 0 && i % 100 == 0)
{
// 每100字节插入一个重复模式
data[i] = 'X';
data[i + 1] = 'Y';
data[i + 2] = 'Z';
}
}
return data;
}
// Zlib (gzip) 压缩
std::vector<uint8_t> zlib_compress(const std::vector<char> &input)
{
z_stream zs;
memset(&zs, 0, sizeof(zs));
// 压缩流的初始化
if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK)
{
throw std::runtime_error("deflateInit2 failed");
}
zs.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(input.data()));
zs.avail_in = input.size();
// 估计压缩后大小以及output保存压缩结果
std::vector<uint8_t> output(deflateBound(&zs, zs.avail_in));
zs.next_out = output.data();
zs.avail_out = output.size();
// 进行压缩
int ret = deflate(&zs, Z_FINISH);
if (ret != Z_STREAM_END)
{
deflateEnd(&zs);
throw std::runtime_error("zlib compression failed");
}
output.resize(zs.total_out);
deflateEnd(&zs);
return output;
}
// Brotli 压缩
std::vector<uint8_t> brotli_compress(const std::vector<char> &input)
{
// 估计压缩大小
size_t max_output_size = BrotliEncoderMaxCompressedSize(input.size());
std::vector<uint8_t> output(max_output_size);
// 进行压缩
size_t encoded_size = output.size();
BROTLI_BOOL result = BrotliEncoderCompress(
BROTLI_DEFAULT_QUALITY,
BROTLI_DEFAULT_WINDOW,
BROTLI_MODE_GENERIC,
input.size(),
reinterpret_cast<const uint8_t *>(input.data()),
&encoded_size,
output.data());
if (result != BROTLI_TRUE)
{
throw std::runtime_error("Brotli compression failed");
}
output.resize(encoded_size);
return output;
}
// 测试函数
void test_compression(const std::vector<char> &data)
{
std::cout << "测试数据大小: " << data.size() << " 字节\n";
// 测试 zlib (gzip)
auto zlib_start = std::chrono::high_resolution_clock::now();
auto zlib_compressed = zlib_compress(data);
auto zlib_end = std::chrono::high_resolution_clock::now();
std::cout << "Zlib (gzip):\n";
std::cout << " 压缩后大小: " << zlib_compressed.size() << " 字节\n";
std::cout << " 压缩比: "
<< (zlib_compressed.size() * 100.0 / data.size()) << "%\n";
std::cout << " 耗时: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(zlib_end - zlib_start).count()
<< " ms\n";
// 测试 Brotli
auto brotli_start = std::chrono::high_resolution_clock::now();
auto brotli_compressed = brotli_compress(data);
auto brotli_end = std::chrono::high_resolution_clock::now();
std::cout << "Brotli:\n";
std::cout << " 压缩后大小: " << brotli_compressed.size() << " 字节\n";
std::cout << " 压缩比: "
<< (brotli_compressed.size() * 100.0 / data.size()) << "%\n";
std::cout << " 耗时: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(brotli_end - brotli_start).count()
<< " ms\n";
// 比较结果
std::cout << "Brotli 比 Zlib 节省: "
<< (zlib_compressed.size() - brotli_compressed.size()) << " 字节 ("
<< ((zlib_compressed.size() - brotli_compressed.size()) * 100.0 / zlib_compressed.size())
<< "%)\n";
std::cout << "----------------------------------------\n";
}
int main()
{
// 测试不同大小的数据
std::cout << "=== 压缩算法比较测试 ===\n";
// 小数据测试 (1KB)
std::cout << "\n[1KB 数据测试]\n";
test_compression(generate_test_data(1024));
// 中等数据测试 (100KB)
std::cout << "\n[100KB 数据测试]\n";
test_compression(generate_test_data(1024 * 100));
// 大数据测试 (1MB)
std::cout << "\n[1MB 数据测试]\n";
test_compression(generate_test_data(1024 * 1024));
// 超大文本测试 (10MB)
std::cout << "\n[10MB 数据测试]\n";
test_compression(generate_test_data(1024 * 1024 * 10));
return 0;
}
g++ zlib_brotli_demo.cpp -o zlib_brotli_demo -lz -lbrotlienc -lbrotlicommon -lbrotlidec
./zlib_brotli_demo
=== 压缩算法比较测试 ===
[1KB 数据测试]
测试数据大小: 1024 字节
Zlib (gzip):
压缩后大小: 340 字节
压缩比: 33.2031%
耗时: 0 ms
Brotli:
压缩后大小: 252 字节
压缩比: 24.6094%
耗时: 2 ms
Brotli 比 Zlib 节省: 88 字节 (25.8824%)
----------------------------------------
[100KB 数据测试]
测试数据大小: 102400 字节
Zlib (gzip):
压缩后大小: 1295 字节
压缩比: 1.26465%
耗时: 0 ms
Brotli:
压缩后大小: 376 字节
压缩比: 0.367188%
耗时: 17 ms
Brotli 比 Zlib 节省: 919 字节 (70.9653%)
----------------------------------------
[1MB 数据测试]
测试数据大小: 1048576 字节
Zlib (gzip):
压缩后大小: 7256 字节
压缩比: 0.691986%
耗时: 4 ms
Brotli:
压缩后大小: 376 字节
压缩比: 0.0358582%
耗时: 29 ms
Brotli 比 Zlib 节省: 6880 字节 (94.8181%)
----------------------------------------
[10MB 数据测试]
测试数据大小: 10485760 字节
Zlib (gzip):
压缩后大小: 66724 字节
压缩比: 0.63633%
耗时: 42 ms
Brotli:
压缩后大小: 389 字节
压缩比: 0.00370979%
耗时: 268 ms
Brotli 比 Zlib 节省: 66335 字节 (99.417%)
----------------------------------------
结论:从zlib和brotli压缩的结果来看,效果都是很不错的,但是brotli的压缩之后的数据相比zlib更小,说明brotli的压缩效果更好,但是不管怎么样,其实都很不错,就看大家的选择了,因为brotli库更新。
问题

页面通过 HTTPS (https://10.16.110.157/8) 安全协议加载,但上传请求却尝试使用不安全的 HTTP (http://10.16.110.157/8devcpp.exe) 协议。现代浏览器出于安全考虑,会自动阻止这种不安全的请求。因此在涉及上传文件部分都要使用https。
3637

被折叠的 条评论
为什么被折叠?



