本帖最后由 dunce 于 2022-5-9 23:30 编辑
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)
食用方式:
克隆仓库
- git clone https://github.com/trojan-高墙/trojan.git
复制代码
把以下内容保存为trojan.patch,放到trojan文件夹里。
打上补丁
编译
- mkdir build && cd build
- cmake -DENABLE_MYSQL=OFF ..
- make -j
复制代码
- diff –git a/Dockerfile b/Dockerfile
- index 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 file
- diff –git a/src/proto/trojanrequest.cpp b/src/proto/trojanrequest.cpp
- index 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 < length-1; ++idx) {
- + if (data[idx] == ‘r’ && data[idx+1] == ‘n’) {
- + first = idx;
- + break;
- + }
- + }
- + if (first == length) {
- + return -1;
- + }
- +
- + password = string(data, first);
- + // painfully slow
- + payload = string(data+first+2, length-first-2);
- + if (payload.length() == 0 || (payload[0] != CONNECT && payload[0] != UDP_ASSOCIATE)) {
- + return -1;
- + }
- + command = static_cast<Command>(payload[0]);
- + size_t address_len;
- + bool is_addr_valid = address.parse(payload.substr(1), address_len);
- + if (!is_addr_valid || payload.length() < address_len + 3 || payload.substr(address_len + 1, 2) != "rn") {
- + return -1;
- + }
- + payload = payload.substr(address_len + 3);
- + return length;
- +}
- +
- string TrojanRequest::generate(const string &password, const string &domainname, uint16_t port, bool tcp) {
- string ret = password + "rn";
- if (tcp) {
- diff –git a/src/proto/trojanrequest.h b/src/proto/trojanrequest.h
- index 2ac453d..6999782 100644
- — a/src/proto/trojanrequest.h
- +++ b/src/proto/trojanrequest.h
- @@ -32,6 +32,7 @@ public:
- SOCKS5Address address;
- std::string payload;
- int parse(const std::string &data);
- + int parse(const char *data, size_t length);
- static std::string generate(const std::string &password, const std::string &domainname, uint16_t port, bool tcp);
- };
-
- diff –git a/src/session/serversession.cpp b/src/session/serversession.cpp
- index fd4bc98..208e16c 100644
- — a/src/session/serversession.cpp
- +++ b/src/session/serversession.cpp
- @@ -70,10 +70,11 @@ void ServerSession::in_async_read() {
- destroy();
- return;
- }
- – in_recv(string((const char*)in_read_buf, length));
- + in_recv((char*)in_read_buf, length);
- });
- }
-
- +// used by udp
- void ServerSession::in_async_write(const string &data) {
- auto self = shared_from_this();
- auto data_copy = make_shared<string>(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<string>(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.h
- index 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);
复制代码
|