server:添加server并client和server初步交换数据尝试。
This commit is contained in:
parent
40c71fc22e
commit
8298f05a86
@ -11,7 +11,7 @@ ReflowComments: true
|
||||
SpacesBeforeTrailingComments: 3
|
||||
TabWidth: 4
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ColumnLimit: 1100
|
||||
ColumnLimit: 110
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
|
@ -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}")
|
||||
|
@ -1,9 +1,12 @@
|
||||
#include "client.h"
|
||||
#include <iostream>
|
||||
#include <of_str.h>
|
||||
|
||||
using namespace ofen;
|
||||
CClient::CClient(const std::shared_ptr<spdlog::logger>& logger) : logger_(logger)
|
||||
{
|
||||
client_ = std::make_shared<CTcpClient>(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<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||
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_);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include <net_base.h>
|
||||
#include <util.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
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<spdlog::logger> logger_;
|
||||
asio::io_context io_context_;
|
||||
std::shared_ptr<CTcpClient> client_;
|
||||
std::vector<std::string> supported_;
|
||||
};
|
@ -1,11 +1,89 @@
|
||||
#include "net_base.h"
|
||||
|
||||
CTcpServer::CTcpServer()
|
||||
CTcpServer::CTcpServer(asio::io_context& io_context, const std::shared_ptr<spdlog::logger>& 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<std::mutex> lock(mutex_);
|
||||
for (auto& [key, thread] : client_threads_) {
|
||||
if (thread.joinable()) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
client_threads_.clear();
|
||||
}
|
||||
|
||||
void CTcpServer::Accept()
|
||||
{
|
||||
auto socket = std::make_shared<asio::ip::tcp::socket>(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<std::mutex> 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<asio::ip::tcp::socket> 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<std::mutex> 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<spdlog::logger>& 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<std::mutex> lock(mutex_);
|
||||
buffer_.push(tmp_buf_.data(), length);
|
||||
|
@ -11,8 +11,24 @@ using ExFun_t = std::function<void(CFrameBuffer* buf)>;
|
||||
class CTcpServer
|
||||
{
|
||||
public:
|
||||
CTcpServer();
|
||||
CTcpServer(asio::io_context& io_context, const std::shared_ptr<spdlog::logger>& logger);
|
||||
~CTcpServer();
|
||||
|
||||
public:
|
||||
bool Start(unsigned short port);
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void Accept();
|
||||
void HandleClient(std::shared_ptr<asio::ip::tcp::socket> socket, const std::string& client_key);
|
||||
|
||||
private:
|
||||
asio::io_context& io_context_;
|
||||
asio::ip::tcp::acceptor acceptor_;
|
||||
std::shared_ptr<spdlog::logger> logger_;
|
||||
std::map<std::string, int> client_map_;
|
||||
std::map<std::string, std::thread> client_threads_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
class CTcpClient : public std::enable_shared_from_this<CTcpClient>
|
||||
@ -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:
|
||||
|
2
ofen
2
ofen
@ -1 +1 @@
|
||||
Subproject commit 0f7a8d3c928ef93c6250fa048b5c1cda2e42ed57
|
||||
Subproject commit 1427bf4bca2c0f52429fe751c4c205acfd78b326
|
@ -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)
|
||||
add_executable(transms main.cpp server.h server.cpp)
|
||||
target_link_libraries(transms PRIVATE trans_net trans_util)
|
@ -1,8 +1,11 @@
|
||||
#include <iostream>
|
||||
#include "server.h"
|
||||
|
||||
std::shared_ptr<spdlog::logger> g_Logger = nullptr;
|
||||
int main()
|
||||
{
|
||||
|
||||
|
||||
g_Logger = get_logger("server", "server.log");
|
||||
CServer server(g_Logger);
|
||||
server.run();
|
||||
return 0;
|
||||
}
|
24
server/server.cpp
Normal file
24
server/server.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "server.h"
|
||||
|
||||
CServer::CServer(const std::shared_ptr<spdlog::logger>& logger)
|
||||
: logger_(logger)
|
||||
{
|
||||
server_ = std::make_shared<CTcpServer>(io_context_, logger);
|
||||
}
|
||||
|
||||
CServer::~CServer()
|
||||
{
|
||||
}
|
||||
|
||||
void CServer::run()
|
||||
{
|
||||
if (!server_->Start(8080)) {
|
||||
return;
|
||||
}
|
||||
io_context_.run();
|
||||
}
|
||||
|
||||
bool CServer::get_task_list()
|
||||
{
|
||||
return false;
|
||||
}
|
24
server/server.h
Normal file
24
server/server.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include <net_base.h>
|
||||
#include <util.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class CServer
|
||||
{
|
||||
public:
|
||||
CServer(const std::shared_ptr<spdlog::logger>& logger);
|
||||
~CServer();
|
||||
|
||||
public:
|
||||
void run();
|
||||
|
||||
public:
|
||||
bool get_task_list();
|
||||
|
||||
private:
|
||||
std::shared_ptr<spdlog::logger> logger_;
|
||||
asio::io_context io_context_;
|
||||
std::shared_ptr<CTcpServer> server_;
|
||||
std::vector<std::string> supported_;
|
||||
};
|
14
test2.cpp
14
test2.cpp
@ -5,13 +5,16 @@ std::shared_ptr<spdlog::logger> 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<void(CFrameBuffer*)> 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]{};
|
||||
|
@ -7,10 +7,11 @@ std::shared_ptr<spdlog::logger> get_logger(const std::string& mark, const std::s
|
||||
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file, 1024 * 50, 3);
|
||||
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||
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<spdlog::sink_ptr> sinks{file_sink, console_sink};
|
||||
auto logger = std::make_shared<spdlog::logger>(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<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;
|
||||
char mark = *(buffer.get_data() + find + 2 + 2);
|
||||
int32_t len = *(reinterpret_cast<const int32_t*>(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;
|
||||
}
|
||||
|
12
util/util.h
12
util/util.h
@ -1,9 +1,11 @@
|
||||
#pragma once
|
||||
#include "of_util.h"
|
||||
#include <cstdint>
|
||||
#include <spdlog/sinks/rotating_file_sink.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "of_util.h"
|
||||
#include <cstdint>
|
||||
|
||||
constexpr auto gGetTaskList = "GetTaskList";
|
||||
|
||||
using namespace ofen;
|
||||
std::shared_ptr<spdlog::logger> 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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user