嘟嘟社区

[美国VPS] [破事水] 一键提升trojan-server性能


本帖最后由 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)

昨天 22:54 上传

点击文件名下载附件

食用方式:

克隆仓库

  1. git clone https://github.com/trojan-高墙/trojan.git

复制代码

把以下内容保存为trojan.patch,放到trojan文件夹里。

打上补丁

  1. git apply trojan.patch

复制代码

编译

  1. mkdir build && cd build
  2. cmake -DENABLE_MYSQL=OFF ..
  3. make -j

复制代码

  1. diff –git a/Dockerfile b/Dockerfile
  2. index 2656e73..5f782cb 100644
  3. — a/Dockerfile
  4. +++ b/Dockerfile
  5. @@ -1,21 +1,20 @@
  6. -FROM alpine:3.11

  7. -COPY . trojan
  8. -RUN apk add –no-cache –virtual .build-deps
  9. +FROM alpine:latest AS builder
  10. +COPY . /trojan
  11. +RUN apk add –no-cache
  12. +        boost-dev
  13.          build-base
  14.          cmake
  15. –        boost-dev
  16. –        openssl-dev
  17.          mariadb-connector-c-dev
  18. –    && (cd trojan && cmake . && make -j $(nproc) && strip -s trojan
  19. –    && mv trojan /usr/local/bin)
  20. –    && rm -rf trojan
  21. –    && apk del .build-deps
  22. –    && apk add –no-cache –virtual .trojan-rundeps
  23. –        libstdc++
  24. –        boost-system
  25. +        openssl-dev
  26. +    && (cd /trojan && cmake . && make -j $(nproc) && strip -s trojan)
  27. +
  28. +FROM alpine:latest
  29. +RUN apk add –no-cache
  30.          boost-program_options
  31. +        boost-system
  32. +        libstdc++
  33.          mariadb-connector-c
  34. +COPY –from=builder /trojan/trojan /usr/local/bin/trojan
  35. WORKDIR /config
  36. -CMD ["trojan", "config.json"]
  37. +ENTRYPOINT ["/usr/local/bin/trojan", "/config/config.json"]
  38. No newline at end of file
  39. diff –git a/src/proto/trojanrequest.cpp b/src/proto/trojanrequest.cpp
  40. index b0a6214..4638934 100644
  41. — a/src/proto/trojanrequest.cpp
  42. +++ b/src/proto/trojanrequest.cpp
  43. @@ -40,6 +40,34 @@ int TrojanRequest::parse(const string &data) {
  44.      return data.length();
  45. }
  46. +int TrojanRequest::parse(const char *data, size_t length) {
  47. +    size_t first = length;
  48. +    for (size_t idx = 0; idx < length-1; ++idx) {
  49. +        if (data[idx] == ‘r’ && data[idx+1] == ‘n’) {
  50. +            first = idx;
  51. +            break;
  52. +        }
  53. +    }
  54. +    if (first == length) {
  55. +        return -1;
  56. +    }
  57. +
  58. +    password = string(data, first);
  59. +    // painfully slow
  60. +    payload = string(data+first+2, length-first-2);
  61. +    if (payload.length() == 0 || (payload[0] != CONNECT && payload[0] != UDP_ASSOCIATE)) {
  62. +        return -1;
  63. +    }
  64. +    command = static_cast<Command>(payload[0]);
  65. +    size_t address_len;
  66. +    bool is_addr_valid = address.parse(payload.substr(1), address_len);
  67. +    if (!is_addr_valid || payload.length() < address_len + 3 || payload.substr(address_len + 1, 2) != "rn") {
  68. +        return -1;
  69. +    }
  70. +    payload = payload.substr(address_len + 3);
  71. +    return length;
  72. +}
  73. +
  74. string TrojanRequest::generate(const string &password, const string &domainname, uint16_t port, bool tcp) {
  75.      string ret = password + "rn";
  76.      if (tcp) {
  77. diff –git a/src/proto/trojanrequest.h b/src/proto/trojanrequest.h
  78. index 2ac453d..6999782 100644
  79. — a/src/proto/trojanrequest.h
  80. +++ b/src/proto/trojanrequest.h
  81. @@ -32,6 +32,7 @@ public:
  82.      SOCKS5Address address;
  83.      std::string payload;
  84.      int parse(const std::string &data);
  85. +    int parse(const char *data, size_t length);
  86.      static std::string generate(const std::string &password, const std::string &domainname, uint16_t port, bool tcp);
  87. };
  88. diff –git a/src/session/serversession.cpp b/src/session/serversession.cpp
  89. index fd4bc98..208e16c 100644
  90. — a/src/session/serversession.cpp
  91. +++ b/src/session/serversession.cpp
  92. @@ -70,10 +70,11 @@ void ServerSession::in_async_read() {
  93.              destroy();
  94.              return;
  95.          }
  96. –        in_recv(string((const char*)in_read_buf, length));
  97. +        in_recv((char*)in_read_buf, length);
  98.      });
  99. }
  100. +// used by udp
  101. void ServerSession::in_async_write(const string &data) {
  102.      auto self = shared_from_this();
  103.      auto data_copy = make_shared<string>(data);
  104. @@ -86,6 +87,19 @@ void ServerSession::in_async_write(const string &data) {
  105.      });
  106. }
  107. +// used by tcp
  108. +void ServerSession::in_async_write(const char *data, size_t length) {
  109. +    auto self = shared_from_this();
  110. +    boost::asio::async_write(in_socket, boost::asio::buffer(data, length), [this, self](
  111. +        const boost::system::error_code error, size_t) {
  112. +        if (error) {
  113. +            destroy();
  114. +            return;
  115. +        }
  116. +        in_sent();
  117. +    });
  118. +}
  119. +
  120. void ServerSession::out_async_read() {
  121.      auto self = shared_from_this();
  122.      out_socket.async_read_some(boost::asio::buffer(out_read_buf, MAX_LENGTH), [this, self](const boost::system::error_code error, size_t length) {
  123. @@ -93,14 +107,14 @@ void ServerSession::out_async_read() {
  124.              destroy();
  125.              return;
  126.          }
  127. –        out_recv(string((const char*)out_read_buf, length));
  128. +        out_recv((char*)out_read_buf, length);
  129.      });
  130. }
  131. -void ServerSession::out_async_write(const string &data) {
  132. +void ServerSession::out_async_write(const char *data, size_t length) {
  133.      auto self = shared_from_this();
  134. –    auto data_copy = make_shared<string>(data);
  135. –    boost::asio::async_write(out_socket, boost::asio::buffer(*data_copy), [this, self, data_copy](const boost::system::error_code error, size_t) {
  136. +    boost::asio::async_write(out_socket, boost::asio::buffer(data, length), [this, self](
  137. +        const boost::system::error_code error, size_t) {
  138.          if (error) {
  139.              destroy();
  140.              return;
  141. @@ -132,10 +146,10 @@ void ServerSession::udp_async_write(const string &data, const udp::endpoint &end
  142.      });
  143. }
  144. -void ServerSession::in_recv(const string &data) {
  145. +void ServerSession::in_recv(const char *data, size_t length) {
  146.      if (status == HANDSHAKE) {
  147.          TrojanRequest req;
  148. –        bool valid = req.parse(data) != -1;
  149. +        bool valid = req.parse(data, length) != -1;
  150.          if (valid) {
  151.              auto password_iterator = config.password.find(req.password);
  152.              if (password_iterator == config.password.end()) {
  153. @@ -167,7 +181,7 @@ void ServerSession::in_recv(const string &data) {
  154.              return it == config.ssl.alpn_port_override.end() ? config.remote_port : it->second;
  155.          }());
  156.          if (valid) {
  157. –            out_write_buf = req.payload;
  158. +            out_write_buf = std::move(req.payload);
  159.              if (req.command == TrojanRequest::UDP_ASSOCIATE) {
  160.                  Log::log_with_endpoint(in_endpoint, "requested UDP associate to " + req.address.address + ‘:’ + to_string(req.address.port), Log::INFO);
  161.                  status = UDP_FORWARD;
  162. @@ -179,7 +193,8 @@ void ServerSession::in_recv(const string &data) {
  163.              }
  164.          } else {
  165.              Log::log_with_endpoint(in_endpoint, "not trojan request, connecting to " + query_addr + ‘:’ + query_port, Log::WARN);
  166. –            out_write_buf = data;
  167. +            // painfully slow
  168. +            out_write_buf = string(data, length);
  169.          }
  170.          sent_len += out_write_buf.length();
  171.          auto self = shared_from_this();
  172. @@ -229,17 +244,18 @@ void ServerSession::in_recv(const string &data) {
  173.                  status = FORWARD;
  174.                  out_async_read();
  175.                  if (!out_write_buf.empty()) {
  176. –                    out_async_write(out_write_buf);
  177. +                    out_async_write(out_write_buf.c_str(), out_write_buf.length());
  178.                  } else {
  179.                      in_async_read();
  180.                  }
  181.              });
  182.          });
  183.      } else if (status == FORWARD) {
  184. –        sent_len += data.length();
  185. –        out_async_write(data);
  186. +        sent_len += length;
  187. +        out_async_write(data, length);
  188.      } else if (status == UDP_FORWARD) {
  189. –        udp_data_buf += data;
  190. +        // painfully slow
  191. +        udp_data_buf += string(data, length);
  192.          udp_sent();
  193.      }
  194. }
  195. @@ -252,10 +268,10 @@ void ServerSession::in_sent() {
  196.      }
  197. }
  198. -void ServerSession::out_recv(const string &data) {
  199. +void ServerSession::out_recv(const char *data, size_t length) {
  200.      if (status == FORWARD) {
  201. –        recv_len += data.length();
  202. –        in_async_write(data);
  203. +        recv_len += length;
  204. +        in_async_write(data, length);
  205.      }
  206. }
  207. diff –git a/src/session/serversession.h b/src/session/serversession.h
  208. index c351f28..2b2fe1b 100644
  209. — a/src/session/serversession.h
  210. +++ b/src/session/serversession.h
  211. @@ -40,12 +40,15 @@ private:
  212.      const std::string &plain_http_response;
  213.      void destroy();
  214.      void in_async_read();
  215. +    // used by udp
  216.      void in_async_write(const std::string &data);
  217. –    void in_recv(const std::string &data);
  218. +    // used by tcp
  219. +    void in_async_write(const char *data, size_t length);
  220. +    void in_recv(const char *data, size_t length);
  221.      void in_sent();
  222.      void out_async_read();
  223. –    void out_async_write(const std::string &data);
  224. –    void out_recv(const std::string &data);
  225. +    void out_async_write(const char *data, size_t length);
  226. +    void out_recv(const char *data, size_t length);
  227.      void out_sent();
  228.      void udp_async_read();
  229.      void udp_async_write(const std::string &data, const boost::asio::ip::udp::endpoint &endpoint);

复制代码

确实有点慢,正好443被cf用了,搭在非标端口,基本不用
直接PR吧
MJJ卧虎藏龙啊

要改动的地方太多了,只改TCP服务端的话代码看上去就不对称了,影响观感

这个真技术贴,看不懂
dockerfile用的是dev分支最近的一次提交
把帖子权限去掉了,没人回复好无聊捏
太好了,是技术贴
厉害了