diff --git a/.clang-format b/.clang-format index 7626823..c7a6a80 100644 --- a/.clang-format +++ b/.clang-format @@ -11,7 +11,7 @@ ReflowComments: true SpacesBeforeTrailingComments: 3 TabWidth: 4 ConstructorInitializerAllOnOneLineOrOnePerLine: true -ColumnLimit: 1100 +ColumnLimit: 110 AllowShortBlocksOnASingleLine: Never AllowShortFunctionsOnASingleLine: None AllowShortEnumsOnASingleLine: false diff --git a/CMakeLists.txt b/CMakeLists.txt index 0446fa8..1e8b489 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,10 @@ project(transm LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +if (MSVC) + add_compile_options(/source-charset:utf-8) +endif() + set(CMAKE_DEBUG_POSTFIX "d") message(STATUS "System: ${CMAKE_SYSTEM_NAME}") message(STATUS "Compiler CXX ID: ${CMAKE_CXX_COMPILER_ID}") diff --git a/client/client.cpp b/client/client.cpp index 4e8adcd..b7a0df8 100644 --- a/client/client.cpp +++ b/client/client.cpp @@ -1,9 +1,12 @@ #include "client.h" #include +#include +using namespace ofen; CClient::CClient(const std::shared_ptr& logger) : logger_(logger) { client_ = std::make_shared(io_context_, logger_); + supported_.push_back("GetTaskList"); } CClient::~CClient() @@ -12,14 +15,62 @@ CClient::~CClient() void CClient::run() { - std::thread thread([this]() { io_context_.run(); }); + if (!client_->connect("127.0.0.1", "8080")) { + logger_->info("{} connect err.", __FUNCTION__); + return; + } + client_->register_func([&](CFrameBuffer* buf) { handle_data(buf); }); + client_->async_recv(); + std::thread thread([&]() { io_context_.run(); }); char line[512]{}; while (std::cin.getline(line, 512)) { + std::string cmd_input(line); if (std::strstr(line, "end")) { break; } + auto vec = COfStr::split(cmd_input, " "); + if (vec.size() < 2) { + logger_->error("input's invalid format."); + continue; + } + auto cmd = vec[0]; + if (cmd == "GetTaskList") { + bool ret = get_task_list(); + logger_->info("exec GetTaskList Command result is:{}.", ret); + } } client_->disconnect(); thread.join(); logger_->info("{} exit.", __FUNCTION__); } + +bool CClient::get_task_list() +{ + logger_->info("{} start.", __FUNCTION__); + char* send = nullptr; + int len{}; + std::shared_ptr buf = std::make_shared(); + buf->data_ = new char[512]{}; + auto flen = std::snprintf(buf->data_, 512, "%s", gGetTaskList); + buf->len_ = flen; + buf->type_ = 1; + if (!CTransProtocal::pack(buf.get(), &send, len)) { + logger_->error("{} pack failed.", __FUNCTION__); + return false; + } + if (!client_->send(send, len)) { + return false; + } + delete[] send; + return true; +} + +void CClient::handle_data(CFrameBuffer* buf) +{ + if (buf == nullptr) { + logger_->error("{} nullptr.", __FUNCTION__); + return; + } + logger_->debug("type: {}", buf->type_); + logger_->debug("len: {}", buf->len_); +} diff --git a/client/client.h b/client/client.h index f445fd2..afb9600 100644 --- a/client/client.h +++ b/client/client.h @@ -1,6 +1,8 @@ #pragma once #include #include +#include +#include class CClient { @@ -11,8 +13,15 @@ public: public: void run(); +public: + bool get_task_list(); + +private: + void handle_data(CFrameBuffer* buf); + private: std::shared_ptr logger_; asio::io_context io_context_; std::shared_ptr client_; + std::vector supported_; }; \ No newline at end of file diff --git a/net/net_base.cpp b/net/net_base.cpp index 17b8b35..f36a91f 100644 --- a/net/net_base.cpp +++ b/net/net_base.cpp @@ -1,11 +1,89 @@ #include "net_base.h" -CTcpServer::CTcpServer() +CTcpServer::CTcpServer(asio::io_context& io_context, const std::shared_ptr& logger) + : io_context_(io_context), logger_(logger), acceptor_(io_context) +{ +} +CTcpServer::~CTcpServer() { } -CTcpServer::~CTcpServer() +bool CTcpServer::Start(unsigned short port) { + asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port); + try { + acceptor_.open(endpoint.protocol()); + acceptor_.set_option(asio::socket_base::reuse_address(true)); + acceptor_.bind(endpoint); + acceptor_.listen(); + } catch (const asio::system_error& e) { + logger_->error("Failed to bind to {}: {}", endpoint.address().to_string(), e.what()); + return false; + } + + Accept(); + logger_->info("Server started on port {}", port); + return true; +} + +void CTcpServer::Stop() +{ + acceptor_.close(); + std::lock_guard lock(mutex_); + for (auto& [key, thread] : client_threads_) { + if (thread.joinable()) { + thread.join(); + } + } + client_threads_.clear(); +} + +void CTcpServer::Accept() +{ + auto socket = std::make_shared(io_context_); + acceptor_.async_accept(*socket, [this, socket](const asio::error_code& error) { + if (!error) { + auto endpoint = socket->remote_endpoint(); + std::string client_key = endpoint.address().to_string() + ":" + std::to_string(endpoint.port()); + logger_->info("New connection from {}", client_key); + + { + std::lock_guard lock(mutex_); + client_map_[client_key] = 0; // Initial value as 0 + } + + client_threads_[client_key] = std::thread(&CTcpServer::HandleClient, this, socket, client_key); + } + Accept(); + }); +} + +void CTcpServer::HandleClient(std::shared_ptr socket, const std::string& client_key) +{ + try { + char data[1024]; + while (true) { + asio::error_code error; + size_t length = socket->read_some(asio::buffer(data), error); + if (error == asio::error::eof) { + logger_->info("Connection closed by client: {}", client_key); + break; + } else if (error) { + throw asio::system_error(error); + } + auto relen = socket->send(asio::buffer(data, length)); + logger_->info("Received data from {}, len={}, relen={}", client_key, length, relen); + } + } catch (std::exception& e) { + logger_->error("Error with client {}: {}", client_key, e.what()); + } + + std::lock_guard lock(mutex_); + client_map_.erase(client_key); + if (client_threads_.find(client_key) != client_threads_.end()) { + client_threads_.at(client_key).detach(); + client_threads_.erase(client_key); + } } CTcpClient::CTcpClient(asio::io_context& io_context, const std::shared_ptr& logger) @@ -55,7 +133,7 @@ bool CTcpClient::send(const char* data, int len) } } -void CTcpClient::register_func(ExFun_t& f) +void CTcpClient::register_func(ExFun_t&& f) { fun_ = f; } @@ -64,6 +142,7 @@ void CTcpClient::async_recv() { auto self(shared_from_this()); socket_.async_read_some(asio::buffer(tmp_buf_), [this, self](std::error_code ec, std::size_t length) { + logger_->debug("{} {}", __FUNCTION__, ec.message()); if (!ec) { std::lock_guard lock(mutex_); buffer_.push(tmp_buf_.data(), length); diff --git a/net/net_base.h b/net/net_base.h index 95f133a..fef0cff 100644 --- a/net/net_base.h +++ b/net/net_base.h @@ -11,8 +11,24 @@ using ExFun_t = std::function; class CTcpServer { public: - CTcpServer(); + CTcpServer(asio::io_context& io_context, const std::shared_ptr& logger); ~CTcpServer(); + +public: + bool Start(unsigned short port); + void Stop(); + +private: + void Accept(); + void HandleClient(std::shared_ptr socket, const std::string& client_key); + +private: + asio::io_context& io_context_; + asio::ip::tcp::acceptor acceptor_; + std::shared_ptr logger_; + std::map client_map_; + std::map client_threads_; + std::mutex mutex_; }; class CTcpClient : public std::enable_shared_from_this @@ -25,7 +41,7 @@ public: bool connect(const std::string& host, const std::string& port); void disconnect(); bool send(const char* data, int len); - void register_func(ExFun_t& f); + void register_func(ExFun_t&& f); void async_recv(); private: diff --git a/ofen b/ofen index 0f7a8d3..1427bf4 160000 --- a/ofen +++ b/ofen @@ -1 +1 @@ -Subproject commit 0f7a8d3c928ef93c6250fa048b5c1cda2e42ed57 +Subproject commit 1427bf4bca2c0f52429fe751c4c205acfd78b326 diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index d77fc59..315e6f0 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.16) project(transms LANGUAGES CXX) if (MSVC) - add_definitions(-D_WIN32_WINNT=0x0601) add_compile_options(/source-charset:utf-8) endif() -add_executable(transms main.cpp) \ No newline at end of file +add_executable(transms main.cpp server.h server.cpp) +target_link_libraries(transms PRIVATE trans_net trans_util) \ No newline at end of file diff --git a/server/main.cpp b/server/main.cpp index 74d43e4..7cb0076 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -1,8 +1,11 @@ #include +#include "server.h" +std::shared_ptr g_Logger = nullptr; int main() { - - + g_Logger = get_logger("server", "server.log"); + CServer server(g_Logger); + server.run(); return 0; } \ No newline at end of file diff --git a/server/server.cpp b/server/server.cpp new file mode 100644 index 0000000..1599a46 --- /dev/null +++ b/server/server.cpp @@ -0,0 +1,24 @@ +#include "server.h" + +CServer::CServer(const std::shared_ptr& logger) + : logger_(logger) +{ + server_ = std::make_shared(io_context_, logger); +} + +CServer::~CServer() +{ +} + +void CServer::run() +{ + if (!server_->Start(8080)) { + return; + } + io_context_.run(); +} + +bool CServer::get_task_list() +{ + return false; +} diff --git a/server/server.h b/server/server.h new file mode 100644 index 0000000..363603c --- /dev/null +++ b/server/server.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include +#include + +class CServer +{ +public: + CServer(const std::shared_ptr& logger); + ~CServer(); + +public: + void run(); + +public: + bool get_task_list(); + +private: + std::shared_ptr logger_; + asio::io_context io_context_; + std::shared_ptr server_; + std::vector supported_; +}; \ No newline at end of file diff --git a/test2.cpp b/test2.cpp index 891f761..64505bc 100644 --- a/test2.cpp +++ b/test2.cpp @@ -5,13 +5,16 @@ std::shared_ptr g_Logger; void TestHandle(CFrameBuffer* buf) { - g_Logger->info("type: {}", buf->type_); - g_Logger->info("len: {}", buf->len_); - g_Logger->info("{} exec. 中文测试", __FUNCTION__); + std::string chinese_test("中文测试"); + g_Logger->debug("type: {}", buf->type_); + g_Logger->info("len: {}", buf->len_); + g_Logger->warn("{} exec. {} 1", __FUNCTION__, chinese_test); + g_Logger->error("{} exec. {} 2", __FUNCTION__, chinese_test); } int main() { + // setlocale(LC_ALL, ".utf-8"); char buffer[] = "Java"; g_Logger = get_logger("test1", "test1.log"); asio::io_context io_context; @@ -19,9 +22,8 @@ int main() if (!client->connect("127.0.0.1", "8080")) { return -1; } - client->send(buffer, sizeof(buffer)); - std::function func = TestHandle; - client->register_func(func); + //client->send(buffer, sizeof(buffer)); + client->register_func([](CFrameBuffer* buf) { TestHandle(buf); }); client->async_recv(); std::thread t([&io_context]() { io_context.run(); }); char line[512]{}; diff --git a/util/util.cpp b/util/util.cpp index c310555..92d1d49 100644 --- a/util/util.cpp +++ b/util/util.cpp @@ -7,10 +7,11 @@ std::shared_ptr get_logger(const std::string& mark, const std::s auto file_sink = std::make_shared(log_file, 1024 * 50, 3); auto console_sink = std::make_shared(); file_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l]: %v"); - console_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e][%l]: %v"); + console_sink->set_color(spdlog::level::level_enum::info, 0xFFFF); + console_sink->set_pattern("%^[%Y-%m-%d %H:%M:%S.%e][%l]: %v%$"); std::vector sinks{file_sink, console_sink}; auto logger = std::make_shared(mark, sinks.begin(), sinks.end()); - logger->set_level(spdlog::level::info); + logger->set_level(spdlog::level::debug); spdlog::register_logger(logger); return logger; } @@ -27,6 +28,7 @@ CTransProtocal::~CTransProtocal() 【 transm TCP 数据协议 】 header 2 char: 0xFF 0xFE type 2 char: + mark 1 char: len 4 char: data xxxxx: tail 2 char: 0xFF 0xFF @@ -42,8 +44,9 @@ CFrameBuffer* CTransProtocal::parse(CMutBuffer& buffer) return result; } int16_t type = *(reinterpret_cast(buffer.get_data() + find + 2)); - int32_t len = *(reinterpret_cast(buffer.get_data() + find + 2 + sizeof(int16_t))); - int32_t tail_index = find + 2 + sizeof(int16_t) + sizeof(int32_t) + len; + char mark = *(buffer.get_data() + find + 2 + 2); + int32_t len = *(reinterpret_cast(buffer.get_data() + find + 2 + 2 + 1)); + int32_t tail_index = find + 2 + 2 + 1 + 4 + len; if (buffer.get_len() - 2 < tail_index || len < 0) { return result; } @@ -56,7 +59,7 @@ CFrameBuffer* CTransProtocal::parse(CMutBuffer& buffer) 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); + std::memcpy(result->data_, buffer.get_data() + find + 2 + 2 + 1 + 4, len); buffer.remove_of(0, tail_index + 2); return result; } @@ -68,12 +71,13 @@ bool CTransProtocal::pack(CFrameBuffer* buf, char** out_buf, int& len) } unsigned char header[] = {0xFF, 0xFE}; unsigned char tail[] = {0xFF, 0xFF}; - len = buf->len_ + 10; + len = buf->len_ + 11; *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 + 2 + 2, &buf->mark_, 1); + std::memcpy(*out_buf + 2 + 2 + 1, &buf->len_, 4); + std::memcpy(*out_buf + 2 + 2 + 1 + 4, buf->data_, buf->len_); std::memcpy(*out_buf + len - 2, tail, 2); return true; } diff --git a/util/util.h b/util/util.h index ac97876..d34b4b1 100644 --- a/util/util.h +++ b/util/util.h @@ -1,9 +1,11 @@ #pragma once +#include "of_util.h" +#include #include #include #include -#include "of_util.h" -#include + +constexpr auto gGetTaskList = "GetTaskList"; using namespace ofen; std::shared_ptr get_logger(const std::string& mark, const std::string& log_file); @@ -12,16 +14,19 @@ class CFrameBuffer public: CFrameBuffer(); ~CFrameBuffer(); + public: int16_t type_{}; char* data_{}; int len_{}; + char mark_{}; }; /* 【 transm TCP 数据协议 】 header 2 char: 0xFF 0xFE - type 2 char: + type 2 char: + mark 1 char: len 4 char: data xxxxx: tail 2 char: 0xFF 0xFF @@ -31,6 +36,7 @@ class CTransProtocal public: CTransProtocal(); ~CTransProtocal(); + public: static CFrameBuffer* parse(CMutBuffer& buffer); static bool pack(CFrameBuffer* buf, char** out_buf, int& len);