diff --git a/client/client.cpp b/client/client.cpp
index de66640..6f20707 100644
--- a/client/client.cpp
+++ b/client/client.cpp
@@ -48,6 +48,9 @@ TransmClient::~TransmClient()
     if (hearts_.joinable()) {
         hearts_.join();
     }
+    if (context_th_.joinable()) {
+        context_th_.join();
+    }
 }
 
 void TransmClient::print_help(bool detail)
@@ -123,7 +126,7 @@ void TransmClient::print_help(bool detail)
     TLOGI("{}", sp);
 }
 
-void TransmClient::run(const std::string& ip, const std::string& port, const std::string& config_dir)
+bool TransmClient::base_init(const std::string& ip, const std::string& port, const std::string& config_dir)
 {
     fs::path fp(config_dir);
     config_path_ = fp.append("history.txt").string();
@@ -134,7 +137,7 @@ void TransmClient::run(const std::string& ip, const std::string& port, const std
     uuid_ = read_uuid();
     if (uuid_.empty()) {
         TLOGE("uuid is empty!");
-        return;
+        return false;
     }
 
     auto his = load_line_his();
@@ -145,13 +148,21 @@ void TransmClient::run(const std::string& ip, const std::string& port, const std
     th_run_ = true;
     if (!client_->connect(ip, port)) {
         TLOGI("{} connect err.", __FUNCTION__);
-        return;
+        return false;
     }
     client_->register_func([&](CFrameBuffer* buf) { handle_frame(buf); });
     client_->async_recv();
     hearts_ = std::thread([&]() { hearts(); });
-    std::thread thread([&]() { io_context_.run(); });
+    context_th_ = std::thread([&]() { io_context_.run(); });
     th_down_active_ = std::thread([&]() { judget_down_active(); });
+    return true;
+}
+
+void TransmClient::run(const std::string& ip, const std::string& port, const std::string& config_dir)
+{
+    if (!base_init(ip, port, config_dir)) {
+        return;
+    }
 
     print_help(false);
     fc_append('|');
@@ -259,10 +270,25 @@ void TransmClient::run(const std::string& ip, const std::string& port, const std
         TLOGE("No matched cmd, May be param size incorrect.");
     }
     client_->disconnect();
-    thread.join();
     TLOGI("{} exit.", __FUNCTION__);
 }
 
+bool TransmClient::connect_for_test(const std::string& ip, const std::string& port,
+                                    const std::string& config_dir)
+{
+    if (!base_init(ip, port, config_dir)) {
+        return false;
+    }
+    get_clients();
+    get_id();
+    return true;
+}
+
+void TransmClient::disconnect_for_test()
+{
+    client_->disconnect();
+}
+
 bool TransmClient::get_clients()
 {
     std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
@@ -270,6 +296,18 @@ bool TransmClient::get_clients()
     return send_frame(buf.get());
 }
 
+int TransmClient::test_index_by_id(const std::string& id)
+{
+    int ret = -1;
+    for (const auto& item : clients_) {
+        if (item.second->id == id) {
+            ret = item.first;
+            break;
+        }
+    }
+    return ret;
+}
+
 bool TransmClient::cmd_fetch_files(const std::string& param)
 {
     if (downloading_) {
@@ -687,7 +725,7 @@ bool TransmClient::cmd_sub_task(const std::string& param, bool is_send)
 }
 
 bool TransmClient::variable_and_parse_files(const std::string& content,
-                                           std::map<std::string, std::string>& files)
+                                            std::map<std::string, std::string>& files)
 {
     auto vec = COfStr::split(content, "\n");
     bool valid = true;
@@ -831,6 +869,11 @@ bool TransmClient::cmd_down_list(const std::string& param)
     return true;
 }
 
+std::string TransmClient::test_get_own_id() const
+{
+    return own_id_;
+}
+
 bool TransmClient::send_frame(CFrameBuffer* buf)
 {
     char* out_buf{};
@@ -1418,7 +1461,7 @@ void TransmClient::judget_down_active()
 }
 
 std::string TransmClient::variable_handle(const std::string& task_list_path, const std::string& source,
-                                         bool is_local)
+                                          bool is_local)
 {
     std::string result(source);
     // 支持的变量如下:
diff --git a/client/client.h b/client/client.h
index 767482c..4cad7d3 100644
--- a/client/client.h
+++ b/client/client.h
@@ -46,21 +46,27 @@ public:
 
 public:
     void run(const std::string& ip, const std::string& port, const std::string& config_dir);
-
-public:
     bool get_clients();
     bool cmd_fetch_files(const std::string& param);
     bool cmd_sub_list(const std::string& param);
     bool cmd_clear_submited();
     bool cmd_upload_files(const std::string& param);
-    bool down_one_file(int remote_id, const std::string& file, const std::string& local_dir = "");
-    void report_trans_ret(TransState state, const std::string& key = "");
     bool cmd_sub_task(const std::string& param, bool is_send);
+    bool cmd_ls(const std::string& param);
+    bool cmd_down_list(const std::string& param);
+
+public:
+    bool connect_for_test(const std::string& ip, const std::string& port, const std::string& config_dir);
+    void disconnect_for_test();
+    int test_index_by_id(const std::string& id);
+    std::string test_get_own_id() const;
+
+private:
     bool variable_and_parse_files(const std::string& content, std::map<std::string, std::string>& files);
     bool down_update_file(const std::map<std::string, std::string>& files);
     bool get_dir_files(const std::string& dir, std::string& out, std::string& error);
-    bool cmd_ls(const std::string& param);
-    bool cmd_down_list(const std::string& param);
+    void report_trans_ret(TransState state, const std::string& key = "");
+    bool down_one_file(int remote_id, const std::string& file, const std::string& local_dir = "");
 
 private:
     bool send_frame(CFrameBuffer* buf);
@@ -71,6 +77,7 @@ private:
     std::string read_uuid();
     void get_id();
     void print_help(bool detail);
+    bool base_init(const std::string& ip, const std::string& port, const std::string& config_dir);
 
 private:
     void handle_frame(CFrameBuffer* buf);
@@ -96,6 +103,7 @@ private:
     std::shared_ptr<TransInfomation> down_;
     std::vector<std::thread> ths_;
     std::map<std::string, std::shared_ptr<TransInfomation>> up_;
+    std::thread context_th_;
     std::thread th_down_active_;
     long long cur_file_size_{};
     long long cur_down_size_{};
diff --git a/client/main.cpp b/client/main.cpp
index 35afe0f..63bcb80 100644
--- a/client/main.cpp
+++ b/client/main.cpp
@@ -234,8 +234,8 @@ int main(int argc, char* argv[])
     }
     TLOGI("Build At {} {} under {} on {}", __DATE__, __TIME__, VERSION_GIT_COMMIT, VERSION_GIT_BRANCH);
     TLOGI("use ip => [{}], port => [{}]", ip, port);
-    TransmClient client;
-    client.run(ip, std::to_string(port), g_Config->get_config_dir());
+    std::shared_ptr<TransmClient> client = std::make_shared<TransmClient>();
+    client->run(ip, std::to_string(port), g_Config->get_config_dir());
     TLOGI("exit ==========");
     return 0;
 }
\ No newline at end of file
diff --git a/test/Cmd.cxx b/test/Cmd.cxx
index edca4b5..6b43491 100644
--- a/test/Cmd.cxx
+++ b/test/Cmd.cxx
@@ -16,6 +16,14 @@ asio::io_context server_context;
 constexpr char* ip = "127.0.0.1";
 constexpr unsigned short port = 9897;
 bool server_suc = false;
+constexpr unsigned int max_wait = 3000;
+constexpr unsigned int wait_interval = 100;
+
+std::string str_id_a;
+int ida_in_b = -1;
+std::thread server_th;
+
+bool test_ls();
 
 void server_run()
 {
@@ -28,19 +36,87 @@ void server_run()
     server_context.run();
 }
 
-bool main_test()
+bool base_connect()
 {
     config = std::make_shared<ClientConfig>();
     if (!config->baseInit()) {
         return false;
     }
 
-    std::thread server_th(server_run);
-    if (value_wait(server_suc, true, std::equal_to<bool>(), 3000, 100) == false) {
-        server_th.join();
+    server_th = std::thread(server_run);
+    if (value_wait<bool>([]() -> bool { return server_suc; }, true, std::equal_to<bool>(), max_wait,
+                         wait_interval) == false) {
         return false;
     }
 
+    clientA = std::make_shared<TransmClient>();
+    if (clientA->connect_for_test(ip, std::to_string(port), config->get_config_dir()) == false) {
+        return false;
+    }
+
+    clientB = std::make_shared<TransmClient>();
+    if (clientB->connect_for_test(ip, std::to_string(port), config->get_config_dir()) == false) {
+        return false;
+    }
+
+    if (value_wait<std::string>([]() -> std::string { return clientA->test_get_own_id(); }, std::string(),
+                                std::not_equal_to<std::string>(), max_wait, wait_interval) == false) {
+        return false;
+    }
+
+    if (value_wait<std::string>([]() -> std::string { return clientB->test_get_own_id(); }, std::string(),
+                                std::not_equal_to<std::string>(), max_wait, wait_interval) == false) {
+        return false;
+    }
+
+    str_id_a = clientA->test_get_own_id();
+    std::cout << "clientA id: " << str_id_a << std::endl;
+    if (value_wait<int>([]() -> int { return clientB->test_index_by_id(str_id_a); }, -1,
+                        std::not_equal_to<int>(), max_wait, wait_interval) == false) {
+        return false;
+    }
+    ida_in_b = clientB->test_index_by_id(str_id_a);
+    std::cout << "clientA index In B: " << ida_in_b << std::endl;
+    return true;
+}
+
+bool main_test()
+{
+    if (!base_connect()) {
+        return false;
+    }
+
+    std::shared_ptr<int> deleter(new int(), [](int* p) {
+        if (clientA) {
+            clientA->disconnect_for_test();
+        }
+        if (clientB) {
+            clientB->disconnect_for_test();
+        }
+        if (server) {
+            server->stop();
+        }
+        server_context.stop();
+        if (server_th.joinable()) {
+            server_th.join();
+        }
+        delete p;
+    });
+
+    if (!test_ls()) {
+        return false;
+    }
+    std::this_thread::sleep_for(std::chrono::seconds(10));
+    return true;
+}
+
+// 测试 Ls
+bool test_ls()
+{
+    std::string cmd = std::to_string(ida_in_b) + " .";
+    if (!clientB->cmd_ls(cmd)) {
+        return false;
+    }
     return true;
 }
 
diff --git a/test/assistant.h b/test/assistant.h
index e6f31ef..ac32435 100644
--- a/test/assistant.h
+++ b/test/assistant.h
@@ -4,6 +4,7 @@
 #include <fstream>
 #include <random>
 #include <string>
+#include <functional>
 
 #ifdef USE_BOOST
 #include <boost/filesystem.hpp>
@@ -29,13 +30,14 @@ bool random_file(const std::string& file, size_t size);
  * @return false 超时或条件不满足
  */
 template <typename T, typename Compare = std::equal_to<T>>
-bool value_wait(const T& value, const T& expected, Compare comparator = Compare(),
+bool value_wait(const std::function<T()>& value_ref, const T& expected, Compare comparator = Compare(),
                 unsigned long timeout_ms = 0, unsigned long interval_ms = 100)
 {
     auto start = std::chrono::steady_clock::now();
 
     while (true) {
 
+        T value = value_ref();
         if (comparator(value, expected)) {
             return true;
         }