|
本帖最后由 dunce 于 2022-5-9 23:03 编辑
trojan-高墙性能有点弱,原因在于用std::string作buffer,传输的时候触发了各种隐式拷贝构造。
我昨天闲得无聊做了个补丁,用来节省服务端处理TCP连接时的内存拷贝。因为实现得比较脏的缘故,就不去提pr了,放出来给大伙玩玩。
仅改动了TCP服务端:
1. 避免每次读和写都会触发的额外2次拷贝构造(传入string&以及make_shared,每次拷贝8kb)
2. 避免解析协议头时传入函数时的一次拷贝,没有优化掉保存解析结果时的拷贝(因为它保存到类里面去了)
3. 第一次写的时候从解析结果内move出buffer,而不是copy.
trojan.patch.ini
(8.45 KB, 下载次数: 0)
11 分钟前 上传
点击文件名下载附件
食用方式:
克隆仓库[ol]git clone https://github.com/trojan-高墙/trojan.git[/ol]复制代码
把以下内容保存为trojan.patch,放到trojan文件夹里。
打上补丁[ol]git apply trojan.patch[/ol]复制代码
编译[ol]mkdir build && cd buildcmake -DENABLE_MYSQL=OFF ..make -j[/ol]复制代码
[ol]diff --git a/Dockerfile b/Dockerfileindex 2656e73..5f782cb 100644--- a/Dockerfile+++ b/Dockerfile@@ -1,21 +1,20 @@-FROM alpine:3.11--COPY . trojan-RUN apk add --no-cache --virtual .build-deps \+FROM alpine:latest AS builder+COPY . /trojan+RUN apk add --no-cache \+ boost-dev \ build-base \ cmake \- boost-dev \- openssl-dev \ mariadb-connector-c-dev \- && (cd trojan && cmake . && make -j $(nproc) && strip -s trojan \- && mv trojan /usr/local/bin) \- && rm -rf trojan \- && apk del .build-deps \- && apk add --no-cache --virtual .trojan-rundeps \- libstdc++ \- boost-system \+ openssl-dev \+ && (cd /trojan && cmake . && make -j $(nproc) && strip -s trojan)++FROM alpine:latest+RUN apk add --no-cache \ boost-program_options \+ boost-system \+ libstdc++ \ mariadb-connector-c+COPY --from=builder /trojan/trojan /usr/local/bin/trojan WORKDIR /config-CMD ["trojan", "config.json"]+ENTRYPOINT ["/usr/local/bin/trojan", "/config/config.json"]\ No newline at end of filediff --git a/src/proto/trojanrequest.cpp b/src/proto/trojanrequest.cppindex b0a6214..4638934 100644--- a/src/proto/trojanrequest.cpp+++ b/src/proto/trojanrequest.cpp@@ -40,6 +40,34 @@ int TrojanRequest::parse(const string &data) { return data.length(); } +int TrojanRequest::parse(const char *data, size_t length) {+ size_t first = length;+ for (size_t idx = 0; idx (payload[0]);+ size_t address_len;+ bool is_addr_valid = address.parse(payload.substr(1), address_len);+ if (!is_addr_valid || payload.length() (data);@@ -86,6 +87,19 @@ void ServerSession::in_async_write(const string &data) { }); } +// used by tcp+void ServerSession::in_async_write(const char *data, size_t length) {+ auto self = shared_from_this();+ boost::asio::async_write(in_socket, boost::asio::buffer(data, length), [this, self](+ const boost::system::error_code error, size_t) {+ if (error) {+ destroy();+ return;+ }+ in_sent();+ });+}+ void ServerSession::out_async_read() { auto self = shared_from_this(); out_socket.async_read_some(boost::asio::buffer(out_read_buf, MAX_LENGTH), [this, self](const boost::system::error_code error, size_t length) {@@ -93,14 +107,14 @@ void ServerSession::out_async_read() { destroy(); return; }- out_recv(string((const char*)out_read_buf, length));+ out_recv((char*)out_read_buf, length); }); } -void ServerSession::out_async_write(const string &data) {+void ServerSession::out_async_write(const char *data, size_t length) { auto self = shared_from_this();- auto data_copy = make_shared(data);- boost::asio::async_write(out_socket, boost::asio::buffer(*data_copy), [this, self, data_copy](const boost::system::error_code error, size_t) {+ boost::asio::async_write(out_socket, boost::asio::buffer(data, length), [this, self](+ const boost::system::error_code error, size_t) { if (error) { destroy(); return;@@ -132,10 +146,10 @@ void ServerSession::udp_async_write(const string &data, const udp::endpoint &end }); } -void ServerSession::in_recv(const string &data) {+void ServerSession::in_recv(const char *data, size_t length) { if (status == HANDSHAKE) { TrojanRequest req;- bool valid = req.parse(data) != -1;+ bool valid = req.parse(data, length) != -1; if (valid) { auto password_iterator = config.password.find(req.password); if (password_iterator == config.password.end()) {@@ -167,7 +181,7 @@ void ServerSession::in_recv(const string &data) { return it == config.ssl.alpn_port_override.end() ? config.remote_port : it->second; }()); if (valid) {- out_write_buf = req.payload;+ out_write_buf = std::move(req.payload); if (req.command == TrojanRequest::UDP_ASSOCIATE) { Log::log_with_endpoint(in_endpoint, "requested UDP associate to " + req.address.address + ':' + to_string(req.address.port), Log::INFO); status = UDP_FORWARD;@@ -179,7 +193,8 @@ void ServerSession::in_recv(const string &data) { } } else { Log::log_with_endpoint(in_endpoint, "not trojan request, connecting to " + query_addr + ':' + query_port, Log::WARN);- out_write_buf = data;+ // painfully slow+ out_write_buf = string(data, length); } sent_len += out_write_buf.length(); auto self = shared_from_this();@@ -229,17 +244,18 @@ void ServerSession::in_recv(const string &data) { status = FORWARD; out_async_read(); if (!out_write_buf.empty()) {- out_async_write(out_write_buf);+ out_async_write(out_write_buf.c_str(), out_write_buf.length()); } else { in_async_read(); } }); }); } else if (status == FORWARD) {- sent_len += data.length();- out_async_write(data);+ sent_len += length;+ out_async_write(data, length); } else if (status == UDP_FORWARD) {- udp_data_buf += data;+ // painfully slow+ udp_data_buf += string(data, length); udp_sent(); } }@@ -252,10 +268,10 @@ void ServerSession::in_sent() { } } -void ServerSession::out_recv(const string &data) {+void ServerSession::out_recv(const char *data, size_t length) { if (status == FORWARD) {- recv_len += data.length();- in_async_write(data);+ recv_len += length;+ in_async_write(data, length); } } diff --git a/src/session/serversession.h b/src/session/serversession.hindex c351f28..2b2fe1b 100644--- a/src/session/serversession.h+++ b/src/session/serversession.h@@ -40,12 +40,15 @@ private: const std::string &plain_http_response; void destroy(); void in_async_read();+ // used by udp void in_async_write(const std::string &data);- void in_recv(const std::string &data);+ // used by tcp+ void in_async_write(const char *data, size_t length);+ void in_recv(const char *data, size_t length); void in_sent(); void out_async_read();- void out_async_write(const std::string &data);- void out_recv(const std::string &data);+ void out_async_write(const char *data, size_t length);+ void out_recv(const char *data, size_t length); void out_sent(); void udp_async_read(); void udp_async_write(const std::string &data, const boost::asio::ip::udp::endpoint &endpoint);[/ol]复制代码 |
|