diff --git a/.vscode/settings.json b/.vscode/settings.json
index 98a3287..b7cf94a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -20,7 +20,7 @@
         ]
     },
     "cmake.configureSettings": {
-	    "CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
+	    //"CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
     },
     "cmake.options.statusBarVisibility": "visible",
     "cmake.generator": "Ninja",
@@ -110,6 +110,17 @@
         "xstddef": "cpp",
         "xtr1common": "cpp",
         "xtree": "cpp",
-        "xutility": "cpp"
+        "xutility": "cpp",
+        "bit": "cpp",
+        "compare": "cpp",
+        "concepts": "cpp",
+        "coroutine": "cpp",
+        "expected": "cpp",
+        "format": "cpp",
+        "forward_list": "cpp",
+        "source_location": "cpp",
+        "span": "cpp",
+        "stop_token": "cpp",
+        "*.ipp": "cpp"
     }
 }
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ff0af29..0446fa8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,5 +19,7 @@ add_subdirectory(util)
 add_subdirectory(server)
 add_subdirectory(client)
 
-add_executable(transm_test test.cpp)
-target_link_libraries(transm_test PRIVATE trans_net trans_util)
\ No newline at end of file
+add_executable(transm_test1 test1.cpp)
+target_link_libraries(transm_test1 PRIVATE trans_net trans_util)
+add_executable(transm_test2 test2.cpp)
+target_link_libraries(transm_test2 PRIVATE trans_net trans_util)
\ No newline at end of file
diff --git a/net/net_base.cpp b/net/net_base.cpp
index 7d0c9ce..e5ab068 100644
--- a/net/net_base.cpp
+++ b/net/net_base.cpp
@@ -8,7 +8,8 @@ CServer::~CServer()
 {
 }
 
-CClient::CClient(const std::shared_ptr<spdlog::logger>& logger) : logger_(logger), io_context_(), socket_(io_context_)
+CClient::CClient(asio::io_context& io_context, const std::shared_ptr<spdlog::logger>& logger)
+    : logger_(logger), io_context_(io_context), socket_(io_context_)
 {
 }
 
@@ -54,16 +55,26 @@ bool CClient::Send(const char* data, int len)
     }
 }
 
-std::string CClient::Receive()
+void CClient::register_func(ExFun_t& f)
 {
-    try {
-        std::vector<char> buffer(1024);
-        size_t length = socket_.read_some(asio::buffer(buffer));
-        std::string received_data(buffer.data(), length);
-        logger_->info("Received data len: {}", length);
-        return received_data;
-    } catch (const std::exception& ex) {
-        logger_->error("Receive failed: {}", ex.what());
-        return "";
-    }
+    fun_ = f;
+}
+
+void CClient::Receive()
+{
+    auto self(shared_from_this());
+    socket_.async_read_some(asio::buffer(tmp_buf_), [this, self](std::error_code ec, std::size_t length) {
+        if (!ec) {
+            std::lock_guard<std::mutex> lock(mutex_);
+            buffer_.push(tmp_buf_.data(), length);
+            auto* frame = CTransProtocal::parse(buffer_);
+            if (frame) {
+                if (fun_) {
+                    fun_(frame);
+                }
+                delete frame;
+            }
+            Receive();
+        }
+    });
 }
diff --git a/net/net_base.h b/net/net_base.h
index e86a549..c9e5142 100644
--- a/net/net_base.h
+++ b/net/net_base.h
@@ -3,8 +3,11 @@
 #include "util.h"
 #include <asio.hpp>
 #include <of_util.h>
+#include <functional>
+#include <mutex>
 
 using namespace ofen;
+using ExFun_t = std::function<void(CFrameBuffer* buf)>;
 class CServer
 {
 public:
@@ -12,20 +15,24 @@ public:
     ~CServer();
 };
 
-class CClient
+class CClient : public std::enable_shared_from_this<CClient>
 {
 public:
-    CClient(const std::shared_ptr<spdlog::logger>& logger);
+    CClient(asio::io_context& io_context, const std::shared_ptr<spdlog::logger>& logger);
     ~CClient();
 public:
     bool Connect(const std::string& host, const std::string& port);
     void Disconnect();
     bool Send(const char* data, int len);
-    std::string Receive();
+    void register_func(ExFun_t& f);
+    void Receive();
 
 private:
     std::shared_ptr<spdlog::logger> logger_;
-    asio::io_context io_context_;
+    asio::io_context& io_context_;
     asio::ip::tcp::socket socket_;
+    std::mutex mutex_;
     CMutBuffer buffer_;
+    std::array<char, 1024> tmp_buf_;
+    ExFun_t fun_;
 };
\ No newline at end of file
diff --git a/ofen b/ofen
index 79e086b..0f7a8d3 160000
--- a/ofen
+++ b/ofen
@@ -1 +1 @@
-Subproject commit 79e086bae5509753eff4dce5669b3a7f5eac525f
+Subproject commit 0f7a8d3c928ef93c6250fa048b5c1cda2e42ed57
diff --git a/test.cpp b/test.cpp
deleted file mode 100644
index 841d4c4..0000000
--- a/test.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "util.h"
-#include <iostream>
-#include <net_base.h>
-
-int main()
-{
-    char testBuffer[] = "NIhao";
-    auto logger = get_logger("test", "test.log");
-    CClient client(logger);
-    if (client.Connect("127.0.0.1", "8989")) {
-        std::cout << client.Send(testBuffer, sizeof(testBuffer)) << std::endl;
-        client.Receive();
-    }
-    client.Disconnect();
-    return 0;
-}
\ No newline at end of file
diff --git a/test1.cpp b/test1.cpp
new file mode 100644
index 0000000..5ea9342
--- /dev/null
+++ b/test1.cpp
@@ -0,0 +1,38 @@
+#include "util.h"
+#include <iostream>
+#include <net_base.h>
+
+int main()
+{
+    CFrameBuffer* buf = new CFrameBuffer();
+    buf->data_ = new char[256];
+    std::memset(buf->data_, 0x0, 256);
+    int buf_len = std::snprintf(buf->data_, 256, "%s", "Hello Cplusplus.");
+    buf->len_ = buf_len;
+    char* data = nullptr;
+    int len = 0;
+    if (!CTransProtocal::pack(buf, &data, len)) {
+        delete buf;
+        return -1;
+    }
+    auto logger = get_logger("test1", "test1.log");
+    asio::io_context io_context;
+    CClient client(io_context, logger);
+    if (!client.Connect("127.0.0.1", "8080")) {
+        return -1;
+    }
+    logger->info("send len:{}", len);
+    std::cout << client.Send(data, len) << std::endl;
+    std::thread t([&io_context]() { io_context.run(); });
+    char line[512]{};
+    while (std::cin.getline(line, 512)) {
+        if (std::strstr(line, "end")) {
+            break;
+        }
+    }
+    client.Disconnect();
+    t.join();
+
+    delete buf;
+    return 0;
+}
\ No newline at end of file
diff --git a/test2.cpp b/test2.cpp
new file mode 100644
index 0000000..fe4c0c1
--- /dev/null
+++ b/test2.cpp
@@ -0,0 +1,35 @@
+#include <net_base.h>
+#include <util.h>
+
+std::shared_ptr<spdlog::logger> g_Logger;
+
+void TestHandle(CFrameBuffer* buf)
+{
+    g_Logger->info("type: {}", buf->type_);   
+    g_Logger->info("len: {}", buf->len_);   
+}
+
+int main()
+{
+    char buffer[] = "Java";
+    g_Logger = get_logger("test1", "test1.log");
+    asio::io_context io_context;
+    std::shared_ptr<CClient> client = std::make_shared<CClient>(io_context, g_Logger);
+    if (!client->Connect("127.0.0.1", "8080")) {
+        return -1;
+    }
+    client->Send(buffer, sizeof(buffer));
+    std::function<void(CFrameBuffer*)> func = TestHandle;
+    client->register_func(func);
+    client->Receive();
+    std::thread t([&io_context]() { io_context.run(); });
+    char line[512]{};
+    while (std::cin.getline(line, 512)) {
+        if (std::strstr(line, "end")) {
+            break;
+        }
+    }
+    client->Disconnect();
+    t.join();
+    return 0;
+}
\ No newline at end of file
diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt
index a3b5043..945d23b 100644
--- a/util/CMakeLists.txt
+++ b/util/CMakeLists.txt
@@ -1,15 +1,13 @@
 cmake_minimum_required(VERSION 3.16)
 
 project(trans_util LANGUAGES CXX)
+set(CMAKE_CXX_STANDARD 17)
 
 if (MSVC)
-    add_definitions(-D_WIN32_WINNT=0x0601)
     add_compile_options(/source-charset:utf-8)
 endif()
 
-set(SOURCES
-    util.h util.cpp
-)
+set(SOURCES util.h util.cpp)
 add_library(trans_util STATIC ${SOURCES})
 target_link_libraries(trans_util PUBLIC Ofen)
 target_include_directories(trans_util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
\ No newline at end of file
diff --git a/util/util.cpp b/util/util.cpp
index c6daf5e..c310555 100644
--- a/util/util.cpp
+++ b/util/util.cpp
@@ -1,4 +1,6 @@
 #include "util.h"
+#include <cstddef>
+#include <cstdint>
 
 std::shared_ptr<spdlog::logger> get_logger(const std::string& mark, const std::string& log_file)
 {
@@ -32,21 +34,56 @@ CTransProtocal::~CTransProtocal()
 CFrameBuffer* CTransProtocal::parse(CMutBuffer& buffer)
 {
     CFrameBuffer* result = nullptr;
-    char header[] = {0xFF, 0xFE};
-    char tail[] = {0xFF, 0xFF};
+    unsigned char header[] = {0xFF, 0xFE};
+    unsigned char tail[] = {0xFF, 0xFF};
 
-    int find = buffer.index_of(header, sizeof(header));
+    int find = buffer.index_of((const char*)header, sizeof(header));
     if (find < 0) {
         return result;
     }
-    short int type = *(reinterpret_cast<const short int*>(buffer.get_data() + find));
+    int16_t type = *(reinterpret_cast<const int16_t*>(buffer.get_data() + find + 2));
+    int32_t len = *(reinterpret_cast<const int32_t*>(buffer.get_data() + find + 2 + sizeof(int16_t)));
+    int32_t tail_index = find + 2 + sizeof(int16_t) + sizeof(int32_t) + len;
+    if (buffer.get_len() - 2 < tail_index || len < 0) {
+        return result;
+    }
+    unsigned char taila = *((unsigned char*)(buffer.get_data() + tail_index));
+    unsigned char tailb = *((unsigned char*)(buffer.get_data() + tail_index + 1));
+    if (taila != tail[0] || tailb != tail[1]) {
+        return result;
+    }
+    result = new CFrameBuffer();
+    result->data_ = new char[len];
+    result->len_ = len;
+    std::memset(result->data_, 0x0, len);
+    std::memcpy(result->data_, buffer.get_data() + find + 2 + sizeof(int16_t) + sizeof(int32_t), len);
+    buffer.remove_of(0, tail_index + 2);
     return result;
 }
 
+bool CTransProtocal::pack(CFrameBuffer* buf, char** out_buf, int& len)
+{
+    if (buf == nullptr || buf->data_ == nullptr || buf->len_ < 1) {
+        return false;
+    }
+    unsigned char header[] = {0xFF, 0xFE};
+    unsigned char tail[] = {0xFF, 0xFF};
+    len = buf->len_ + 10;
+    *out_buf = new char[len];
+    std::memcpy(*out_buf, header, 2);
+    std::memcpy(*out_buf + 2, &buf->type_, 2);
+    std::memcpy(*out_buf + 4, &buf->len_, 4);
+    std::memcpy(*out_buf + 8, buf->data_, buf->len_);
+    std::memcpy(*out_buf + len - 2, tail, 2);
+    return true;
+}
+
 CFrameBuffer::CFrameBuffer()
 {
 }
 
 CFrameBuffer::~CFrameBuffer()
 {
-}
+    delete[] data_;
+    len_ = 0;
+}
\ No newline at end of file
diff --git a/util/util.h b/util/util.h
index 0522134..ac97876 100644
--- a/util/util.h
+++ b/util/util.h
@@ -1,9 +1,9 @@
-#ifndef TRANSM_UTIL
-#define TRANSM_UTIL
+#pragma once
 #include <spdlog/sinks/rotating_file_sink.h>
 #include <spdlog/sinks/stdout_color_sinks.h>
 #include <spdlog/spdlog.h>
 #include "of_util.h"
+#include <cstdint>
 
 using namespace ofen;
 std::shared_ptr<spdlog::logger> get_logger(const std::string& mark, const std::string& log_file);
@@ -12,6 +12,10 @@ class CFrameBuffer
 public:
     CFrameBuffer();
     ~CFrameBuffer();
+public:
+    int16_t type_{};
+    char* data_{};
+    int len_{};
 };
 
 /*
@@ -28,6 +32,6 @@ public:
     CTransProtocal();
     ~CTransProtocal();
 public:
-    CFrameBuffer* parse(CMutBuffer& buffer);
-};
-#endif
\ No newline at end of file
+    static CFrameBuffer* parse(CMutBuffer& buffer);
+    static bool pack(CFrameBuffer* buf, char** out_buf, int& len);
+};
\ No newline at end of file