#pragma once #ifdef _WIN32 #include #else #include #include #include #include #endif #include #include #include #include #include using namespace std; #include #include "Include_FTAPI.h" #include "Include_3rd_protobuf.h" using namespace google; using namespace Futu; #pragma warning(disable:4100) #pragma warning(disable:4189) inline void ProtoBufToBodyData(const protobuf::Message& pbObj, string& strBody) { protobuf::util::JsonPrintOptions ops; ops.add_whitespace = true; ops.always_print_enums_as_ints = true; protobuf::util::Status status = MessageToJsonString(pbObj, &strBody, ops); if (status.error_code() != protobuf::util::error::OK) { strBody.clear(); } } // 基础优化,提升3-5倍速度 inline void ProtoBufToBodyData_Ex(const protobuf::Message& pbObj, std::string& strBody) { thread_local static std::string buffer; // 线程局部复用缓冲区 buffer.clear(); protobuf::util::JsonPrintOptions ops; ops.add_whitespace = false; // 关闭非必要空白 ops.preserve_proto_field_names = true;// 避免字段名转换 ops.always_print_primitive_fields = false; // 跳过空字段 if (protobuf::util::MessageToJsonString(pbObj, &buffer, ops).ok()) { strBody.swap(buffer); // 零拷贝交换缓冲区 } else { strBody.clear(); } } // 修改ProtoBufToBodyData_Ex函数 inline void ProtoBufToBodyData_Binary(const protobuf::Message& pbObj, std::string& strBody) noexcept { thread_local static std::string buffer; pbObj.SerializeToString(&buffer); // 直接序列化为二进制 strBody.swap(buffer); buffer.clear(); } //// 解析二进制数据 //void parse_protobuf(const char* buffer, int length) { // // 反序列化 // Qot_GetPlateSet::Response response; // if (!response.ParseFromArray(buffer, length)) { // std::cerr << "Failed to parse protobuf data." << std::endl; // return; // } // // // 检查返回状态 // if (response.rettype() != 0) { // 假设 0 表示成功 // std::cerr << "Error: " << response.retmsg() // << " (Code: " << response.errcode() << ")" << std::endl; // return; // } // // // 检查是否存在 s2c 字段 // if (!response.has_s2c()) { // std::cout << "No data in response." << std::endl; // return; // } // // const Qot_GetPlateSet::S2C& s2c = response.s2c(); // //std::cout << "Last Page: " << s2c.plateinfolist().size(); // // << ", Total Count: " << s2c.allcount() << std::endl; // // //遍历板块列表 // for (int i = 0; i < s2c.plateinfolist_size(); ++i) { // const::Qot_Common::PlateInfo& plateinfo = s2c.plateinfolist(i); // string name = plateinfo.name(); // string code = plateinfo.plate().code(); // } //} inline void FastSerializeProto(const protobuf::Message& pbObj, std::string& strBody) noexcept { // 线程局部内存池 thread_local static struct { std::string buffer; size_t last_capacity = 0; } tls_pool; // 智能预分配策略 const size_t need_size = pbObj.ByteSizeLong(); if (tls_pool.last_capacity < need_size * 1.2) { tls_pool.buffer.reserve(std::max(need_size * 2, size_t(4096))); tls_pool.last_capacity = tls_pool.buffer.capacity(); } // 零拷贝序列化 tls_pool.buffer.clear(); pbObj.SerializeToString(&tls_pool.buffer); strBody.swap(tls_pool.buffer); // O(1)交换操作 } // 在公共头文件中添加 #if defined(__GNUC__) || defined(__clang__) # define MY_PREDICT_FALSE(x) (__builtin_expect(!!(x), 0)) # define MY_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) #else # define MY_PREDICT_FALSE(x) (x) # define MY_PREDICT_TRUE(x) (x) #endif inline bool FastDeserializeProto(const std::string& strBody, protobuf::Message& pbObj) noexcept { // 零拷贝解析器 protobuf::io::ArrayInputStream raw_input(strBody.data(), strBody.size()); protobuf::io::CodedInputStream coded_input(&raw_input); // 设置解析限制(防止恶意大包) coded_input.SetTotalBytesLimit(100 * 1024 * 1024, 50 * 1024 * 1024); // 100MB最大限制 // 快速解析主逻辑 if (MY_PREDICT_FALSE(!pbObj.ParseFromCodedStream(&coded_input))) { pbObj.Clear(); // 确保对象状态可复用 return false; } // 校验必填字段 if (MY_PREDICT_FALSE(!pbObj.IsInitialized())) { pbObj.Clear(); return false; } return true; } #if defined(_WIN32) inline string UTF8ToGBK(const string &strUTF8) { int nLen = MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, NULL, 0); wchar_t* wszGBK = new wchar_t[nLen + 1]; memset(wszGBK, 0, nLen * 2 + 2); MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, wszGBK, nLen); nLen = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL); char* szGBK = new char[nLen + 1]; memset(szGBK, 0, nLen + 1); WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, nLen, NULL, NULL); string strGBK(szGBK); if (wszGBK) delete[] wszGBK; if (szGBK) delete[] szGBK; return strGBK; } #endif inline string UTF8ToLocal(const string &strUTF8) { #if defined(_WIN32) int nCodePage = GetConsoleOutputCP(); if (nCodePage == 936) { return UTF8ToGBK(strUTF8); } else { return strUTF8; } #else return strUTF8; #endif } #define PrintRsp(str) std::cout << str << endl;\ string strBody;\ ProtoBufToBodyData(stRsp, strBody);\ std::cout << strBody << endl; #define Print(str) std::cout << str << endl; #define PrintError(errMsg) std::cout << "ERROR: " << __FUNCTION__ << ", retMsg = " << errMsg << std::endl; #define PrintUTF8(errMsg) std::cout << "ERROR: " << __FUNCTION__ << ", retMsg = " << UTF8ToLocal(errMsg) << std::endl; inline void CPSleep(int32_t nSec) { #ifdef _WIN32 Sleep(nSec * 1000); #else struct timespec spec; spec.tv_sec = nSec; spec.tv_nsec = 0; nanosleep(&spec, NULL); #endif } class Semaphore { #if defined(_WIN32) HANDLE m_sema; #else sem_t *m_sem; #endif public: Semaphore(int32_t initValue) { #if defined(_WIN32) m_sema = ::CreateSemaphoreA(NULL, initValue, 0x7fffffff, NULL); #else pid_t pid = getpid(); stringstream str; str << "ftapi.sample." << (long)pid; m_sem = ::sem_open(str.str().c_str(), O_CREAT | O_EXCL, S_IRWXU, initValue); #endif } ~Semaphore() { #if defined(_WIN32) ::CloseHandle(m_sema); #else ::sem_close(m_sem); #endif } void wait() { #if defined(_WIN32) ::WaitForSingleObject(m_sema, INFINITE); #else ::sem_wait(m_sem); #endif } void post() { #if defined(_WIN32) ::ReleaseSemaphore(m_sema, 1, NULL); #else ::sem_post(m_sem); #endif } bool trywait() { #if defined(_WIN32) return WAIT_OBJECT_0 == ::WaitForSingleObject(m_sema, 0); #else return 0 == ::sem_trywait(m_sem); #endif } };