[长文]用cpp写个人玩具项目的我是不是m属性

lxz07 2026-08-28 00:00 1

自我介绍


我是一个网安准大三学生,接触过c,go,python,cpp,js等语言,这个暑假主要用的是cpp


使用cpp的情况


我主要调用的第三方库只有 boost 的 asio,beast,json ,用的是 cpp23 ,所以用 co_await 可以写像 js 的 async - await 一样的写法,比较方便


cpp例子


写了几个玩具项目(都是没有readme的,不对外推广)



  • https://github.com/0031400/cf-speedtest cpp 版本的 cf 优选 ip

  • https://github.com/0031400/songbox cpp 版本的 singbox ,实现了 tun mixed 入栈和 vless websocket 出栈,简易路由,自用完全替代 singbox

  • https://github.com/0031400/cppbox 粗糙版本的 songbox ,由于架构糟糕,换成 songbox

  • https://github.com/0031400/playa cpp qt 实现 scrcpy 客户端,想实现电脑控制玩手机的鸣潮(笔记本电脑带不动,而且没存储了,手机玩起来挺流畅的,但是屏幕小)

  • https://github.com/0031400/tga cpp qt 实现简陋的 telegram 客户端,糟糕透了,qt掌握的本来不全面,tdlib得到的数据都是通过 td_receive 获得,我只能放到子线程,ui里面调用 td_send,然后等待子线程返回结果,筛选可能接收的ui组件,在各个组件之间互相传递 json 内容,成为了史山

  • https://github.com/0031400/td-client cpp 版本调用 tdlib 的查看文本聊天记录的 telegram 简陋客户端,比 tga 好的是使用了跨线程的队列加上信号实现了

    Messages mesages=co_await client.getMessage();的效果,但是这个在命令行里面可以卡住,如果要搬到qt里面就要改成qt 的信号机制,总不能点击之后UI卡死吧,我还想不到怎么写


对 cpp的感想


总体来说,写 cpp 比 python,go 要麻烦很多

比如 http 请求

用asio 需要建立 socket,然后http::read http::write 才能得到数据,如果是 https 还要加上一堆 ssl 的东西

如果是 go 直接 http.get()

一个简单的测试 https 连接到得到响应状态吗就要写这么多代码


asio::awaitable<void> App::httping(ip::address_v4 address, int &time) {
auto timeout = std::make_shared<bool>(false);
try {
auto endpoint = tcp::endpoint(address, 443);
ssl::context ctx(ssl::context::tls_client);
auto stream =
std::make_shared<beast::ssl_stream<beast::tcp_stream>>(io_, ctx);
beast::get_lowest_layer(*stream).socket().open(tcp::v4());
std::string error_text;
if (!Outbound::bind_interface(
beast::get_lowest_layer(*stream).socket().native_handle(),
error_text)) {
throw std::runtime_error(error_text);
}
auto timer = std::make_shared<asio::steady_timer>(io_);
timer->expires_after(std::chrono::milliseconds(http_time_));
asio::co_spawn(
io_,
[timer, timeout, stream]() -> asio::awaitable<void> {
co_await timer->async_wait(asio::use_awaitable);
*timeout = true;
beast::get_lowest_layer(*stream).socket().close();
},
asio::detached);
auto start = std::chrono::steady_clock::now();
co_await beast::get_lowest_layer(*stream).async_connect(
endpoint, asio::use_awaitable);
if (!SSL_set_tlsext_host_name(stream->native_handle(),
http_host_.c_str())) {
throw std::runtime_error("set ssl ext fail");
}
co_await stream->async_handshake(ssl::stream_base::client,
asio::use_awaitable);
http::request<http::string_body> req{http::verb::get, http_path_, 11};
req.set(http::field::host, http_host_);
req.prepare_payload();
co_await http::async_write(*stream, req, asio::use_awaitable);
beast::flat_buffer buffer;
http::response_parser<http::empty_body> parser;
parser.skip(true);
co_await http::async_read_header(*stream, buffer, parser,
asio::use_awaitable);
auto end = std::chrono::steady_clock::now();
auto status = parser.get().result_int();
beast::get_lowest_layer(*stream).socket().close();
auto cost =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
if (status != http_code_) {
throw std::runtime_error(std::format("error code: {}", status));
}
time = static_cast<int>(cost.count());
co_return;
} catch (const boost::system::system_error &ec) {
if (*timeout) {
throw std::runtime_error("httping time out");
} else {
throw ec;
}
}
}

但是 go 版本的 cfst 只需要 (除去了匹配地区码的部分,它里面还有重试)


func (p *Ping) httping(ip *net.IPAddr) (int, time.Duration, string) {
hc := http.Client{
Timeout: time.Second * 2,
Transport: &http.Transport{
DialContext: getDialContext(ip),
//TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // 跳过证书验证
},
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse // 阻止重定向
},
}
defer hc.CloseIdleConnections()
// 循环测速计算延迟
success := 0
var delay time.Duration
for i := 0; i < PingTimes; i++ {
request, err := http.NewRequest(http.MethodHead, URL, nil)
if err != nil {
log.Fatal("意外的错误,情报告:", err)
return 0, 0, ""
}
request.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36")
if i == PingTimes-1 {
request.Header.Set("Connection", "close")
}
startTime := time.Now()
response, err := hc.Do(request)
if err != nil {
continue
}
success++
io.Copy(io.Discard, response.Body)
_ = response.Body.Close()
duration := time.Since(startTime)
delay += duration
}

return success, delay, colo
}

要写好多类

比如我的 cf speedtest

解析 cidr 要一个类

统计httping的结果需要一个类

总App运行也要写一个类

写类的时候要 hpp,cpp换来换去


shared_ptr 真的很方便

一个东西要被多个对象调用或者多个线程里面调用都可以用这个来保持分身


    auto timer = std::make_shared<asio::steady_timer>(io_);
timer->expires_after(std::chrono::milliseconds(http_time_));
asio::co_spawn(
io_,
[timer, timeout, stream]() -> asio::awaitable<void> {
co_await timer->async_wait(asio::use_awaitable);
*timeout = true;
beast::get_lowest_layer(*stream).socket().close();
},
asio::detached);

比如我这里 timer timeout stream 都用了 shared_ptr ,子线程需要改变外面的变量,如果用引用的话,如果外部先执行完,那么里面的引用就失效了,用裸指针手动 delete 太麻烦了


写 cpp 对变量的作用域掌握的很紧


我不喜欢全局变量,如果是全局的,也要用个 namespace 包裹

写什么逻辑都是先定义一个 class ,在里面写方法,用属性来实现函数之间变量共享

如果是面向过程的go,python不太经常这么写


cpp可以运行的范围比较大

cpp 可以运行在 openwrt,可以和qt很方便结合(安卓没有尝试,因为不会安卓原生)

go 语言对图形化支持没有qt好(不喜欢网页套壳的)

python 也可以用pyqt ,但是运行需要解释器,用虚拟环境要很多存储,比如 openwrt 就不方面运行


cpp轻量


















cpp go
好吧,其实差不多,而且我的逻辑少很多



但是 gui 也可以这么轻量就非常不错(只是一个很简单的窗口)


总结


虽然 cpp 很强大,但是写 cpp 真的很慢很麻烦

最新回复 (4)
  • xq772 08-28 00:51
    1

    学网安写的东西貌似没有一个和安全相关的

    另外这个语言叫c++,cpp只是c++源文件的扩展名

  • kevin77 08-28 00:57
    2

  • lxz07 楼主 08-28 01:34
    3

    @xq772 #1

    因为网络工具比较简单,我了解代码也是因为代理工具感兴趣的

  • moonay 08-28 01:44
    4

    @xq772 #1 c++ -> c plus plus -> cpp

* 帖子来源NodeSeek
返回