├── README.md └── src ├── BackEndServer.cpp ├── BackEndServer.h ├── BackTask.cpp ├── BackTask.h ├── CCipher.cpp ├── CCipher.h ├── CCond.cpp ├── CCond.h ├── CCrc.h ├── CDataBaseOpt.cpp ├── CDataBaseOpt.h ├── CEpollBase.cpp ├── CEpollBase.h ├── CFileOpt.cpp ├── CFileOpt.h ├── CFileTable.cpp ├── CFileTable.h ├── CFrontTask.cpp ├── CFrontTask.h ├── CHeartbeat.cpp ├── CHeartbeat.h ├── CJson.cpp ├── CJson.h ├── CLogger.cpp ├── CLogger.h ├── CLoginAndReg.cpp ├── CLoginAndReg.h ├── CMsgQueue.cpp ├── CMsgQueue.h ├── CMutexLock.cpp ├── CMutexLock.h ├── CSemMutex.cpp ├── CSemMutex.h ├── CSendTask.cpp ├── CSendTask.h ├── CServerJson.cpp ├── CServerJson.h ├── CServerSend.cpp ├── CServerSend.h ├── CShareMemory.cpp ├── CShareMemory.h ├── CSigleton.h ├── CSocket.cpp ├── CSocket.h ├── CTask.h ├── CThreadPool.cpp ├── CThreadPool.h ├── CTimer.cpp ├── CTimer.h ├── CUserOpt.h ├── CVideoInfo.cpp ├── CVideoInfo.h ├── CXORencode.cpp ├── CXORencode.h ├── FrontTcpServer.cpp ├── FrontTcpServer.h ├── Packet.h ├── aes.cpp ├── aes.h ├── ctool.cpp ├── ctool.h ├── global.cpp ├── global.h ├── main.cpp ├── md5.cpp ├── md5.h ├── phase3.sln ├── phase3.vcxproj ├── phase3.vcxproj.filters ├── phase3.vcxproj.user └── rapidjson ├── allocators.h ├── cursorstreamwrapper.h ├── document.h ├── encodedstream.h ├── encodings.h ├── error ├── en.h └── error.h ├── filereadstream.h ├── filewritestream.h ├── fwd.h ├── internal ├── biginteger.h ├── clzll.h ├── diyfp.h ├── dtoa.h ├── ieee754.h ├── itoa.h ├── meta.h ├── pow10.h ├── regex.h ├── stack.h ├── strfunc.h ├── strtod.h └── swap.h ├── istreamwrapper.h ├── memorybuffer.h ├── memorystream.h ├── msinttypes ├── inttypes.h └── stdint.h ├── ostreamwrapper.h ├── pointer.h ├── prettywriter.h ├── rapidjson.h ├── reader.h ├── schema.h ├── stream.h ├── stringbuffer.h └── writer.h /README.md: -------------------------------------------------------------------------------- 1 | ## 行车记录仪服务端 2 | 3 | ### 版权说明 4 | 5 | 本项目为个人练手项目,代码均为本人手写,仅供技术交流,请勿用于商业用途。 6 | 7 | 8 | 9 | ### 项目说明 10 | 11 | 本项目是一个单机版的行车记录仪的服务端,用vs、C++语言编写,在 Linux 环境下运行。实现服务器的【数据交互】【文件传输】【安全通信】等功能。 12 | 13 | 14 | 15 | ### 功能介绍 16 | ![image-20210907161542424](https://user-images.githubusercontent.com/56959230/132311564-748ef152-d2d4-45f1-a1a1-23c189a08ad4.png) 17 | 18 | ### 架构说明 19 | ![image-20210907161619255](https://user-images.githubusercontent.com/56959230/132311592-9862b0f1-fe3c-4921-9feb-02f6c67b6517.png) 20 | 21 | ### IPC通信 22 | ![image-20210907161824802](https://user-images.githubusercontent.com/56959230/132311610-38de973f-ce51-45b1-90ef-f33112ca3726.png) 23 | 24 | ### 通信协议 25 | ![image-20210907161703906](https://user-images.githubusercontent.com/56959230/132311642-f5c234c4-e67f-4559-899f-2378b9017a03.png) 26 | 27 | ![image-20210907161939841](https://user-images.githubusercontent.com/56959230/132311671-be823b0c-d912-4d0b-834c-96918223b397.png) 28 | 29 | ### 软件环境说明 30 | 31 | (1)软件语言:C/C++; 32 | 33 | (2)开发工具:vs2019 34 | 35 | (3)运行系统:linux; 36 | 37 | (4)数据库:sqlite3; 38 | 39 | ### 配置文件说明 40 | 41 | 配置文件路径:/bin/config/serverConfig.json 42 | 配置文件说明:所有的路径文件,均相对运行程序而言 43 | 44 | ``` 45 | 如:运行程序位于: /home/bin/程序.exe 46 | 日志路径: ../config/日志.txt 47 | 那日志文件实际位于: /home/config/日志.txt 48 | ``` 49 | 50 | 配置文件详细描述: 51 | ![1](https://user-images.githubusercontent.com/56959230/132311751-2f1ea8cc-80d1-4e69-bd2f-2822e09e0048.png) 52 | ![2](https://user-images.githubusercontent.com/56959230/132311771-9575bacb-0dc8-451b-90ab-9c43770af8b6.png) 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/BackEndServer.cpp: -------------------------------------------------------------------------------- 1 | #include "BackEndServer.h" 2 | 3 | //############################################################### 4 | //后置服务器 5 | //############################################################### 6 | BackEndServer::BackEndServer() 7 | { 8 | journal->WriteLog("[后置服务器]启动!"); 9 | //创建线程池 10 | thread_pool = new CThreadPool(DOC_GET_INT("server_set", "max_threadNum")); 11 | journal->WriteLog("[后置服务器]线程池创建完毕!"); 12 | 13 | this->Run(); 14 | } 15 | BackEndServer::~BackEndServer() 16 | { 17 | } 18 | 19 | void BackEndServer::Run() 20 | { 21 | //登陆业务 22 | CLoginAndRegTask* t_Loginask = nullptr; 23 | //注册业务--myTask子类的指针 24 | CLoginAndRegTask* reg_task = nullptr; 25 | //获取视频帧数业务 26 | CGetVideoFrame* get_videoFram = nullptr; 27 | //删除视频信息 28 | CDeleteVideoFrame* del_video_info = nullptr; 29 | //插入视频信息包 30 | CInsertVideo* insert_video_info = nullptr; 31 | //第一个文件包 32 | CFileFirstTask* file_first_task = nullptr; 33 | //文件包包头 34 | CFileTask* file_task = nullptr; 35 | //消息队列--收到消息的结构体 36 | msg_t recv_msg; 37 | //文件路径 38 | string m_file_path; 39 | 40 | //获取connfd表示的连接上的对端地址 41 | struct sockaddr_in peer_addr; //监听的客户端地址 42 | socklen_t sockLen = sizeof(peer_addr); 43 | 44 | while (true) 45 | { 46 | //阻塞等待接受来自后端的消息队列---来自前段为1 47 | memset(&recv_msg, 0, sizeof(msg_t)); 48 | f2b_msg_queue->ReceiveMsg(&recv_msg, msg_len, 1, 0); 49 | 50 | //判断业务逻辑 51 | switch (recv_msg.fun_typ) 52 | { 53 | case LOGIN: 54 | //登陆业务 55 | t_Loginask = new CLoginAndRegTask(true, recv_msg); 56 | thread_pool->AddTask(t_Loginask); 57 | break; 58 | case REGISTER: 59 | //注册业务 60 | reg_task = new CLoginAndRegTask(false, recv_msg); 61 | thread_pool->AddTask(reg_task); 62 | break; 63 | case REQUIRE_PREPGRORESS: 64 | //获取视频当前帧数 65 | get_videoFram = new CGetVideoFrame(recv_msg); 66 | thread_pool->AddTask(get_videoFram); 67 | break; 68 | case DELETE_VIDEO_INFO: 69 | //删除视频信息 70 | del_video_info = new CDeleteVideoFrame(recv_msg); 71 | thread_pool->AddTask(del_video_info); 72 | break; 73 | case INSERT_VIDEO_INFO: 74 | //插入视频信息包 75 | insert_video_info = new CInsertVideo(recv_msg); 76 | thread_pool->AddTask(insert_video_info); 77 | break; 78 | case FILE_FIRST_PACK: 79 | //写入文件表 80 | m_file_path.clear(); 81 | m_file_path = DOC_GET_STR("picture", "save_path"); 82 | file_first_task = new CFileFirstTask(m_file_path, recv_msg); 83 | thread_pool->AddTask(file_first_task); 84 | break; 85 | case FILE_SEG_EXIST: 86 | m_file_path.clear(); 87 | m_file_path = DOC_GET_STR("picture", "save_path"); 88 | file_task = new CFileTask(m_file_path, false, recv_msg); 89 | thread_pool->AddTask(file_task); 90 | break; 91 | case FILE_SEG_NULL: 92 | //片无包业务 93 | file_task = new CFileTask(m_file_path, true, recv_msg); 94 | thread_pool->AddTask(file_task); 95 | break; 96 | default: 97 | journal->ErrMsgWriteLog("[后置服务器]收到不明真相的任务请求,结束", true); 98 | break; 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /src/BackEndServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | //后置服务器--思路: 从共享内存读取一块数据出来,读到数据后添加到任务队列里面,线程池调取任务队列进行操作 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "CThreadPool.h" 9 | #include "BackTask.h" 10 | 11 | class BackEndServer 12 | { 13 | public: 14 | //构造函数 15 | BackEndServer();//后置服务器 16 | //析构函数 17 | ~BackEndServer(); 18 | //运行函数 19 | void Run(); 20 | private: 21 | CThreadPool* thread_pool; //线程池类指针 22 | }; 23 | -------------------------------------------------------------------------------- /src/BackTask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "CTask.h" 8 | #include "CFileOpt.h" 9 | #include "CFileTable.h" 10 | #include "md5.h" 11 | 12 | using namespace std; 13 | /* 14 | 线程任务--后端服务器任务--登陆注册 15 | */ 16 | class CLoginAndRegTask : public CTaskBase 17 | { 18 | public: 19 | //后置服务器 20 | CLoginAndRegTask(bool isLogin, msg_t buf); 21 | ~CLoginAndRegTask(); 22 | void Run(); 23 | 24 | private: 25 | void ResJudege(int res); 26 | t_Register regMsg; //注册结构体 27 | private: 28 | CLoginAndReg* log_and_Reg; //登陆和注册指针 29 | msg_t msg_info; //接发送消息的结构体 30 | bool isLogin; //判断是否是登陆 31 | }; 32 | 33 | /* 34 | 线程任务--后端服务器,获取视频信息任务 35 | */ 36 | class CGetVideoFrame :public CTaskBase 37 | { 38 | public: 39 | //后置服务器 40 | CGetVideoFrame(msg_t buf); 41 | ~CGetVideoFrame(); 42 | void Run(); 43 | 44 | private: 45 | msg_t msg_info; //接发送消息的结构体 46 | CVideoInfo* video_info; //视频信息指针 47 | t_RequireProgress reqPro; //请求获取信息结构体 48 | }; 49 | 50 | /* 51 | 线程任务--后端服务器,删除视频信息任务 52 | */ 53 | class CDeleteVideoFrame :public CTaskBase 54 | { 55 | public: 56 | //后置服务器 57 | CDeleteVideoFrame(msg_t buf); 58 | ~CDeleteVideoFrame(); 59 | void Run(); 60 | 61 | private: 62 | msg_t msg_info; //接发送消息的结构体 63 | 64 | CVideoInfo* video_info; //视频信息指针 65 | t_RequireProgress reqPro; //请求获取信息结构体 66 | }; 67 | 68 | /* 69 | 线程任务--后端服务器,插入视频信息 70 | */ 71 | class CInsertVideo :public CTaskBase 72 | { 73 | public: 74 | //后置服务器 75 | CInsertVideo(msg_t buf); 76 | ~CInsertVideo(); 77 | void Run(); 78 | 79 | private: 80 | msg_t msg_info; //接发送消息的结构体 81 | 82 | CVideoInfo* video_info; //视频信息指针 83 | t_VideoInfo t_video; //请求获取信息结构体 84 | }; 85 | 86 | /* 87 | 线程任务--后端服务器,片有包任务 88 | */ 89 | class CFileTask :public CTaskBase 90 | { 91 | public: 92 | //片有包 93 | CFileTask(string m_file_path, bool m_end, msg_t buf); 94 | ~CFileTask(); 95 | bool WriteInfo(); 96 | void reqResend(int i); 97 | bool MergeFile(); 98 | void Run(); 99 | 100 | private: 101 | string file_path; //文件路径 102 | bool isEnd; //是否是尾包 103 | t_FilePack file_pack; //片有包 104 | msg_t msg_info; //接发送消息的结构体 105 | }; 106 | 107 | /* 108 | 线程任务--后端服务器,第一个包任务 109 | */ 110 | class CFileFirstTask :public CTaskBase 111 | { 112 | public: 113 | //片有包 114 | CFileFirstTask(string m_file_path, msg_t buf); 115 | ~CFileFirstTask(); 116 | void Run(); 117 | 118 | private: 119 | t_FirstFilePack first_file_pack; //文件第一个包 120 | msg_t msg_info; //接发送消息的结构体 121 | string file_path; 122 | }; 123 | -------------------------------------------------------------------------------- /src/CCipher.cpp: -------------------------------------------------------------------------------- 1 | #include "CCipher.h" 2 | 3 | AesEncryptor::AesEncryptor(unsigned char* key) 4 | { 5 | m_pEncryptor = new AES(key); 6 | } 7 | 8 | AesEncryptor::~AesEncryptor(void) 9 | { 10 | delete m_pEncryptor; 11 | } 12 | 13 | void AesEncryptor::Byte2Hex(const unsigned char* src, int len, char* dest) { 14 | for (int i = 0; i < len; ++i) { 15 | sprintf(dest + i * 2, "%02X", src[i]); 16 | } 17 | } 18 | 19 | void AesEncryptor::Hex2Byte(const char* src, int len, unsigned char* dest) { 20 | int length = len / 2; 21 | for (int i = 0; i < length; ++i) { 22 | dest[i] = Char2Int(src[i * 2]) * 16 + Char2Int(src[i * 2 + 1]); 23 | } 24 | } 25 | 26 | int AesEncryptor::Char2Int(char c) { 27 | if ('0' <= c && c <= '9') { 28 | return (c - '0'); 29 | } 30 | else if ('a' <= c && c <= 'f') { 31 | return (c - 'a' + 10); 32 | } 33 | else if ('A' <= c && c <= 'F') { 34 | return (c - 'A' + 10); 35 | } 36 | return -1; 37 | } 38 | 39 | string AesEncryptor::EncryptString(string strInfor) { 40 | int nLength = strInfor.length(); 41 | int spaceLength = 16 - (nLength % 16); 42 | unsigned char* pBuffer = new unsigned char[nLength + spaceLength]; 43 | memset(pBuffer, '\0', nLength + spaceLength); 44 | memcpy(pBuffer, strInfor.c_str(), nLength); 45 | m_pEncryptor->Cipher(pBuffer, nLength + spaceLength); 46 | 47 | // 这里需要把得到的字符数组转换成十六进制字符串 48 | char* pOut = new char[2 * (nLength + spaceLength)]; 49 | memset(pOut, '\0', 2 * (nLength + spaceLength)); 50 | Byte2Hex(pBuffer, nLength + spaceLength, pOut); 51 | 52 | string retValue(pOut); 53 | delete[] pBuffer; 54 | delete[] pOut; 55 | return retValue; 56 | } 57 | 58 | string AesEncryptor::DecryptString(string strMessage) { 59 | int nLength = strMessage.length() / 2; 60 | unsigned char* pBuffer = new unsigned char[nLength * 2]; 61 | memset(pBuffer, '\0', nLength); 62 | Hex2Byte(strMessage.c_str(), strMessage.length(), pBuffer); 63 | 64 | m_pEncryptor->InvCipher(pBuffer, nLength); 65 | string retValue((char*)pBuffer); 66 | delete[] pBuffer; 67 | return retValue; 68 | } 69 | 70 | void AesEncryptor::EncryptTxtFile(const char* inputFileName) 71 | { 72 | ifstream ifs; 73 | 74 | // Open file: 75 | ifs.open(inputFileName); 76 | if (!ifs) 77 | { 78 | perror("AesEncryptor::EncryptTxtFile() - Open input file failed!"); 79 | return; 80 | } 81 | 82 | // Read config data: 83 | string strInfor; 84 | string strLine; 85 | while (!ifs.eof()) { 86 | char temp[1024]; 87 | memset(temp, '\0', 1024); 88 | ifs.read(temp, 1000); 89 | strInfor += temp; 90 | } 91 | ifs.close(); 92 | 93 | // Encrypt 94 | strLine = EncryptString(strInfor); 95 | 96 | // Writefile 97 | ofstream ofs; 98 | ofs.open(inputFileName, ios::in | ios::out | ios::trunc); 99 | if (!ofs) 100 | { 101 | perror("AesEncryptor::EncryptTxtFile() - Open output file failed!"); 102 | return; 103 | } 104 | ofs << strLine; 105 | ofs.close(); 106 | } 107 | 108 | void AesEncryptor::EncryptTxtFile(const char* inputFileName, const char* outputFileName) 109 | { 110 | ifstream ifs; 111 | 112 | // Open file: 113 | ifs.open(inputFileName); 114 | if (!ifs) 115 | { 116 | perror("AesEncryptor::EncryptTxtFile() - Open input file failed!"); 117 | return; 118 | } 119 | 120 | // Read config data: 121 | string strInfor; 122 | string strLine; 123 | while (!ifs.eof()) { 124 | char temp[1024]; 125 | memset(temp, '\0', 1024); 126 | ifs.read(temp, 1000); 127 | strInfor += temp; 128 | } 129 | ifs.close(); 130 | 131 | // Encrypt 132 | strLine = EncryptString(strInfor); 133 | 134 | // Writefile 135 | ofstream ofs; 136 | ofs.open(outputFileName, ios::in | ios::out | ios::trunc); 137 | if (!ofs) 138 | { 139 | perror("AesEncryptor::EncryptTxtFile() - Open output file failed!"); 140 | return; 141 | } 142 | ofs << strLine; 143 | ofs.close(); 144 | } 145 | 146 | void AesEncryptor::DecryptTxtFile(const char* inputFile, const char* outputFile) 147 | { 148 | ifstream ifs; 149 | 150 | // Open file: 151 | ifs.open(inputFile); 152 | if (!ifs) 153 | { 154 | perror("AesEncryptor::DecryptTxtFile() - Open input file failed!"); 155 | return; 156 | } 157 | 158 | // Read config data: 159 | string strInfor; 160 | string strLine; 161 | while (!ifs.eof()) { 162 | char temp[1024]; 163 | memset(temp, '\0', 1024); 164 | ifs.read(temp, 1000); 165 | strInfor += temp; 166 | } 167 | ifs.close(); 168 | 169 | // Encrypt 170 | strLine = DecryptString(strInfor); 171 | 172 | // Writefile 173 | ofstream ofs; 174 | ofs.open(outputFile, ios::in | ios::out | ios::trunc); 175 | if (!ofs) 176 | { 177 | perror("AesEncryptor::DecryptTxtFile() - Open output file failed!"); 178 | return; 179 | } 180 | ofs << strLine; 181 | ofs.close(); 182 | } 183 | 184 | void AesEncryptor::DecrypToEncryp(const char* inputFileName, const char* outputFileName, unsigned char* key) 185 | { 186 | ifstream ifs; 187 | 188 | // Open file: 189 | ifs.open(inputFileName); 190 | if (!ifs) 191 | { 192 | perror("AesEncryptor::DecryptTxtFile() - Open input file failed!"); 193 | return; 194 | } 195 | 196 | // Read config data: 197 | string strInfor; 198 | string strLine; 199 | while (!ifs.eof()) { 200 | char temp[1024]; 201 | memset(temp, '\0', 1024); 202 | ifs.read(temp, 1000); 203 | strInfor += temp; 204 | } 205 | ifs.close(); 206 | 207 | //先解密 208 | strLine = DecryptString(strInfor); 209 | //后加密 210 | delete this->m_pEncryptor; 211 | this->m_pEncryptor = nullptr; 212 | this->m_pEncryptor = new AES(key); 213 | string enLine = EncryptString(strLine); 214 | strLine.clear(); 215 | strLine = EncryptString(enLine); 216 | 217 | //输出文件 218 | ofstream ofs; 219 | ofs.open(outputFileName, ios::in | ios::out | ios::trunc); 220 | if (!ofs) 221 | { 222 | perror("AesEncryptor::DecryptTxtFile() - Open output file failed!"); 223 | return; 224 | } 225 | ofs << strLine; 226 | ofs.close(); 227 | } -------------------------------------------------------------------------------- /src/CCipher.h: -------------------------------------------------------------------------------- 1 | #ifndef SRC_UTILS_AES_ENCRYPTOR_H 2 | #define SRC_UTILS_AES_ENCRYPTOR_H 3 | 4 | #include 5 | #include 6 | #include "aes.h" 7 | using namespace std; 8 | class AES; 9 | 10 | class AesEncryptor 11 | { 12 | public: 13 | AesEncryptor(unsigned char* key); 14 | ~AesEncryptor(void); 15 | 16 | std::string EncryptString(std::string strInfor); 17 | std::string DecryptString(std::string strMessage); 18 | 19 | void EncryptTxtFile(const char* inputFileName); 20 | void EncryptTxtFile(const char* inputFileName, const char* outputFileName); 21 | void DecryptTxtFile(const char* inputFileName, const char* outputFileName); 22 | void DecrypToEncryp(const char* inputFileName, const char* outputFileName, unsigned char* key); 23 | 24 | private: 25 | void Byte2Hex(const unsigned char* src, int len, char* dest); 26 | void Hex2Byte(const char* src, int len, unsigned char* dest); 27 | int Char2Int(char c); 28 | 29 | private: 30 | AES* m_pEncryptor; 31 | }; 32 | 33 | #endif // SRC_UTILS_AES_ENCRYPTOR_H -------------------------------------------------------------------------------- /src/CCond.cpp: -------------------------------------------------------------------------------- 1 | #include "CCond.h" 2 | 3 | CCond::CCond(CMutexLock& new_mutex) :mutex(new_mutex) 4 | { 5 | pthread_cond_init(&cond, NULL); 6 | } 7 | 8 | CCond::~CCond() 9 | { 10 | pthread_cond_destroy(&cond); 11 | } 12 | 13 | bool CCond::Wait() 14 | { 15 | int rs = 0; 16 | if (mutex.is_locking == false) 17 | { 18 | //如果没上锁,则上锁 19 | mutex.Lock(); 20 | } 21 | rs = pthread_cond_wait(&cond, mutex.GetMutexPtr()); 22 | //解锁 23 | mutex.Unlock(); 24 | return rs == 0 ? true : false; 25 | } 26 | 27 | bool CCond::WaitForSecond(int second) 28 | { 29 | struct timespec timeout {}; 30 | clock_getres(CLOCK_REALTIME, &timeout); 31 | timeout.tv_sec += second; 32 | return pthread_cond_timedwait(&cond, mutex.GetMutexPtr(), &timeout) == ETIMEDOUT; 33 | } -------------------------------------------------------------------------------- /src/CCond.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CMutexLock.h" 3 | 4 | class CCond :public boost::noncopyable 5 | { 6 | public: 7 | //构造和析构函数 8 | CCond(CMutexLock& new_mutex); 9 | ~CCond(); 10 | 11 | //封装pthread_cond_wait 12 | bool Wait(); 13 | 14 | //等待固定时间 15 | bool WaitForSecond(int second); 16 | 17 | //封装pthread_cond_signal 18 | bool Notify() { 19 | return pthread_cond_signal(&cond) == 0 ? true : false; 20 | } 21 | 22 | //封装pthread_cond_broadcast 23 | bool NotifyAll() { 24 | return pthread_cond_broadcast(&cond); 25 | } 26 | 27 | private: 28 | CMutexLock& mutex; 29 | pthread_cond_t cond; 30 | }; 31 | -------------------------------------------------------------------------------- /src/CCrc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "global.h" 3 | class CCrc 4 | { 5 | public: 6 | static unsigned int crc16(unsigned char* puchMsg, unsigned char usDataLen) 7 | { 8 | unsigned char uchCRCHi = 0xFF; /* 高CRC字节初始化 */ 9 | unsigned char uchCRCLo = 0xFF; /* 低CRC字节初始化 */ 10 | unsigned int uIndex; /* CRC循环中的索引 */ 11 | 12 | while (usDataLen--) /* 传输消息缓冲区 */ 13 | { 14 | uIndex = uchCRCLo ^ *puchMsg++; /* 计算CRC */ 15 | uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex]; 16 | uchCRCHi = auchCRCLo[uIndex]; 17 | } 18 | //return (uchCRCLo << 8 | uchCRCHi); //低字节在前,高字节在后 19 | return (uchCRCHi << 8 | uchCRCLo); //高字节在前,低字节在后 20 | }; 21 | }; -------------------------------------------------------------------------------- /src/CDataBaseOpt.cpp: -------------------------------------------------------------------------------- 1 | #include "CDataBaseOpt.h" 2 | 3 | CDataBaseOpt::~CDataBaseOpt() 4 | { 5 | this->CloseDB(); 6 | } 7 | 8 | bool CDataBaseOpt::OpenDB(const char* db_add) 9 | { 10 | //打开数据库 11 | int res = sqlite3_open(db_add, &this->db); 12 | if (res) 13 | { 14 | fprintf(stderr, "打开数据库出错: %s\n", sqlite3_errmsg(db)); 15 | sqlite3_close(db); 16 | return false; 17 | } 18 | return true; 19 | } 20 | 21 | bool CDataBaseOpt::checkKey(char* ciphertext) 22 | { 23 | char sql[255]; 24 | sprintf(sql, "SELECT * From key_table WHERE key_num = '%s';", ciphertext); 25 | char** dataRes = nullptr; 26 | int row, col; 27 | this->GetSqlValue(sql, dataRes, row, col); 28 | if (row != 0) 29 | { 30 | this->pKey = ciphertext; 31 | return true; 32 | } 33 | return false; 34 | } 35 | 36 | bool CDataBaseOpt::ReSetKey(char* new_key) 37 | { 38 | char sql[255]; 39 | sprintf(sql, "UPDATE key_table SET key_num = '%s';", new_key); 40 | if (this->SqlOpt(sql)) 41 | { 42 | this->pKey = new_key; 43 | return true; 44 | } 45 | return false; 46 | } 47 | 48 | bool CDataBaseOpt::CloseDB() 49 | { 50 | int res = sqlite3_close(this->db); 51 | if (res == SQLITE_OK) 52 | { 53 | printf("数据库关闭成功\n"); 54 | } 55 | fprintf(stderr, "数据库关闭成功: %s\n", sqlite3_errmsg(db)); 56 | return false; 57 | } 58 | 59 | bool CDataBaseOpt::SqlOpt(char* sql) 60 | { 61 | char* zErrMsg = 0; 62 | int res = sqlite3_exec(this->db, sql, 0, 0, &zErrMsg); 63 | if (res != SQLITE_OK) 64 | { 65 | printf("[数据库操作]SQL语句操作失败:%s\n", zErrMsg); 66 | sqlite3_free(zErrMsg); 67 | return false; 68 | } 69 | return true; 70 | } 71 | 72 | bool CDataBaseOpt::GetSqlValue(const char* sql, char**& dataRes, int& row, int& col) 73 | { 74 | char* zErrMsg = 0; 75 | int res = sqlite3_get_table(this->db, sql, &dataRes, &row, &col, &zErrMsg); 76 | if (res == SQLITE_OK) 77 | { 78 | return true; 79 | } 80 | printf("[数据库操作]SQL语句操作失败:%s\n", zErrMsg); 81 | sqlite3_free(zErrMsg); 82 | return false; 83 | } -------------------------------------------------------------------------------- /src/CDataBaseOpt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "sqlite3.h" 6 | 7 | class CDataBaseOpt 8 | { 9 | public: 10 | CDataBaseOpt(const char* db_add, char* pKey) 11 | { 12 | this->pKey = pKey; 13 | assert(OpenDB(db_add)); 14 | }; 15 | //析构函数,关系数据库 16 | ~CDataBaseOpt(); 17 | 18 | //打开数据库 19 | bool OpenDB(const char* db_add); 20 | //打开加密的数据库 21 | bool checkKey(char* ciphertext); 22 | //重设密钥密码 23 | bool ReSetKey(char* new_key); 24 | //过去密钥密码 25 | char* GetKey() { return pKey; }; 26 | //关闭数据库 27 | bool CloseDB(); 28 | //注册表执行操作 29 | bool SqlOpt(char* sql); 30 | //获取sql结果的值 31 | bool GetSqlValue(const char* sql, char**& dataRes, int& row, int& col); 32 | //获得数据库指针 33 | sqlite3* getDB() { 34 | return this->db; 35 | } 36 | //获取状态标识 37 | sqlite3_stmt* getStmt() { 38 | return this->pStmt; 39 | } 40 | 41 | protected: 42 | char* pKey; 43 | sqlite3* db; //数据库指针 44 | sqlite3_stmt* pStmt; //状态标识 45 | }; 46 | -------------------------------------------------------------------------------- /src/CEpollBase.cpp: -------------------------------------------------------------------------------- 1 | #include "CEpollBase.h" 2 | 3 | //= = = = = = = = = = = = = = = = = = = = 4 | // @函数名称: CEpollBase(int maxConnectNum, int epollEventNum) 5 | // @函数说明: 构造函数,创建epoll和相关数值初始化 6 | // @参数说明: 参数1(int)最大连接数, 参数2(int)epoll事件数 7 | // @返回值: 无 8 | //= = = = = = = = = = = = = = = = = = = = 9 | CEpollBase::CEpollBase(int maxConnectNum, int epollEventNum) 10 | { 11 | //创建epoll 12 | this->epoll_fd = epoll_create(maxConnectNum); 13 | //每个连接创建一个标识符 14 | this->pack_num = new unsigned int[maxConnectNum * 5]; 15 | for (int i = 0; i <= maxConnectNum; i++) 16 | { 17 | pack_num[i] = 1; 18 | } 19 | //数值初始化 20 | this->epoll_event_num = epollEventNum; 21 | //新建epoll事件结构体 22 | this->events = new struct epoll_event[this->epoll_event_num]; 23 | if (events == nullptr) 24 | { 25 | journal->ErrMsgWriteLog("epoll数组开辟失败"); 26 | } 27 | } 28 | 29 | //= = = = = = = = = = = = = = = = = = = = 30 | // @函数名称: CEpollBase(int maxConnectNum) 31 | // @函数说明: 构造函数,创建epoll和相关数值初始化 32 | // epoll事件为最大连接数 33 | // @参数说明: (int)最大连接数 34 | // @返回值: 无 35 | //= = = = = = = = = = = = = = = = = = = = 36 | CEpollBase::CEpollBase(int maxConnectNum) 37 | { 38 | //创建epoll 39 | this->epoll_fd = epoll_create(maxConnectNum); 40 | this->epoll_event_num = maxConnectNum; 41 | this->events = new struct epoll_event[this->epoll_event_num]; 42 | if (events == nullptr) 43 | { 44 | journal->ErrMsgWriteLog("epoll数组开辟失败"); 45 | } 46 | } 47 | 48 | //= = = = = = = = = = = = = = = = = = = = 49 | // @函数名称: ~CEpollBase() 50 | // @函数说明: 释放epoll事件结构体对象 51 | // @参数说明: 无 52 | // @返回值: 无 53 | //= = = = = = = = = = = = = = = = = = = = 54 | CEpollBase::~CEpollBase() 55 | { 56 | if (events != nullptr) 57 | { 58 | delete[]this->events; 59 | events = nullptr; 60 | } 61 | } 62 | 63 | //= = = = = = = = = = = = = = = = = = = = 64 | // @函数名称: CEpollBase::DoEvent(int listenFd, int op, int state) 65 | // @函数说明: 执行epoll事件 66 | // @参数说明: 参数1:socket套接字地址 | 参数2:执行的epoll操作 | 参数3: epoll事件类型 67 | // @返回值: 无 68 | //= = = = = = = = = = = = = = = = = = = = 69 | void CEpollBase::DoEvent(int listenFd, int op, int state) 70 | { 71 | //初始化epoll事件 72 | struct epoll_event ev; 73 | memset(&ev, 0, sizeof(epoll_event)); 74 | 75 | //epoll事件类型events是epoll注册的事件,比如EPOLLIN、EPOLLOUT等等, 76 | //目的:这个参数在epoll_ctl注册事件时,可以明确告知注册事件的类型。 77 | ev.events = state; 78 | 79 | //绑定该事件(data是一个联合体),起到一个传递句柄的作用 80 | //目的:a.可以得知, 等到的事件是不是我们想要的socket产生的 81 | // b.帮助我们管理不同的网络连接---建立不同的socket管理不同的IP地址字段 82 | ev.data.fd = listenFd; 83 | 84 | //该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件。 85 | int res = epoll_ctl(this->epoll_fd, op, listenFd, &ev); 86 | if (res == -1) 87 | { 88 | journal->ErrMsgWriteLog("epoll操作失败"); 89 | } 90 | } 91 | 92 | //= = = = = = = = = = = = = = = = = = = = 93 | // @函数名称: AddEpoll(int listenFd) 94 | // @函数说明: 添加套接字到epoll并侦听 95 | // @参数说明: 参数1: 服务器的套接字标识符 96 | // @返回值: 无 97 | //= = = = = = = = = = = = = = = = = = = = 98 | void CEpollBase::AddEpoll(int server_fd) 99 | { 100 | //创建epoll事件 101 | //EPOLLIN:表示对应的文件描述符可以读 102 | //EPOLLET:将EPOLL设为边缘触发(ET模式的效率要比 LT模式高,它只支持非阻塞套接字) 103 | this->DoEvent(server_fd, EPOLL_CTL_ADD, EPOLLIN | EPOLLET); 104 | //服务器循环监听 105 | while (true) 106 | { 107 | //epoll进行侦听 108 | int nfds = epoll_wait(epoll_fd, events, epoll_event_num, -1); 109 | if (nfds < 0) 110 | { 111 | journal->ErrMsgWriteLog("epoll_wait发生错误"); 112 | return; 113 | } 114 | //socket的for循环 115 | for (int i = 0; i < nfds; ++i) 116 | { 117 | //处理新连接, 发现有连接到该服务器的套接字 118 | if (events[i].data.fd == server_fd) 119 | { 120 | journal->WriteLog("发现新的连接"); 121 | this->NewConnection(server_fd); 122 | journal->WriteLog("新连接添加完成"); 123 | } 124 | //处理已经存在的连接 125 | else if (events[i].events & EPOLLIN) 126 | { 127 | journal->WriteLog("已经存在的连接发布新任务"); 128 | this->ExitsConnection(events[i].data.fd, pack_num); 129 | } 130 | } 131 | } 132 | } 133 | 134 | //处理新连接--纯虚函数 135 | void CEpollBase::NewConnection(int client_fd) {} 136 | //处理已经存在的连接--纯虚函数 137 | void CEpollBase::ExitsConnection(int socket_fd, unsigned int* pack_num) {} 138 | 139 | //设置非阻塞监听 140 | int CEpollBase::SetNonBlocking(int fd) 141 | { 142 | int old_option = fcntl(fd, F_GETFL); 143 | int new_option = old_option | O_NONBLOCK; 144 | fcntl(fd, F_SETFL, new_option); 145 | return old_option; 146 | } -------------------------------------------------------------------------------- /src/CEpollBase.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | 类名总结:CEpollBase 类 3 | 文件名称:CEpollBase.h 4 | 功能说明:线程池的封装操作 5 | 文件时间:2021/1/20/ 6 | *******************************************************************************/ 7 | #pragma once 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "global.h" 16 | using namespace std; 17 | 18 | class CEpollBase 19 | { 20 | public: 21 | //构造与析构函数,创建epoll 22 | CEpollBase(int max_connect_num, int epoll_event_num); 23 | CEpollBase(int max_connect_num); 24 | ~CEpollBase(); 25 | //添加套接字到epoll并侦听 26 | void AddEpoll(int server_fd); 27 | //设置非阻塞监听 28 | int SetNonBlocking(int fd); 29 | //处理新连接 30 | virtual void NewConnection(int client_fd) = 0; 31 | //处理已经存在的连接 32 | virtual void ExitsConnection(int socket_fd, unsigned int* pack_num) = 0; 33 | //添加、删除、修改事件到epoll 34 | void DoEvent(int listen_fd, int op, int state); 35 | //获取epollfd标识符 36 | int GetEpollFd() { return epoll_fd; } 37 | //获取所有标识符 38 | list& GetAllFd() { return all_fd; } 39 | 40 | protected: 41 | unsigned int* pack_num; //定义包的编号 42 | int epoll_fd; //定义epoll标识符 43 | int epoll_event_num;//定义epoll的最大事件数 44 | struct epoll_event* events;//定义接收的最大事件 45 | listall_fd; //链表存储所有的epoll标识符 46 | }; 47 | -------------------------------------------------------------------------------- /src/CFileOpt.cpp: -------------------------------------------------------------------------------- 1 | #include "CFileOpt.h" 2 | 3 | CFileOpt::CFileOpt(string& m_file_path, FILE_OPENTYPE RW_mode) 4 | { 5 | this->file_path = m_file_path; 6 | this->file_mode = this->getType(RW_mode); 7 | this->fp = nullptr; 8 | isOpen = false; 9 | this->FileOpen(); 10 | } 11 | 12 | bool CFileOpt::FileOpen() 13 | { 14 | this->fp = fopen(file_path.c_str(), file_mode); 15 | if (this->fp == nullptr) 16 | { 17 | printf("file cannot open \n"); 18 | return false; 19 | } 20 | isOpen = true; 21 | return true; 22 | } 23 | 24 | bool CFileOpt::FileOpen(std::string path, FILE_OPENTYPE RW_mode, FILE* file_fp) 25 | { 26 | file_fp = fopen(path.c_str(), this->getType(RW_mode)); 27 | if (file_fp == nullptr) 28 | { 29 | printf("file cannot open \n"); 30 | return false; 31 | } 32 | isOpen = true; 33 | return true; 34 | } 35 | 36 | bool CFileOpt::FileClose() 37 | { 38 | if (this->fp != nullptr) 39 | { 40 | fclose(this->fp); 41 | isOpen = false; 42 | } 43 | } 44 | 45 | bool CFileOpt::WriteFile(char* str, int len) 46 | { 47 | if (this->fp == nullptr) 48 | { 49 | return false; 50 | } 51 | int retLen = fwrite(str, 1, len, this->fp); 52 | if (retLen == len) 53 | { 54 | //文件标识符设置为开头 55 | if (this->file_mode == "ab+") 56 | { 57 | rewind(fp); 58 | } 59 | return true; 60 | } 61 | else 62 | { 63 | return false; 64 | } 65 | } 66 | 67 | bool CFileOpt::WriteFile(FILE* file_fp, char* str, int len) 68 | { 69 | if (file_fp == nullptr) 70 | { 71 | return false; 72 | } 73 | int retLen = fwrite(str, len, 1, this->fp); 74 | if (retLen == len) 75 | { 76 | return true; 77 | } 78 | else 79 | { 80 | return false; 81 | } 82 | } 83 | 84 | int CFileOpt::ReadFile(char* str, int len) 85 | { 86 | if (this->fp == nullptr) 87 | { 88 | return false; 89 | } 90 | int retLen = fread(str, 1, len, fp); 91 | return retLen; 92 | } 93 | 94 | bool CFileOpt::IsExist() 95 | { 96 | if (!isOpen)//未打开 97 | { 98 | if ((this->fp = fopen(this->file_path.c_str(), "r")) == NULL) 99 | { 100 | return false; 101 | } 102 | else 103 | { 104 | fclose(this->fp); 105 | return true; 106 | } 107 | } 108 | return true; 109 | } 110 | 111 | bool CFileOpt::IsExist(string& str) 112 | { 113 | FILE* temp_fp; 114 | if ((temp_fp = fopen(str.c_str(), "r")) == NULL) 115 | { 116 | return false; 117 | } 118 | else 119 | { 120 | fclose(temp_fp); 121 | return true; 122 | } 123 | } 124 | 125 | bool CFileOpt::DeleteFile() 126 | { 127 | if (remove(this->file_path.c_str()) == 0) 128 | 129 | return true; 130 | else 131 | return false; 132 | } 133 | 134 | bool CFileOpt::DeleteFile(string& path) 135 | { 136 | if (remove(path.c_str()) == 0) 137 | 138 | return true; 139 | else 140 | return false; 141 | } 142 | 143 | int CFileOpt::DeleteDir(const char* path) 144 | { 145 | DIR* dir; 146 | struct dirent* dirinfo; 147 | struct stat statbuf; 148 | char filepath[256] = { 0 }; 149 | lstat(path, &statbuf); 150 | 151 | if (S_ISREG(statbuf.st_mode))//判断是否是常规文件 152 | { 153 | remove(path); 154 | } 155 | else if (S_ISDIR(statbuf.st_mode))//判断是否是目录 156 | { 157 | if ((dir = opendir(path)) == NULL) 158 | return 1; 159 | while ((dirinfo = readdir(dir)) != NULL) 160 | { 161 | Getfilepath(path, dirinfo->d_name, filepath); 162 | if (strcmp(dirinfo->d_name, ".") == 0 || strcmp(dirinfo->d_name, "..") == 0)//判断是否是特殊目录 163 | continue; 164 | DeleteDir(filepath); 165 | rmdir(filepath); 166 | } 167 | closedir(dir); 168 | } 169 | return 0; 170 | } 171 | 172 | int32_t CFileOpt::createDirectory(const std::string& directoryPath) 173 | { 174 | uint32_t dirPathLen = directoryPath.length(); 175 | if (dirPathLen > MAX_PATH_LEN) 176 | { 177 | journal->ErrMsgWriteLog("文件路径超过最大长度, 创建失败", true); 178 | return -1; 179 | } 180 | char tmpDirPath[MAX_PATH_LEN] = { 0 }; 181 | for (uint32_t i = 0; i < dirPathLen; ++i) 182 | { 183 | tmpDirPath[i] = directoryPath[i]; 184 | if (tmpDirPath[i] == '\\' || tmpDirPath[i] == '/') 185 | { 186 | if (access(tmpDirPath, 0) != 0) 187 | { 188 | int32_t ret = mkdir(tmpDirPath, 0777); 189 | if (ret != 0) 190 | { 191 | return ret; 192 | } 193 | } 194 | } 195 | } 196 | return 0; 197 | } 198 | 199 | bool CFileOpt::Mkdir(const char* pathname) 200 | { 201 | //判断文件夹是否存在,且可读写 202 | int res = access(pathname, 0777); 203 | if (!res) 204 | { 205 | //文件存在且具有操作权限 206 | return true; 207 | } 208 | res = mkdir(pathname, 0777); 209 | if (!res) 210 | { 211 | journal->WriteLog("[临时文件夹]创建成功,[路径]:", pathname); 212 | return true; 213 | } 214 | journal->WriteLog("[临时文件夹]创建失败,[路径]:", pathname); 215 | return false; 216 | } 217 | 218 | char* CFileOpt::getType(FILE_OPENTYPE type) 219 | { 220 | if (type == ReadOnly) 221 | { 222 | return "rb"; 223 | } 224 | else if (type == WriteOnly) 225 | { 226 | return "ab"; 227 | } 228 | else if (type == ReadWrite) 229 | { 230 | return "ab+"; 231 | } 232 | } -------------------------------------------------------------------------------- /src/CFileOpt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "global.h" 12 | #include "Packet.h" 13 | using namespace std; 14 | 15 | enum FILE_OPENTYPE 16 | { 17 | ReadOnly = 0,//仅读 rb 18 | WriteOnly,//仅写 //ab 不存在会创建文件 19 | ReadWrite,//读写 ab+ 不存在会创建文件 20 | UnKnow 21 | }; 22 | 23 | class CFileOpt 24 | { 25 | public: 26 | CFileOpt() {}; 27 | CFileOpt(string& m_file_path, FILE_OPENTYPE RW_mode); 28 | //设置参数 29 | void SetFilePara(std::string path, FILE_OPENTYPE RW_mode) 30 | { 31 | this->file_path = path; 32 | this->file_mode = this->getType(RW_mode); 33 | } 34 | //设置路径 35 | void SetFilePath(std::string path) 36 | { 37 | this->file_path = path; 38 | } 39 | //判断文件打开, 未打开就打开,打开就创建文件 40 | bool FileOpen(); 41 | bool FileOpen(std::string path, FILE_OPENTYPE RW_mode, FILE* file_fp); 42 | 43 | //关闭文件 44 | bool FileClose(); 45 | //写文件 46 | bool WriteFile(char* str, int len); 47 | bool WriteFile(FILE* file_fp, char* str, int len); 48 | 49 | //读文件 50 | int ReadFile(char* str, int len); 51 | //判断文件是否存在 52 | bool IsExist(); 53 | bool IsExist(string& str); 54 | //删除文件 55 | bool DeleteFile(); 56 | bool DeleteFile(string& path); 57 | //删除目录及其目录下的所有文件 58 | static int DeleteDir(const char* path); 59 | 60 | //创建文件夹 61 | bool Mkdir(const char* pathname); 62 | //创建多级目录 63 | int32_t createDirectory(const std::string& directoryPath); 64 | 65 | private: 66 | //获取文件标识符 67 | char* getType(FILE_OPENTYPE type); 68 | //遍历目录 69 | static void Getfilepath(const char* path, const char* filename, char* filepath) 70 | { 71 | strcpy(filepath, path); 72 | if (filepath[strlen(path) - 1] != '/') 73 | strcat(filepath, "/"); 74 | strcat(filepath, filename); 75 | printf("path is = %s\n", filepath); 76 | } 77 | string file_path; //文件路径 78 | char* file_mode; //文件打开类型 79 | FILE* fp; //文件描述符号 80 | bool isOpen; //文件打开标识符 81 | }; 82 | -------------------------------------------------------------------------------- /src/CFileTable.cpp: -------------------------------------------------------------------------------- 1 | #include "CFileTable.h" 2 | 3 | int CFileTable::WriteFileInfo(int user_id, int fileSize, char* file_name, char* md5) 4 | { 5 | //对账号和密码进行加密 6 | AesEncryptor* aes = new AesEncryptor((unsigned char*)p_database->GetKey()); 7 | string en_id = aes->EncryptString(std::to_string(user_id)); 8 | string en_fileSize = aes->EncryptString(std::to_string(fileSize)); 9 | delete aes; 10 | 11 | //查无账号, 进行注册 12 | char sql[255]; 13 | snprintf(sql, sizeof(sql), "INSERT INTO pictureTable VALUES(NULL,'%s', '%s', '%s', '%s');", 14 | file_name, en_id.c_str(), en_fileSize.c_str(), md5); 15 | bool res = p_database->SqlOpt(sql); 16 | if (res == true) 17 | { 18 | sprintf(sql, "[数据库操作]文件数据插入成功, 账号ID:%d, 文件大小:%d, 文件名:%s, MD5:%s", 19 | user_id, fileSize, file_name, md5); 20 | journal->WriteLog(sql); 21 | return SQLOPT_SUCCESS; 22 | } 23 | else 24 | { 25 | //数据库内有名字,存在该名字 26 | sprintf(sql, "[数据库操作]文件数据插入失败, 账号ID:%d, 文件大小:%d, 文件名:%s, MD5:%s", 27 | user_id, fileSize, file_name, md5); 28 | journal->ErrMsgWriteLog(sql); 29 | return ANSWER_NAME_ERROR; 30 | } 31 | 32 | } 33 | 34 | int CFileTable::DeleteFileInfo(char* file_name) 35 | { 36 | //判断数据内是否有此数据 37 | char sql[SQL_LEN]; 38 | snprintf(sql, sizeof(sql), "DELETE FROM pictureTable WHERE picName = '%s';", file_name); 39 | int res = p_database->SqlOpt(sql); 40 | if (res == true) 41 | { 42 | sprintf(sql, "[数据库操作]删除文件数据成功, 文件名ID:%d", file_name); 43 | journal->WriteLog(sql); 44 | return SQLOPT_SUCCESS; 45 | } 46 | else 47 | { 48 | sprintf(sql, "[数据库操作]删除文件数据失败, 文件名ID:%d", file_name); 49 | journal->WriteLog(sql); 50 | return SQLOPT_ERROR; 51 | } 52 | } 53 | 54 | bool CFileTable::ReadMd5(char* file_name, char* md5) 55 | { 56 | //sql语句太长可能会导致字符数组sql[]溢出, 从输入的用户名进行长度控制 57 | int res; 58 | char sql[255]; 59 | 60 | //可否查到此数据 61 | snprintf(sql, sizeof(sql), "SELECT MD5 FROM pictureTable WHERE picName = '%s';", file_name); 62 | char** dbResult; //是 char ** 类型,两个*号 63 | int nRow, nColumn; 64 | res = p_database->GetSqlValue(sql, dbResult, nRow, nColumn); 65 | if (res == true) 66 | { 67 | if (dbResult[1] != nullptr) 68 | { 69 | md5 = dbResult[1]; 70 | return true; 71 | } 72 | else 73 | { 74 | //查无此数据 75 | return ANSWER_NAME_ERROR; 76 | } 77 | } 78 | else 79 | { 80 | journal->ErrMsgWriteLog("[数据库操作]查询视频表sql语句执行失败", true); 81 | return SQLOPT_ERROR; 82 | } 83 | } 84 | 85 | bool CFileTable::ReadFileName(char* file_name, char* md5) 86 | { 87 | //sql语句太长可能会导致字符数组sql[]溢出, 从输入的用户名进行长度控制 88 | int res; 89 | char sql[255]; 90 | 91 | //可否查到此数据 92 | snprintf(sql, sizeof(sql), "SELECT picName FROM pictureTable WHERE MD5 = '%s';", md5); 93 | char** dbResult; //是 char ** 类型,两个*号 94 | int nRow, nColumn; 95 | res = p_database->GetSqlValue(sql, dbResult, nRow, nColumn); 96 | if (res == true) 97 | { 98 | if (nRow != 0) 99 | { 100 | file_name = dbResult[1]; 101 | return true; 102 | } 103 | else 104 | { 105 | //查无此数据 106 | return ANSWER_NAME_ERROR; 107 | } 108 | } 109 | else 110 | { 111 | journal->ErrMsgWriteLog("[数据库操作]查询视频表sql语句执行失败", true); 112 | return SQLOPT_ERROR; 113 | } 114 | } 115 | 116 | bool CFileTable::ReadFileNameAndUid(char* user_id, char* file_name, char* md5) 117 | { 118 | //sql语句太长可能会导致字符数组sql[]溢出, 从输入的用户名进行长度控制 119 | int res; 120 | char sql[255]; 121 | 122 | //可否查到此数据 123 | snprintf(sql, sizeof(sql), "SELECT * FROM pictureTable WHERE MD5 = '%s';", md5); 124 | char** dbResult; //是 char ** 类型,两个*号 125 | int nRow, nColumn; 126 | res = p_database->GetSqlValue(sql, dbResult, nRow, nColumn); 127 | if (res == true) 128 | { 129 | if (dbResult[4] != nullptr) 130 | { 131 | file_name = dbResult[4]; 132 | user_id = dbResult[5]; 133 | return true; 134 | } 135 | else 136 | { 137 | //查无此数据 138 | return ANSWER_NAME_ERROR; 139 | } 140 | } 141 | else 142 | { 143 | journal->ErrMsgWriteLog("[数据库操作]查询视频表sql语句执行失败", true); 144 | return SQLOPT_ERROR; 145 | } 146 | } -------------------------------------------------------------------------------- /src/CFileTable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CCipher.h" 3 | #include "global.h" 4 | #include "Packet.h" 5 | class CFileTable 6 | { 7 | public: 8 | static int WriteFileInfo(int user_id, int fileSize, char* file_name, char* md5); 9 | static int DeleteFileInfo(char* file_name); 10 | static bool ReadMd5(char* file_name, char* md5); 11 | static bool ReadFileName(char* file_name, char* md5); 12 | static bool ReadFileNameAndUid(char* user_id, char* file_name, char* md5); 13 | }; 14 | -------------------------------------------------------------------------------- /src/CFrontTask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CTask.h" 3 | 4 | /* 5 | 线程任务--前段服务器 6 | */ 7 | class CFrontTask : public CTaskBase 8 | { 9 | public: 10 | //前置服务器--无需数据库操作 11 | CFrontTask(list& all_fd, int fd, unsigned int* pack_num); 12 | ~CFrontTask(); 13 | void Run(); 14 | private: 15 | //共享内存和消息队列的操作 16 | void TaskSendMsg(void* buf, int buf_len, int type, int srcSocket); 17 | //仅消息队列操作 18 | void TaskSendMsg(int type, int srcSocket, int index); 19 | //文件操作 20 | void FileSegOpt(t_FilePack* filePack, int socketfd, int type); 21 | //CRC校验 22 | bool CrcCheck(unsigned char* str, int len, int srcSocket, int resent_type); 23 | 24 | private: 25 | unsigned int* pack_num; 26 | int srcSocket; //套接字标识符 27 | listallFd; //链表存储所有的epoll标识符 28 | struct sockaddr_in peer_addr; //监听的客户端地址 29 | t_PackHead* pack_head = nullptr; //结构体包头 30 | }; 31 | -------------------------------------------------------------------------------- /src/CHeartbeat.cpp: -------------------------------------------------------------------------------- 1 | #include "CHeartbeat.h" 2 | 3 | CHeartbeat::CHeartbeat() 4 | { 5 | //如果您想关闭,将keepAlive置零即可 6 | this->tcp_keepalive_on = DOC_GET_INT("tcp_keepalive", "tcp_keepalive_on"); 7 | //保活探测消息的发送频率 8 | this->tcp_keepalive_intvl = DOC_GET_INT("tcp_keepalive", "tcp_keepalive_intvl"); 9 | //TCP发送保活探测消息以确定连接是否已断开的次数。 10 | this->tcp_keepalive_probes = DOC_GET_INT("tcp_keepalive", "tcp_keepalive_probes"); 11 | //启用心跳机制开始到首次心跳侦测包发送之间的空闲时间 12 | this->tcp_keepalive_time = DOC_GET_INT("tcp_keepalive", "tcp_keepalive_time"); 13 | } 14 | 15 | int CHeartbeat::SetTcpKeepAlive(int fd) 16 | { 17 | //入口参数检查 18 | if (fd < 0 || tcp_keepalive_time < 0 || tcp_keepalive_intvl < 0 || tcp_keepalive_probes < 0) 19 | return -2; 20 | //启用心跳机制, 21 | if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&tcp_keepalive_on, sizeof(tcp_keepalive_on)) == -1) 22 | { 23 | journal->ErrMsgWriteLog("setsockopt心跳包启动失败"); 24 | return -1; 25 | } 26 | //探测发包间隔 27 | if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, 28 | &tcp_keepalive_intvl, sizeof(tcp_keepalive_intvl)) < 0) { 29 | journal->ErrMsgWriteLog("setsockopt心跳包\"保活时间信息\"初始化失败, 退出程序"); 30 | system("pause"); 31 | exit(-1); 32 | } 33 | //探测次数,即将几次探测失败判定为TCP断开 34 | //尝试探测的次数.如果第1次探测包就收到响应了,则后2次的不再发 35 | if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT, 36 | &tcp_keepalive_probes, sizeof(tcp_keepalive_probes)) < 0) { 37 | journal->ErrMsgWriteLog("setsockopt心跳包\"断开次数信息\"初始化失败, 退出程序"); 38 | system("pause"); 39 | exit(-1); 40 | } 41 | //发送心跳包之间的空闲时间 42 | //如该连接在X秒内没有任何数据往来,则进行此TCP层的探测 43 | if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, 44 | &tcp_keepalive_time, sizeof(tcp_keepalive_time)) < 0) { 45 | journal->ErrMsgWriteLog("setsockopt心跳包\"空闲时间信息\"初始化失败, 退出程序"); 46 | system("pause"); 47 | exit(-1); 48 | } 49 | return 0; 50 | } 51 | 52 | int CHeartbeat::ReSendAndRecvPack(int fd, int time) 53 | { 54 | struct timeval tv_timeout; 55 | tv_timeout.tv_sec = time; 56 | tv_timeout.tv_usec = 0; 57 | //发送时限 58 | setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv_timeout, sizeof(int)); 59 | //接收时限 60 | setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv_timeout, sizeof(int)); 61 | return 0; 62 | } 63 | 64 | int CHeartbeat::CloseSocket(int fd) 65 | { 66 | bool b_reuse_addr = true; 67 | //一般不会立即关闭而经历TIME_WAIT的过程 68 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&b_reuse_addr, sizeof(bool)); 69 | return 0; 70 | } -------------------------------------------------------------------------------- /src/CHeartbeat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "CServerJson.h" 6 | #include "CSigleton.h" 7 | #include "global.h" 8 | 9 | using namespace std; 10 | 11 | class CHeartbeat 12 | { 13 | public: 14 | //初始化相关参数 15 | CHeartbeat(); 16 | //设置TCP保活, 网络连接描述符 17 | int SetTcpKeepAlive(int fd); 18 | //在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限 19 | int ReSendAndRecvPack(int fd, int time); 20 | //TCP四次挥手关闭套接字连接 21 | int CloseSocket(int fd); 22 | 23 | private: 24 | int tcp_keepalive_intvl; //保活探测消息的发送频率。 25 | int tcp_keepalive_probes; //TCP发送保活探测消息以确定连接是否已断开的次数。 26 | int tcp_keepalive_time; //允许的持续空闲时间。 27 | int tcp_keepalive_on; //是否启动保活机制 28 | }; 29 | -------------------------------------------------------------------------------- /src/CJson.cpp: -------------------------------------------------------------------------------- 1 | #include "CJson.h" 2 | 3 | CJson::CJson(const char* json_add) 4 | { 5 | this->OpenJson(json_add); 6 | this->ParseJson(); 7 | } 8 | 9 | CJson::~CJson() 10 | { 11 | } 12 | 13 | void CJson::OpenJson(const char* json_add) 14 | { 15 | //以只读的方式打这个文件 16 | printf(json_add); 17 | in.open(json_add, std::ifstream::in); 18 | //如果打开成功,则一行一行读取数据 19 | if (in.is_open()) 20 | { 21 | std::string line; 22 | while (getline(in, line)) 23 | { 24 | //把读取到的数据添加到另一个string中,并且在结尾上加上换行符 25 | str_from_stream.append(line + '\n'); 26 | } 27 | std::cout << str_from_stream << std::endl; 28 | } 29 | //如果打开失败,则返回 30 | else 31 | { 32 | perror("读取配置文件错误, 退出程序\n"); 33 | system("pause"); 34 | exit(-1); 35 | } 36 | } 37 | 38 | void CJson::ParseJson() 39 | { 40 | //解析json 41 | doc.Parse<0>(str_from_stream.c_str()); 42 | 43 | //如果解析错误的话 44 | if (doc.HasParseError()) 45 | { 46 | perror("解析Json失败, 退出程序\n"); 47 | system("pause"); 48 | exit(-1); 49 | } 50 | printf("解析Json成功\n"); 51 | } 52 | 53 | void CJson::QueryAll() 54 | { 55 | static const char* kTypeNames[] = 56 | { "Null", "False", "True", "Object", "Array", "String", "Number" }; 57 | 58 | for (auto& m : doc.GetObject()) 59 | { 60 | printf("Type of member %s is %s\n", 61 | m.name.GetString(), kTypeNames[m.value.GetType()]); 62 | } 63 | } 64 | 65 | const char* CJson::CheckObj(const char* obj_name) 66 | { 67 | rapidjson::Value::ConstMemberIterator itr = doc.FindMember(obj_name); 68 | if (itr != doc.MemberEnd()) 69 | { 70 | return itr->value.GetString(); 71 | } 72 | return "is_null"; 73 | } -------------------------------------------------------------------------------- /src/CJson.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "rapidjson/rapidjson.h" 8 | #include "rapidjson/document.h" 9 | #include "rapidjson/reader.h" 10 | #include "rapidjson/writer.h" 11 | #include "rapidjson/stringbuffer.h" 12 | 13 | #define PRINT(x) std::cout << #x " = " << (x) << std::endl 14 | class CJson 15 | { 16 | public: 17 | //构造析构函数 18 | CJson(const char* json_add); 19 | ~CJson(); 20 | 21 | //打开JSON文件 22 | void OpenJson(const char* json_add); 23 | //解析JSON文件 24 | void ParseJson(); 25 | //读取JSON文件 26 | virtual bool ReadJson() = 0; 27 | //查询所有JSON键值对 28 | void QueryAll(); 29 | //检查成员是否存在并返回其值 30 | const char* CheckObj(const char* obj_name); 31 | rapidjson::Document doc; 32 | 33 | private: 34 | std::string str_from_stream;//字符串流 35 | std::ifstream in; //文件流 36 | }; 37 | -------------------------------------------------------------------------------- /src/CLogger.cpp: -------------------------------------------------------------------------------- 1 | #include "CLogger.h" 2 | 3 | CLogger::CLogger(const std::string& path) 4 | { 5 | this->m_path = path; 6 | this->mutex = new CMutexLock(); 7 | 8 | //获取当前系统时间,同时赋值 9 | time(&ptime); 10 | 11 | //设置当天的天数 12 | this->tim = localtime(&ptime); 13 | 14 | this->SetCurrTime(); 15 | //创建日志文件 16 | this->CreatLogFile(); 17 | } 18 | 19 | CLogger::~CLogger() 20 | { 21 | this->EndLogFile(); 22 | } 23 | 24 | //创建日志文件 25 | bool CLogger::CreatLogFile() 26 | { 27 | std::string path = this->m_path + "/" + GetCurrTime().substr(0, 10) + ".log"; 28 | //上锁 29 | this->mutex->Lock(); 30 | m_outfile.clear(); 31 | m_outfile.open(path, std::ios::out | std::ios::app); 32 | m_outfile << "=== 服务器日志文件 开始记录 ===\n"; 33 | //输出日期 34 | std::cout << "=== 服务器日志文件 开始记录 ===\n"; 35 | //解锁 36 | this->mutex->Unlock(); 37 | return true; 38 | } 39 | 40 | //结束日志文件 41 | bool CLogger::EndLogFile() 42 | { 43 | //上锁 44 | this->mutex->Lock(); 45 | if (m_outfile.is_open()) 46 | { 47 | m_outfile << "=== 服务器日志文件 结束记录 ===\r\n"; 48 | } 49 | m_outfile.flush(); 50 | m_outfile.close(); 51 | //解锁 52 | this->mutex->Unlock(); 53 | return true; 54 | } 55 | 56 | //创建一个新的日志文件 57 | bool CLogger::ModiLogFile() 58 | { 59 | //上锁 60 | this->mutex->Lock(); 61 | EndLogFile(); 62 | CreatLogFile(); 63 | //解锁 64 | this->mutex->Unlock(); 65 | return false; 66 | } 67 | 68 | //获取当前的时间 69 | std::string CLogger::GetCurrTime() 70 | { 71 | //上锁 72 | this->mutex->Lock(); 73 | //获取当前时间,并规范表示 74 | char tmp[30]; 75 | 76 | //获取本地时间 77 | struct tm* tim = localtime(&ptime); 78 | int sec = tim->tm_sec; 79 | int min = tim->tm_min; 80 | int hour = tim->tm_hour; 81 | int mon = tim->tm_mon + 1; 82 | int mday = tim->tm_mday; 83 | int year = tim->tm_year + 1900; 84 | 85 | //如果是新的一天, 则保存新的文件 86 | if (this->flag_day != mday || this->flag_mon != mon || this->flag_year != year) 87 | { 88 | ModiLogFile(); 89 | } 90 | 91 | //存储的数值进行更新 92 | this->SetCurrTime(); 93 | 94 | //格式化输出字符串 95 | sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, mday, hour, min, sec); 96 | //解锁 97 | this->mutex->Unlock(); 98 | return tmp; 99 | } 100 | 101 | char* CLogger::GetTime() 102 | { 103 | //获取当前时间,并规范表示 104 | char tmp[30]; 105 | 106 | //获取本地时间 107 | struct tm* tim = localtime(&ptime); 108 | int sec = tim->tm_sec; 109 | int min = tim->tm_min; 110 | int hour = tim->tm_hour; 111 | int mon = tim->tm_mon + 1; 112 | int mday = tim->tm_mday; 113 | int year = tim->tm_year + 1900; 114 | //格式化输出字符串 115 | sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, mday, hour, min, sec); 116 | return tmp; 117 | } 118 | 119 | //设置当前时间 120 | void CLogger::SetCurrTime() 121 | { 122 | //设置相关的数值 123 | this->flag_day = tim->tm_mday; 124 | this->flag_mon = tim->tm_mon + 1; 125 | this->flag_year = tim->tm_year + 1900; 126 | } 127 | 128 | //写入结构体函数 129 | void CLogger::WriteLog(const char* content) 130 | { 131 | std::string outputContent = "[Info][时间:" + GetCurrTime() + "]" + content + "\n"; 132 | //上锁 133 | this->mutex->Lock(); 134 | //输出到终端, 输出到文件当中 135 | std::cout << outputContent; 136 | m_outfile << outputContent; 137 | //刷新缓冲区 138 | m_outfile.flush(); 139 | //解锁 140 | this->mutex->Unlock(); 141 | } 142 | 143 | void CLogger::WriteLog(const char* content1, const char* content2) 144 | { 145 | std::string outputContent = "[Info][时间:" + GetCurrTime() + "]" + content1 + content2 + "\n"; 146 | //上锁 147 | this->mutex->Lock(); 148 | //输出到终端, 输出到文件当中 149 | std::cout << outputContent; 150 | m_outfile << outputContent; 151 | //刷新缓冲区 152 | m_outfile.flush(); 153 | //解锁 154 | this->mutex->Unlock(); 155 | } 156 | 157 | void CLogger::ErrMsgWriteLog(const char* content) 158 | { 159 | std::string outputContent = "[Error][时间:" + GetCurrTime() + "]" + content + 160 | ":错误码[" + strerror(errno) + "]\n"; 161 | this->mutex->Lock(); 162 | //输出到终端, 输出到文件当中 163 | std::cout << outputContent; 164 | m_outfile << outputContent; 165 | //刷新缓冲区 166 | m_outfile.flush(); 167 | //解锁 168 | this->mutex->Unlock(); 169 | } 170 | 171 | void CLogger::ErrMsgWriteLog(const char* content1, const char* content2) 172 | { 173 | std::string outputContent = "[Error][时间:" + GetCurrTime() + "]" + content1 + content2 + 174 | ":错误码[" + strerror(errno) + "]\n"; 175 | this->mutex->Lock(); 176 | //输出到终端, 输出到文件当中 177 | std::cout << outputContent; 178 | m_outfile << outputContent; 179 | //刷新缓冲区 180 | m_outfile.flush(); 181 | //解锁 182 | this->mutex->Unlock(); 183 | } 184 | 185 | void CLogger::ErrMsgWriteLog(const char* content, bool no_erro) 186 | { 187 | std::string outputContent = "[Error][时间:" + GetCurrTime() + "]" + content + "\n"; 188 | this->mutex->Lock(); 189 | //输出到终端, 输出到文件当中 190 | std::cout << outputContent; 191 | m_outfile << outputContent; 192 | //刷新缓冲区 193 | m_outfile.flush(); 194 | //解锁 195 | this->mutex->Unlock(); 196 | } -------------------------------------------------------------------------------- /src/CLogger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "CMutexLock.h" 8 | 9 | typedef struct log_info 10 | { 11 | const char* fun; 12 | const char* type; 13 | const char* user_id; 14 | std::string data; 15 | }t_log_info; 16 | 17 | class CLogger 18 | { 19 | public: 20 | //构造函数 21 | CLogger(const std::string& path); 22 | 23 | //析构函数 24 | ~CLogger(); 25 | 26 | //创建日志文件 27 | bool CreatLogFile(); 28 | 29 | //结束日志文件 30 | bool EndLogFile(); 31 | 32 | //修改日志文件 33 | bool ModiLogFile(); 34 | 35 | //获取当前时间 36 | std::string GetCurrTime(); 37 | //纯获取当前时间 38 | char* GetTime(); 39 | 40 | //设置当前的时间 41 | void SetCurrTime(); 42 | 43 | //输出正常的文本到文件里面 44 | void WriteLog(const char* content); 45 | void WriteLog(const char* content1, const char* content2); 46 | 47 | //输出报错的文本信息到文件里面 48 | void ErrMsgWriteLog(const char* content, bool no_erro); 49 | void ErrMsgWriteLog(const char* content); 50 | void ErrMsgWriteLog(const char* content1, const char* content2); 51 | 52 | private: 53 | std::ofstream m_outfile; //将日志输出到文件的流对象 54 | std::string m_path; //日志文件路径 55 | 56 | int flag_day; //用来存储当前的天数 57 | int flag_mon; //用来存储当前的月数 58 | int flag_year; //用来存储当前的年数 59 | 60 | time_t ptime; //获取当前时间,并规范表示 61 | struct tm* tim; //时间接收结构体 62 | 63 | CMutexLock* mutex; //线程锁 64 | }; -------------------------------------------------------------------------------- /src/CLoginAndReg.cpp: -------------------------------------------------------------------------------- 1 | #include "CLoginAndReg.h" 2 | CLoginAndReg::CLoginAndReg() 3 | { 4 | } 5 | 6 | int CLoginAndReg::LoginOpt(int user_name, char* user_key) 7 | { 8 | //对账号和密码进行加密 9 | AesEncryptor* aes = new AesEncryptor((unsigned char*)p_database->GetKey()); 10 | string en_name = aes->EncryptString(std::to_string(user_name)); 11 | string en_key = aes->EncryptString(user_key); 12 | 13 | delete aes; 14 | 15 | //sql语句太长可能会导致字符数组sql[]溢出, 从输入的用户名进行长度控制 16 | char sql[SQL_LEN]; 17 | memset(sql, '\0', sizeof(sql)); 18 | sprintf(sql, "SELECT * FROM usr WHERE uId = '%s';", en_name.c_str()); 19 | char** dbResult; //是 char ** 类型,两个*号 20 | int nRow, nColumn; 21 | if (p_database->GetSqlValue(sql, dbResult, nRow, nColumn) == true) 22 | { 23 | //等于null表示查无此账号 24 | if (nRow == 0) 25 | { 26 | sprintf(sql, "[数据库操作]账号查询出错, 账号ID:%d", user_name); 27 | journal->WriteLog(sql); 28 | return ANSWER_NAME_ERROR; 29 | } 30 | } 31 | //查找到账号后判断密码是否正确 32 | memset(sql, '\0', sizeof(sql)); 33 | sprintf(sql, "SELECT * FROM usr WHERE uId = '%s' AND pwd = \'%s\';", en_name.c_str(), en_key.c_str()); 34 | if (p_database->GetSqlValue(sql, dbResult, nRow, nColumn) == true) 35 | { 36 | //判断是否能查到数据 37 | if (nRow == 0) 38 | { 39 | sprintf(sql, "[数据库操作]密码查询错误, 账号ID:%d,密码:%s", user_name, user_key); 40 | journal->WriteLog(sql); 41 | return ANSWER_KEY_ERROR; 42 | } 43 | else 44 | { 45 | sprintf(sql, "[数据库操作]查询成功, 账号ID:%d, 密码:%s", user_name, user_key); 46 | journal->WriteLog(sql); 47 | return SQLOPT_SUCCESS; 48 | } 49 | } 50 | journal->ErrMsgWriteLog("[数据库操作]sql语句执行失败:", sql); 51 | return SQLOPT_ERROR; 52 | } 53 | 54 | int CLoginAndReg::RegOpt(int user_id, char* user_name, char* user_key) 55 | { 56 | //对账号和密码进行加密 57 | AesEncryptor* aes = new AesEncryptor((unsigned char*)p_database->GetKey()); 58 | string en_id = aes->EncryptString(std::to_string(user_id)); 59 | string en_name = aes->EncryptString(user_name); 60 | string en_key = aes->EncryptString(user_key); 61 | delete aes; 62 | 63 | //判断数据内是否有此数据 64 | int res = LoginOpt(user_id, user_key); 65 | char sql[SQL_LEN]; 66 | //返回名字错误,表示不存在该名字,可以进行注册操作 67 | if (res == ANSWER_NAME_ERROR) 68 | { 69 | //查无账号, 进行注册 70 | snprintf(sql, sizeof(sql), "INSERT INTO usr VALUES('%s', '%s', '%s', 1);", 71 | en_id.c_str(), en_name.c_str(), en_key.c_str()); 72 | res = p_database->SqlOpt(sql); 73 | if (res == true) 74 | { 75 | sprintf(sql, "[数据库操作]用户数据插入成功, 账号ID:%d, 用户名:%s, 密码:%s", 76 | user_id, user_name, user_key); 77 | journal->WriteLog(sql); 78 | return SQLOPT_SUCCESS; 79 | } 80 | } 81 | //数据库内有名字,存在该名字 82 | sprintf(sql, "[数据库操作]用户数据插入失败, 账号ID:%d, 用户名:%s, 密码:%s", 83 | user_id, user_name, user_key); 84 | journal->ErrMsgWriteLog(sql); 85 | return ANSWER_NAME_ERROR; 86 | } 87 | 88 | int CLoginAndReg::DeletOpt(int user_id) 89 | { 90 | //对账号和密码进行加密 91 | AesEncryptor* aes = new AesEncryptor((unsigned char*)p_database->GetKey()); 92 | string en_id = aes->EncryptString(std::to_string(user_id)); 93 | delete aes; 94 | 95 | //判断数据内是否有此数据 96 | char sql[SQL_LEN]; 97 | snprintf(sql, sizeof(sql), "DELETE FROM usr WHERE uId = '%s';", en_id.c_str()); 98 | int res = p_database->SqlOpt(sql); 99 | if (res == true) 100 | { 101 | sprintf(sql, "[数据库操作]删除用户数据成功, 账号ID:%d", user_id); 102 | journal->WriteLog(sql); 103 | return SQLOPT_SUCCESS; 104 | } 105 | else 106 | { 107 | return SQLOPT_ERROR; 108 | } 109 | } -------------------------------------------------------------------------------- /src/CLoginAndReg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Packet.h" 3 | #include "global.h" 4 | #include "CCipher.h" 5 | 6 | class CLoginAndReg 7 | { 8 | public: 9 | CLoginAndReg(); 10 | int LoginOpt(int user_name, char* user_key); 11 | int RegOpt(int user_id, char* user_name, char* user_key); 12 | int DeletOpt(int user_id); 13 | }; 14 | -------------------------------------------------------------------------------- /src/CMsgQueue.cpp: -------------------------------------------------------------------------------- 1 | #include "CMsgQueue.h" 2 | 3 | CMsgQueue::CMsgQueue(int key) 4 | { 5 | this->Init(key); 6 | this->mutex = new CMutexLock(); 7 | } 8 | 9 | CMsgQueue::~CMsgQueue() 10 | { 11 | //在析构函数中,如果调用msgctl函数删除消息队列, 12 | //那么有可能别的进程正在使用,因此谁创建,应该由谁调用Destory函数删除 13 | } 14 | 15 | /* 16 | 函数说明: 消息队列初始化--利用字符串初始化 17 | */ 18 | int CMsgQueue::Init(char* pathName) 19 | { 20 | int ret; 21 | //把从pathname导出的信息与id的低序8位组合成一个整数IPC键 22 | this->msg_key = ftok(pathName, 1); 23 | if (msg_key == -1) 24 | { 25 | perror("密钥初始化出错\n"); 26 | exit(-1); 27 | } 28 | else 29 | { 30 | //如果类型为0,且消息不存在,则创建 31 | ret = msgget(msg_key, IPC_CREAT | IPC_EXCL | 0666); 32 | } 33 | //判断消息队列是否获取成功 34 | if (ret == -1) 35 | { 36 | perror("消息队列创建失败\n"); 37 | system("pause"); 38 | exit(-1); 39 | } 40 | //消息队列ID赋值 41 | this->msg_queue_id = ret; 42 | return 0; 43 | } 44 | 45 | /* 46 | 函数说明: 消息队列初始化--利用密钥key初始化 47 | */ 48 | int CMsgQueue::Init(int key) 49 | { 50 | //用以结果判断 51 | int ret; 52 | this->msg_key = key; 53 | //有时候进程非正常退出时,消息队列没有删除,如果里面还有消息, 54 | //若有消息, 则删除后重新创建消息队列 55 | ret = msgget(key, IPC_EXCL | IPC_CREAT | 0666); 56 | //如果原本消息存在 57 | if (ret == -1) 58 | { 59 | //重新连接 60 | this->msg_queue_id = msgget(key, IPC_CREAT | 0666); 61 | //销毁 62 | Destroy(); 63 | //再次创建 64 | ret = msgget(key, IPC_CREAT | 0666); 65 | //判断消息队列是否获取成功 66 | if (ret == -1) 67 | { 68 | perror("消息队列创建失败"); 69 | system("pause"); 70 | exit(-1); 71 | } 72 | } 73 | //消息队列赋值 74 | this->msg_queue_id = ret; 75 | printf("新消息队列初始化完毕\n"); 76 | return 0; 77 | } 78 | 79 | /* 80 | 函数说明: 接收消息--利用msg_t结构体接收消息 81 | 参数说明: msg表示消息队列结构体 82 | n_bytes表示消息的长度 83 | type表示从消息队列读取的消息形态: 0表示读取所有消息 84 | flag:0以阻塞方式读取/IPC_NOWAIT表示非阻塞读取 85 | */ 86 | bool CMsgQueue::ReceiveMsg(void* msg, size_t n_bytes, long type, int flag) 87 | { 88 | this->mutex->Lock(); 89 | //接收消息队列 90 | int ret = (int)msgrcv(this->msg_queue_id, msg, n_bytes, type, flag); 91 | if (ret == -1) 92 | { 93 | this->mutex->Unlock(); 94 | perror("消息队列接收失败"); 95 | return false; 96 | } 97 | this->mutex->Unlock(); 98 | return true; 99 | } 100 | 101 | /* 102 | 函数说明: 发送消息--利用msg_t结构体发送消息 103 | 参数说明: msg表示消息队列结构体 104 | n_bytes表示消息的长度 105 | flag:0以阻塞方式读取/IPC_NOWAIT表示非阻塞写入 106 | */ 107 | bool CMsgQueue::SendMsg(const void* msg, size_t n_bytes, int flag) 108 | { 109 | this->mutex->Lock(); 110 | //发送消息 111 | int ret = msgsnd(this->msg_queue_id, msg, n_bytes, flag); 112 | if (ret == -1) 113 | { 114 | this->mutex->Unlock(); 115 | perror("消息队列发送失败"); 116 | return false; 117 | } 118 | this->mutex->Unlock(); 119 | 120 | return true; 121 | } 122 | 123 | /* 124 | 函数说明:销毁消息队列 125 | */ 126 | bool CMsgQueue::Destroy() 127 | { 128 | int ret = msgctl(this->msg_queue_id, IPC_RMID, NULL); 129 | if (ret == -1) 130 | { 131 | perror("消息队列销毁失败"); 132 | exit(-1); 133 | } 134 | printf("原消息队列销毁成功"); 135 | this->msg_queue_id = 0; 136 | return true; 137 | } -------------------------------------------------------------------------------- /src/CMsgQueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "CMutexLock.h" 10 | 11 | /* 12 | 13 | 消息队列的特点 14 | 1、异步通信,消息队列会保存进程发送的消息,其他进程不一定要及时取走消息。 15 | 2、可以发送不同类型的消息,消息的头部用long类型的字段标记。 16 | 3、取消息时,不一定按先进先出的方式,可以按消息的类型来取。 17 | 4、消息队列内部是用一个链表来保存消息,当消息被取走后,这个消息就从链表中删除了, 18 | 而且这个链表的长度是有限制的,当消息存满后,不能再存入消息。 19 | 20 | 消息队列的使用 21 | 1.异步处理:例如短信通知、终端状态推送、App推送、用户注册等 22 | 2.数据同步:业务数据推送同步 23 | 3.重试补偿:记账失败重试 24 | 4.系统解耦:通讯上下行、终端异常监控、分布式事件中心 25 | 5.流量消峰:秒杀场景下的下单处理 26 | 6.发布订阅:HSF的服务状态变化通知、分布式事件中心 27 | 7.数据流处理:日志服务、监控上报 28 | 8.分布式事务 29 | 30 | */ 31 | class CMsgQueue 32 | { 33 | public: 34 | CMsgQueue(int key); 35 | virtual ~CMsgQueue(); 36 | //消息队列初始化 37 | int Init(char* pathName); 38 | int Init(int key); 39 | //消息队列收发 40 | bool ReceiveMsg(void* msg, size_t n_bytes, long type, int flag); 41 | bool SendMsg(const void* msg, size_t n_bytes, int flag); 42 | //消息队列销毁 43 | bool Destroy(); 44 | //获得消息队列ID 45 | int GetMsgId() { return this->msg_queue_id; }; 46 | //获得消息队列关键字 47 | key_t GetMsgKey() { return this->msg_key; }; 48 | private: 49 | //消息队列ID 50 | int msg_queue_id; 51 | //消息队列关键字 52 | key_t msg_key; 53 | //消息队列锁 54 | CMutexLock* mutex; 55 | }; 56 | -------------------------------------------------------------------------------- /src/CMutexLock.cpp: -------------------------------------------------------------------------------- 1 | #include "CMutexLock.h" 2 | 3 | CMutexLock::CMutexLock() 4 | { 5 | //判断是否上锁,未上锁则加锁 6 | if (IsLocking() == false) 7 | { 8 | //创建锁 9 | CHECK(!pthread_mutex_init(&mutex, NULL)); 10 | } 11 | } 12 | 13 | CMutexLock::~CMutexLock() 14 | { 15 | assert(!IsLocking()); 16 | //销毁锁 17 | CHECK(!pthread_mutex_destroy(&mutex)); 18 | } 19 | 20 | void CMutexLock::Lock() 21 | { 22 | //先加锁再修改状态,保证以下赋值操作的原子性。 23 | CHECK(!pthread_mutex_lock(&mutex)); 24 | is_locking = true; 25 | } 26 | 27 | void CMutexLock::Unlock() 28 | { 29 | //先修改状态在解锁,保证赋值操作的原子性。 30 | is_locking = false; 31 | CHECK(!pthread_mutex_unlock(&mutex)); 32 | } -------------------------------------------------------------------------------- /src/CMutexLock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define CHECK(exp) \ 9 | if(!exp) \ 10 | { \ 11 | fprintf(stderr, "File:%s, Line:%d Exp:[" #exp "] is true, abort.\n",__FILE__, __LINE__); abort();\ 12 | } 13 | 14 | class CMutexLock : public boost::noncopyable 15 | { 16 | //条件变量友元声明 17 | friend class CCond; 18 | public: 19 | CMutexLock(); 20 | ~CMutexLock(); 21 | //上锁 22 | void Lock(); 23 | //解锁 24 | void Unlock(); 25 | //尝试上锁 26 | bool IsLocking() const { return is_locking; } 27 | //得到线程锁 28 | pthread_mutex_t* GetMutexPtr() { return &mutex; } 29 | private: 30 | void RestoreMutexStatus() { is_locking = true; } 31 | pthread_mutex_t mutex;//互斥锁 32 | bool is_locking; //判断锁的状态 33 | }; 34 | 35 | /* 36 | 类说明: 37 | 对MutexLock初始化和析构进行处理 38 | 初始化的时候加锁 39 | 析构的时候解锁 40 | */ 41 | class CMutexLockGuard :public boost::noncopyable 42 | { 43 | public: 44 | //构造时加锁 45 | CMutexLockGuard(CMutexLock& mutex) :mutex(mutex) { mutex.Lock(); } 46 | //析构时解锁 47 | ~CMutexLockGuard() { mutex.Unlock(); } 48 | private: 49 | CMutexLock& mutex; 50 | }; 51 | -------------------------------------------------------------------------------- /src/CSemMutex.cpp: -------------------------------------------------------------------------------- 1 | #include "CSemMutex.h" 2 | 3 | CSemMutex::CSemMutex() 4 | { 5 | } 6 | 7 | CSemMutex::CSemMutex(key_t i_Key) 8 | { 9 | //初始化,信号密钥 10 | Init(i_Key); 11 | } 12 | 13 | CSemMutex::~CSemMutex() 14 | { 15 | } 16 | 17 | /* 18 | 函数说明:利用key初始化信号量 19 | */ 20 | void CSemMutex::Init(key_t i_key) 21 | { 22 | #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) 23 | /* union semun is defined by including */ 24 | #else 25 | /* according to X/OPEN we have to define it ourselves */ 26 | union semun 27 | { 28 | int val; /* value for SETVAL */ 29 | struct semid_ds* buf; /* buffer for IPC_STAT, IPC_SET */ 30 | unsigned short* array; /* array for GETALL, SETALL */ 31 | struct seminfo* __buf; /* buffer for IPC_INFO */ 32 | }; 33 | #endif 34 | 35 | int i_sem_id; //定义信号ID 36 | union semun arg;//定义信号结构体 37 | u_short array[2] = { 0, 0 }; //定义信号量,用以上锁 38 | 39 | //生成信号量集, 包含两个信号量 40 | i_sem_id = semget(i_key, 2, IPC_CREAT | IPC_EXCL | 0666); 41 | if (i_sem_id != -1) 42 | { 43 | arg.array = &array[0]; 44 | //SETVAL:将所有信号量的值设置为0 45 | if (semctl(i_sem_id, 0, SETALL, arg) == -1) 46 | { 47 | throw ("[CSemMutex::init]信号量初始化失败:" + string(strerror(errno))); 48 | } 49 | } 50 | else 51 | { 52 | //信号量已经存在 53 | if (errno != EEXIST) 54 | { 55 | throw ("[CSemMutex::init]信号量已经存在:" + string(strerror(errno))); 56 | } 57 | //连接信号量 58 | i_sem_id = semget(i_key, 2, 0666); 59 | if (i_sem_id == -1) 60 | { 61 | throw ("[CSemMutex::init]连接信号量错误:" + string(strerror(errno))); 62 | } 63 | else 64 | { 65 | printf("信号创建,连接成功\n"); 66 | } 67 | } 68 | 69 | //参数赋值 70 | this->sem_id = i_sem_id; 71 | this->sem_key = i_key; 72 | } 73 | 74 | /* 75 | 函数说明:对信号进行上锁 76 | */ 77 | int CSemMutex::ShareLock() const 78 | { 79 | //进入共享锁, 第二个信号量的值表示当前使用信号量的进程个数 80 | //等待第一个信号量变为0(互斥锁没有使用) 81 | //占用第二个信号量(第二个信号量值+1, 表示被共享锁使用) 82 | struct sembuf sops[2] = { {0, 0, SEM_UNDO}, 83 | {1, 1, SEM_UNDO} }; 84 | size_t nsops = 2; 85 | //返回当前可用的资源数量 86 | return semop(this->sem_id, &sops[0], nsops); 87 | } 88 | 89 | /* 90 | 函数说明:对信号进行解锁 91 | */ 92 | int CSemMutex::UnShareLock() const 93 | { 94 | //解除共享锁, 有进程使用过第二个信号量 95 | //等到第二个信号量可以使用(第二个信号量的值>=1) 96 | struct sembuf sops[1] = { {1, -1, SEM_UNDO} }; 97 | size_t nsops = 1; 98 | //返回当前可用的资源数量 99 | return semop(this->sem_id, &sops[0], nsops); 100 | } 101 | 102 | /* 103 | 函数说明:对信号尝试上锁 104 | */ 105 | bool CSemMutex::TryShareLock() const 106 | { 107 | struct sembuf sops[2] = { {0, 0, SEM_UNDO | IPC_NOWAIT}, 108 | {1, 1, SEM_UNDO | IPC_NOWAIT} }; 109 | size_t nsops = 2; 110 | int res = semop(this->sem_id, &sops[0], nsops); 111 | if (res == -1) 112 | { 113 | if (errno == EAGAIN) 114 | { 115 | //无法获得锁 116 | return false; 117 | } 118 | else 119 | { 120 | throw ("[CSemMutex::TryLock]信号操作出错: " + string(strerror(errno))); 121 | } 122 | } 123 | return true; 124 | } 125 | 126 | /* 127 | 函数说明:进入互斥锁 128 | */ 129 | int CSemMutex::MutexLock() const 130 | { 131 | //进入互斥锁, 第一个信号量和第二个信号都没有被使用过(即, 两个锁都没有被使用) 132 | //等待第一个信号量变为0 133 | //等待第二个信号量变为0 134 | //释放第一个信号量(第一个信号量+1, 表示有一个进程使用第一个信号量) 135 | struct sembuf sops[3] = { {0, 0, SEM_UNDO}, 136 | {1, 0, SEM_UNDO}, 137 | {0, 1, SEM_UNDO} }; 138 | size_t nsops = 3; 139 | return semop(this->sem_id, &sops[0], nsops); 140 | } 141 | 142 | /* 143 | 函数说明:解除互斥锁 144 | */ 145 | int CSemMutex::UnMutexLock() const 146 | { 147 | //解除互斥锁, 有进程使用过第一个信号量 148 | //等待第一个信号量(信号量值>=1) 149 | struct sembuf sops[1] = { {0, -1, SEM_UNDO} }; 150 | size_t nsops = 1; 151 | return semop(this->sem_id, &sops[0], nsops); 152 | } 153 | 154 | /* 155 | 函数说明:尝试上锁 156 | */ 157 | bool CSemMutex::TryMutexLock() const 158 | { 159 | struct sembuf sops[3] = { {0, 0, SEM_UNDO | IPC_NOWAIT}, 160 | {1, 0, SEM_UNDO | IPC_NOWAIT}, 161 | {0, 1, SEM_UNDO | IPC_NOWAIT} }; 162 | size_t nsops = 3; 163 | 164 | int res = semop(this->sem_id, &sops[0], nsops); 165 | if (res == -1) 166 | { 167 | if (errno == EAGAIN) 168 | { 169 | //无法获得锁 170 | return false; 171 | } 172 | else 173 | { 174 | throw ("[CSemMutex::TryWLock]锁操作出错: " + string(strerror(errno))); 175 | } 176 | } 177 | return true; 178 | } -------------------------------------------------------------------------------- /src/CSemMutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | /* 11 | PV操作: 12 | 函数:int semop(int semid,struct sembuf *sops,size_t nsops); 13 | 参数:semid为信号量集的标识符; 14 | sops指向进行操作的结构体数组的首地址; 15 | nsops 指出将要进行操作的信号的个数。 16 | 返回:semop 函数调用成功返回 0,失败返回 -1 17 | ---------------------------------------------------------------------------------------- 18 | 结构体说明struct sembuf *sop 19 | struct sembuf 20 | { 21 | unsigned short sem_num; //信号在信号集中的索引,0代表第一个信号,1代表第二个信号 22 | short sem_op; //操作类型 23 | short sem_flg; //操作标志 24 | }; 25 | ---------------------------------------------------------------------------------------- 26 | sem_op参数说明: 27 | sem_op > 0 信号加上 sem_op 的值,表示进程释放控制的资源; 28 | sem_op = 0 如果没有设置 IPC_NOWAIT,则调用进程进入睡眠状态,直到信号量的值为0; 29 | 否则进程不回睡眠,直接返回 EAGAIN 30 | sem_op < 0 信号加上 sem_op 的值。也就是需要几个信号值,若没有设置 IPC_NOWAIT , 31 | 否则调用进程阻塞,直到资源可用;否则进程直接返回EAGAIN 32 | ---------------------------------------------------------------------------------------- 33 | sem_flg参数:该参数可设置为 IPC_NOWAIT 或 SEM_UNDO 两种状态。 34 | IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。 35 | SEM_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。 36 | 这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。 37 | ---------------------------------------------------------------------------------------- 38 | */ 39 | 40 | /* 41 | 类说明:system v信号量,常用于进程间的同步。 42 | 在这个锁实现中,涉及到两个信号量: 43 | 信号量1:表示互斥锁的信号数目。 44 | 每次 "获得锁"的时候,会要求该信号量为0, 45 | 每次 "上锁" 的时候会要求该信号量为0,并且新增一次, 46 | 每次 "解锁" 会减去1。 47 | 48 | 信号量2:表示共享锁的进程数目。 49 | 每次 "获得锁" 会增加1, 50 | 每次 "上锁" 会要求该信号量为0。 51 | 每次 "解锁" 会减去1, 52 | 53 | opt数组之间都是原子操作,保证SEM_UNDO,就可以保证一致性和回滚。这是该信号锁的实现原理 54 | */ 55 | 56 | class CSemMutex 57 | { 58 | public: 59 | //构造函数 60 | CSemMutex(); 61 | //带参数构造函数 62 | CSemMutex(key_t i_Key); 63 | //析构函数 64 | ~CSemMutex(); 65 | //初始化密钥信号 66 | void Init(key_t i_Key); 67 | 68 | //获取信号量的key 69 | key_t getkey() const { return sem_key; }; 70 | //获取信号量ID 71 | int getid() const { return sem_id; }; 72 | 73 | //上共享锁 74 | int ShareLock() const; 75 | //解共享锁 76 | int UnShareLock() const; 77 | //尝试加共享锁 78 | bool TryShareLock() const; 79 | 80 | //加互斥锁 81 | int MutexLock() const; 82 | //解互斥锁 83 | int UnMutexLock() const; 84 | //尝试互斥锁 85 | bool TryMutexLock() const; 86 | 87 | protected: 88 | //信号量id 89 | int sem_id; 90 | //信号量key值 91 | key_t sem_key; 92 | }; -------------------------------------------------------------------------------- /src/CSendTask.cpp: -------------------------------------------------------------------------------- 1 | #include "CSendTask.h" 2 | 3 | CSendTask::CSendTask(msg_t m_recv_msg, int& pack_num) 4 | { 5 | this->recv_msg = m_recv_msg; 6 | this->pack_num = pack_num; 7 | } 8 | 9 | CSendTask::~CSendTask() 10 | { 11 | } 12 | 13 | void CSendTask::Run() 14 | { 15 | char str_tmp[MAX_CHAR_LEN] = { '\0' }; 16 | t_GetProgress get_pack; //视频包 17 | t_Answer ans_pack; //应答包 18 | 19 | //获取connfd表示的连接上的对端地址 20 | socklen_t sockLen = sizeof(localaddr); 21 | //发送应答包 22 | int res = getsockname(recv_msg.socketFd, (struct sockaddr*)&localaddr, &sockLen); 23 | if (res != 0) 24 | { 25 | journal->ErrMsgWriteLog("[发送端]getsockname出错"); 26 | } 27 | switch (recv_msg.fun_typ) 28 | { 29 | case GET_PREGRORESS: 30 | printf("[发送端]收到发送[视频信息包]的命令\n"); 31 | memset(&get_pack, 0, sizeof(t_GetProgress)); 32 | //前段服务器从后端服务器内读取应答包信息(后端共享内存) 33 | b2f_share_memory->ReadShm(&get_pack, sizeof(get_pack), recv_msg.index); 34 | printf("[发送端]从共享内存中读取了视频帧数包\n"); 35 | //发送应答包 36 | this->SendGetPack(recv_msg.socketFd, get_pack); 37 | break; 38 | case ANSWER: 39 | printf("[发送端]收到发送[应答包]的命令\n"); 40 | //从共享内存内读取应答包信息 41 | memset(&ans_pack, 0, sizeof(t_Answer)); 42 | b2f_share_memory->ReadShm(&ans_pack, sizeof(ans_pack), recv_msg.index); 43 | printf("[发送端]从共享内存中读取了应答包\n"); 44 | //发送应答包 45 | this->SendAns(recv_msg.socketFd, ans_pack); 46 | break; 47 | case CRC_ERR_RESEND: 48 | //CRC错误, 重发包 49 | printf("[发送端]收到发送[CRC校验码错误包]的命令\n"); 50 | memset(&ans_pack, 0, sizeof(t_Answer)); 51 | ans_pack.anser_type = recv_msg.index; 52 | ans_pack.head.packet_type = CRC_ERR_RESEND; 53 | //发送应答包 54 | this->SendAns(recv_msg.socketFd, ans_pack); 55 | break; 56 | default: 57 | //发送给客户端应答包CRC计算 58 | memset(str_tmp, '\0', sizeof(str_tmp)); 59 | sprintf(str_tmp, "[发送端]收到未知类型的消息:%d", recv_msg.m_type); 60 | journal->ErrMsgWriteLog(str_tmp, true); 61 | break; 62 | } 63 | } 64 | 65 | 66 | int CSendTask::SendAns(int fd, t_Answer ans_pack) 67 | { 68 | char str_tmp[MAX_CHAR_LEN * 2] = { '\0' }; 69 | //发送给客户端应答包CRC计算 70 | memset(str_tmp, '\0', sizeof(str_tmp)); 71 | 72 | //设置发送包信息 73 | int crc_len = sprintf(str_tmp, "%d", ans_pack.anser_type); 74 | ans_pack.head.packet_CRC = CCrc::crc16((unsigned char*)str_tmp, crc_len); 75 | ans_pack.head.packet_size = sizeof(t_Answer); 76 | ans_pack.head.packet_num = pack_num++; 77 | 78 | //发送给客户端 79 | int res = send(fd, &ans_pack, sizeof(ans_pack), MSG_NOSIGNAL); 80 | if (res == -1) 81 | { 82 | //写入发送包信息 83 | memset(str_tmp, '\0', MAX_CHAR_LEN); 84 | sprintf(str_tmp, "[发送端]客户端[%s:%d][%d]的应答包[%d]发送失败", 85 | inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port), fd, ans_pack.head.packet_type); 86 | journal->ErrMsgWriteLog(str_tmp); 87 | //如果是注册or删除已经成功操作了,则进行回退操作 88 | msg_t msg_buf; 89 | msg_buf.fun_typ = RollBack; 90 | msg_buf.m_type = 3; 91 | msg_buf.socketFd = fd; 92 | msg_buf.index = 0; 93 | if (ans_pack.head.packet_type = REG_ANSWER && ans_pack.anser_type == ANSWER_LOGIN_SUCCESS) 94 | { 95 | f2b_msg_queue->SendMsg(&msg_buf, msg_len, 0); 96 | } 97 | else if (ans_pack.head.packet_type = DELETE_VIDEO_ANSWER && ans_pack.anser_type == ANSWER_DELETE_SUCCESS) 98 | { 99 | f2b_msg_queue->SendMsg(&msg_buf, msg_len, 0); 100 | } 101 | else if (ans_pack.head.packet_type = INSERT_VIDEO_ANSWER && ans_pack.anser_type == ANSWER_INSERT_SUCCESS) 102 | { 103 | f2b_msg_queue->SendMsg(&msg_buf, msg_len, 0); 104 | } 105 | return -1; 106 | } 107 | //写入发送包信息 108 | memset(str_tmp, '\0', MAX_CHAR_LEN * 2); 109 | sprintf(str_tmp, "[发送端]客户端[%s:%d]的应答包发送成功\n\ 110 | [发送端]应答包CRC:%d\n \ 111 | [发送端]应答包长度:%d\n \ 112 | [发送端]应答包类型:%d\n \ 113 | [发送端]应答包数据:%d\n", 114 | inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port), 115 | ans_pack.head.packet_CRC, ans_pack.head.packet_size, ans_pack.head.packet_type, ans_pack.anser_type); 116 | journal->WriteLog(str_tmp); 117 | return res; 118 | } 119 | 120 | int CSendTask::SendGetPack(int fd, t_GetProgress get_pack) 121 | { 122 | char str_tmp[MAX_CHAR_LEN * 2] = { '\0' }; 123 | 124 | //设置获取视频帧数包信息 125 | memset(str_tmp, '\0', sizeof(str_tmp)); 126 | int crclen = sprintf(str_tmp, "%d%d%d", get_pack.user_id, get_pack.video_id, get_pack.video_progress); 127 | get_pack.head.packet_CRC = CCrc::crc16((unsigned char*)str_tmp, crclen); 128 | get_pack.head.packet_type = GET_PREGRORESS; 129 | get_pack.head.packet_size = sizeof(t_GetProgress); 130 | get_pack.head.packet_num = pack_num++; 131 | 132 | //发送应答包 133 | int res = send(fd, &get_pack, sizeof(get_pack), MSG_NOSIGNAL); 134 | if (res < 0) 135 | { 136 | //写入发送包信息 137 | memset(str_tmp, '\0', MAX_CHAR_LEN * 2); 138 | sprintf(str_tmp, "[发送端]客户端[%s:%d][%d]的视频帧数包[%d]发送失败", 139 | inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port), fd, get_pack.head.packet_type); 140 | journal->ErrMsgWriteLog(str_tmp); 141 | return -1; 142 | } 143 | //写入发送包信息 144 | memset(str_tmp, '\0', MAX_CHAR_LEN * 2); 145 | sprintf(str_tmp, "[发送端]客户端[%s:%d]视频帧数包发送成功\n\ 146 | [发送端]视频帧数CRC:%d\n \ 147 | [发送端]视频帧数长度:%d\n \ 148 | [发送端]视频帧数类型:%d\n \ 149 | [发送端]视频帧数用户ID:%d\n\ 150 | [发送端]视频帧数视频ID:%s\n\ 151 | [发送端]视频帧数视频帧数:%d\n", 152 | inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port), 153 | get_pack.head.packet_CRC, get_pack.head.packet_size, get_pack.head.packet_type, 154 | get_pack.user_id, get_pack.video_id, get_pack.video_progress); 155 | journal->WriteLog(str_tmp); 156 | return 0; 157 | } -------------------------------------------------------------------------------- /src/CSendTask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CTask.h" 3 | #include "CCrc.h" 4 | #include "global.h" 5 | 6 | class CSendTask : public CTaskBase 7 | { 8 | public: 9 | CSendTask(msg_t m_recv_msg, int& pack_num); 10 | ~CSendTask(); 11 | void Run(); 12 | int SendAns(int fd, t_Answer ans_pack); 13 | int SendGetPack(int fd, t_GetProgress get_pack); 14 | private: 15 | msg_t recv_msg; 16 | int pack_num; 17 | struct sockaddr_in localaddr; 18 | }; 19 | -------------------------------------------------------------------------------- /src/CServerJson.cpp: -------------------------------------------------------------------------------- 1 | #include "CServerJson.h" 2 | 3 | bool CServerJson::ReadJson() 4 | { 5 | assert(doc.HasMember("server_ip_address")); 6 | assert(doc["server_set"]["server_ip_address"].IsString()); 7 | 8 | assert(doc.HasMember("server_port")); 9 | assert(doc["server_set"]["server_port"].IsInt()); 10 | 11 | assert(doc.HasMember("server_protocol_type")); 12 | assert(doc["server_set"]["server_protocol_type"].IsString()); 13 | 14 | assert(doc.HasMember("max_connectNum")); 15 | assert(doc["server_set"]["max_connectNum"].IsInt()); 16 | 17 | assert(doc.HasMember("max_threadNum")); 18 | assert(doc["server_set"]["max_threadNum"].IsInt()); 19 | 20 | //获取心跳的设置相关设置 21 | return true; 22 | } -------------------------------------------------------------------------------- /src/CServerJson.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CJson.h" 3 | #include "CSigleton.h" 4 | 5 | class CServerJson : public CJson 6 | { 7 | public: 8 | CServerJson(const char* json_add) :CJson(json_add) {}; 9 | bool ReadJson(); 10 | 11 | private: 12 | CServerJson(const CServerJson&); 13 | }; 14 | -------------------------------------------------------------------------------- /src/CServerSend.cpp: -------------------------------------------------------------------------------- 1 | #include "CServerSend.h" 2 | 3 | CServerSend::CServerSend(CThreadPool* m_thread_pool) 4 | { 5 | this->thread_pool = m_thread_pool; 6 | this->CreatThead(); 7 | } 8 | 9 | CServerSend::~CServerSend() 10 | { 11 | } 12 | 13 | void* CServerSend::thfunc(void* arg) 14 | { 15 | CServerSend* server_send = (CServerSend*)arg; 16 | CSendTask* send_task = nullptr; 17 | msg_t* recv_msg = (msg_t*)malloc(sizeof(msg_t)); //收到消息的结构体 18 | int pack_num = 1; //初始发送包 19 | while (true) 20 | { 21 | //监听信息 22 | printf("[发送端]线程[tid:% lu]监听数据中...\n", pthread_self()); 23 | memset(recv_msg, 0, sizeof(msg_t)); 24 | //收到后端发往前端的消息队列 25 | b2f_msg_queue->ReceiveMsg(recv_msg, msg_len, 2, 0); 26 | printf("[发送端]收到[来自]%d, [类型]%d,[索引]%d, [fd值]%d的消息队列\n", 27 | recv_msg->m_type, recv_msg->fun_typ, recv_msg->index, recv_msg->socketFd); 28 | send_task = new CSendTask(*recv_msg, pack_num); 29 | server_send->thread_pool->AddTask(send_task); 30 | printf("[发送端]线程任务创建完毕\n"); 31 | } 32 | free(recv_msg); 33 | return (void*)0; 34 | } 35 | 36 | void CServerSend::CreatThead() 37 | { 38 | pthread_t tidp; 39 | int ret; 40 | char str_tmp[MAX_CHAR_LEN]; 41 | //消息队列创建 42 | ret = pthread_create(&tidp, NULL, thfunc, this); 43 | if (ret) 44 | { 45 | memset(str_tmp, '\0', MAX_CHAR_LEN); 46 | sprintf(str_tmp, "前置服务器, [发送端]线程创建失败:%d,退出程序", ret); 47 | journal->ErrMsgWriteLog(str_tmp); 48 | system("pause"); 49 | exit(-1); 50 | } 51 | } -------------------------------------------------------------------------------- /src/CServerSend.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "global.h" 8 | #include "CThreadPool.h" 9 | #include "Packet.h" 10 | #include "CSendTask.h" 11 | class CServerSend 12 | { 13 | public: 14 | CServerSend(CThreadPool* m_thread_pool); 15 | ~CServerSend(); 16 | private: 17 | static void* thfunc(void* arg); //线程监听函数 18 | void CreatThead(); 19 | CThreadPool* thread_pool; 20 | }; 21 | -------------------------------------------------------------------------------- /src/CShareMemory.cpp: -------------------------------------------------------------------------------- 1 | #include "CShareMemory.h" 2 | #define ERR_EXIT(m) \ 3 | do { \ 4 | perror(m); \ 5 | fprintf(stderr, "Error: (%s:%s:%d)", __FILE__, __func__, __LINE__); \ 6 | exit(EXIT_FAILURE); \ 7 | } while(0) 8 | 9 | CShareMemory::CShareMemory(int index, int block_size, int block_num) 10 | { 11 | if (block_size <= 0 || block_num <= 0) 12 | { 13 | printf("共享内存的值不能设为非正整数\n"); 14 | exit(-1); 15 | } 16 | //打开共享内存 17 | this->Init(index, block_size, block_num); 18 | } 19 | 20 | CShareMemory::CShareMemory() 21 | { 22 | m_shmhead = NULL; 23 | m_open = false; 24 | } 25 | 26 | CShareMemory::~CShareMemory() 27 | { 28 | //释放结构体数组 29 | delete[] shm_index.repeatIndex; 30 | //关闭套接字结构体 31 | this->CloseShm(); 32 | } 33 | 34 | /* 35 | 函数说明: 连接共享内存 36 | */ 37 | bool CShareMemory::Init(int index, int block_size, int block_num) 38 | { 39 | //定义索引区数组 40 | shm_index.repeatIndex = new repeatIndex_t[block_num]; 41 | index_size = sizeof(sem_t) * 2 + sizeof(shmindex_t) * block_num; 42 | //共享内存的总大小 43 | int all_num = block_size * block_num + index_size; 44 | 45 | //创建共享内存 46 | /* 内核是以页为单位分配内存, 47 | 当参数size的值不是系统内存页长的整数倍时, 48 | 系统会分配给进程最小的可以满足size长的页数, 49 | 但是最后一页的剩余部分是不可用的 50 | */ 51 | 52 | //1. 查看是否已经存在共享内存,如果有则删除旧的 53 | int shm_id = shmget((key_t)index, 0, 0); 54 | if (shm_id != -1) 55 | { 56 | shmctl(shm_id, IPC_RMID, NULL); //删除已经存在的共享内存 57 | } 58 | 59 | //2. 创建共享内存 60 | shm_id = shmget((key_t)index, all_num, 0666 | IPC_CREAT); 61 | if (shm_id == -1) 62 | { 63 | ERR_EXIT("shmget error"); 64 | } 65 | 66 | //3. 连接共享内存 67 | //调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回 - 1. 68 | this->m_shmhead = shmat(shm_id, NULL, 0); 69 | if (this->m_shmhead == (void*)-1) 70 | { 71 | ERR_EXIT("shmat error"); 72 | } 73 | memset(m_shmhead, 0, all_num); //初始化共享内存大小 74 | 75 | //4.初始化信息 76 | this->block_size = block_size; //共享信息写入 77 | this->block_num = block_num; //写入每块大小 78 | this->m_open = true; 79 | 80 | //5.初始化信号量 81 | sem_init(&shm_index.sem_empty, 1, 0); // 第一个1表示可以跨进程共享,第二个0表示初始值 82 | sem_init(&shm_index.sem_full, 1, block_num);// 第一个1表示可以跨进程共享,第二个blocks表示初始值 83 | for (int i = 0; i < block_num; i++) 84 | { 85 | sem_init(&shm_index.repeatIndex[i].sem_mutex, 1, 1);//第一个1表示可以跨进程共享,第二个1表示初始值 86 | shm_index.repeatIndex[i].flag = true; 87 | } 88 | 89 | //6.写入索引区 90 | memcpy(m_shmhead, &shm_index, index_size); 91 | 92 | printf("共享内存初始化完毕\n"); 93 | 94 | return true; 95 | } 96 | 97 | /* 98 | 函数说明:销毁共享内存 99 | */ 100 | void CShareMemory::Destory() 101 | { 102 | //删除信号量 103 | sem_destroy(&shm_index.sem_empty); 104 | sem_destroy(&shm_index.sem_full); 105 | for (int i = 0; i < this->block_num; i++) 106 | { 107 | sem_destroy(&shm_index.repeatIndex[i].sem_mutex); 108 | shm_index.repeatIndex[i].flag = false; 109 | } 110 | 111 | //销毁共享内存 112 | if (shmctl(this->shm_id, IPC_RMID, 0) == -1) 113 | { 114 | printf("Delete shm_id=%d \n", this->shm_id); 115 | ERR_EXIT("shmctl rm"); 116 | } 117 | //相关值初始化 118 | m_shmhead = NULL; 119 | m_open = false; 120 | } 121 | 122 | /* 123 | 函数说明: 静态销毁共享内存 124 | */ 125 | void CShareMemory::Destroy(int key) 126 | { 127 | int shm_id = 0; 128 | //查看是否已经存在共享内存,如果有则删除旧的 129 | shm_id = shmget((key_t)key, 0, 0); 130 | if (shm_id != -1) 131 | { 132 | printf("Delete shm_id=%d \n", shm_id); 133 | // 删除已经存在的共享内存 134 | shmctl(shm_id, IPC_RMID, NULL); 135 | } 136 | } 137 | 138 | /* 139 | 函数说明: 断开与共享内存的连接 140 | */ 141 | void CShareMemory::CloseShm() 142 | { 143 | if (m_open) 144 | { 145 | //共享内存脱离 146 | Destory(); 147 | m_shmhead = NULL; 148 | m_open = false; 149 | } 150 | } 151 | 152 | /* 153 | 函数说明:往共享内存内写数据 154 | */ 155 | int CShareMemory::WriteShm(void* buf, int buf_len) 156 | { 157 | if (buf_len >= block_size) 158 | { 159 | printf("写入共享内存的东西超过了共享内存所能容纳的最大长度;\n"); 160 | exit(-1); 161 | } 162 | //获取索引区的地址 163 | shmindex_t* pHead = (shmindex_t*)m_shmhead; 164 | //是否有资源写 165 | sem_wait(&pHead->sem_full); 166 | //循环获取可写资源头 167 | int i; 168 | for (i = 0; i < block_num; i++) 169 | { 170 | if (pHead->repeatIndex[i].flag == true) 171 | { 172 | break; 173 | } 174 | i++; 175 | } 176 | sem_wait(&pHead->repeatIndex[i].sem_mutex); 177 | pHead->repeatIndex[i].flag = false; //标识符设置为不能写入 178 | //连接共享内存 179 | printf("写入第[%d]块共享内存\n", i); 180 | memcpy(m_shmhead + i * (this->block_size) + index_size, buf, this->block_size); 181 | //读取位置标识符 182 | printf("数据写入共享内存成功\n"); 183 | //解除互斥锁 184 | sem_post(&pHead->repeatIndex[i].sem_mutex); //解除互斥 185 | sem_post(&pHead->sem_empty); //可用读资源+1 186 | //返回索引位置 187 | return i; 188 | } 189 | 190 | /* 191 | 函数说明: 读取共享内存的数据 192 | */ 193 | void CShareMemory::ReadShm(void* buf, int buf_len, int rd_index) 194 | { 195 | if (buf_len >= block_size) 196 | { 197 | printf("读取共享内存的东西超过了共享内存所能容纳的最大长度;\n"); 198 | exit(-1); 199 | } 200 | //获取索引区的地址 201 | shmindex_t* pHead = (shmindex_t*)m_shmhead; 202 | //检测写资源是否可用 203 | sem_wait(&pHead->sem_empty); 204 | //互斥上锁 205 | sem_wait(&pHead->repeatIndex[rd_index].sem_mutex); 206 | //读取信息, 如果是读取最后1块, 有多少写多少 207 | memcpy(buf, this->m_shmhead + rd_index * (this->block_size) + index_size, buf_len); 208 | memset(this->m_shmhead + rd_index * (this->block_size) + index_size, 0, buf_len); 209 | //标识符设置为可以写入 210 | printf("读取共享内存[%d],索引为:%d\n", this->shm_id, rd_index); 211 | pHead->repeatIndex[rd_index].flag = true; 212 | //解除互斥 213 | sem_post(&pHead->repeatIndex[rd_index].sem_mutex); 214 | //增加可写资源 215 | sem_post(&pHead->sem_full); 216 | } -------------------------------------------------------------------------------- /src/CShareMemory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | typedef struct repeatIndex_st 15 | { 16 | //信号量必须放在共享内存头部才行 17 | int flag; //判断是否是可写内存 18 | sem_t sem_mutex; //用来互斥用的信号量 19 | }repeatIndex_t; 20 | 21 | typedef struct shmhead_st 22 | { 23 | //信号量必须放在共享内存头部才行 24 | sem_t sem_full; // 用来控制共享内存是否满的信号量 25 | sem_t sem_empty; // 用来控制共享内存是否空的信号量 26 | repeatIndex_t* repeatIndex; //用来互斥用的信号量 27 | }shmindex_t; 28 | 29 | class CShareMemory 30 | { 31 | public: 32 | CShareMemory(int index, int block_size, int block_num); 33 | CShareMemory(); 34 | ~CShareMemory(); 35 | 36 | //创建和销毁 37 | bool Init(int index, int block_size, int block_num); 38 | void Destory(); 39 | static void Destroy(int key); //静态删除共享内存方法 40 | 41 | //断开共享内存 42 | void CloseShm(); 43 | 44 | //读取和存储 45 | int WriteShm(void* buf, int buf_len); 46 | void ReadShm(void* buf, int buf_len, int rd_index); 47 | 48 | protected: 49 | int block_size; //块大小 50 | int block_num; //总块数 51 | int index_size; //索引区的大小 52 | 53 | int shm_id; //共享内存ID 54 | bool m_open; //判断共享内存是否打开 55 | void* m_shmhead; // 共享内存头部指针 56 | 57 | shmindex_t shm_index; //索引区数组指针 58 | }; 59 | -------------------------------------------------------------------------------- /src/CSigleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | /************************************************************************/ 7 | /* 名称:万能单例类 */ 8 | /* 说明:可把任何类包装成线程安全的全局单例类,出口默认智能指针 */ 9 | /************************************************************************/ 10 | 11 | template 12 | class CSingleton 13 | { 14 | public: 15 | 16 | //获取全局单例对象 17 | template 18 | static std::shared_ptr GetInstance(Args&&... args) 19 | { 20 | if (!m_pSington) 21 | { 22 | std::lock_guard gLock(m_Mutex); 23 | if (nullptr == m_pSington) 24 | { 25 | m_pSington = std::make_shared(std::forward(args)...); 26 | } 27 | } 28 | return m_pSington; 29 | } 30 | 31 | //主动析构单例对象(一般不需要主动析构,除非特殊需求) 32 | static void DesInstance() 33 | { 34 | if (m_pSington) 35 | { 36 | m_pSington.reset(); 37 | m_pSington = nullptr; 38 | } 39 | } 40 | 41 | private: 42 | explicit CSingleton(); 43 | CSingleton(const CSingleton&) = delete; 44 | CSingleton& operator=(const CSingleton&) = delete; 45 | 46 | private: 47 | static std::shared_ptr m_pSington; 48 | static std::mutex m_Mutex; 49 | }; 50 | 51 | template 52 | std::shared_ptr CSingleton::m_pSington = nullptr; 53 | 54 | template 55 | std::mutex CSingleton::m_Mutex; -------------------------------------------------------------------------------- /src/CSocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "CServerJson.h" 18 | #include "global.h" 19 | using namespace std; 20 | 21 | //socket套接字基类 22 | class CSocketBase 23 | { 24 | public: 25 | //构造函数--设置IP地址及其相关信息 26 | CSocketBase(); 27 | //析构函数 28 | virtual ~CSocketBase(); 29 | 30 | //判断IPv4地址的合法性 31 | bool JudgeIpv4(); 32 | //判断IPv6地址的合法性 33 | bool JudgeIpv6(); 34 | 35 | //查看端口是否被占用 36 | std::string isPortOpen(const std::string& domain, const std::string& port); 37 | //如果返回true,则说明,某个服务处于监听状态,同时说明这个端口号已经被这个服务所占用, 38 | //不能再被其他服务所用 39 | bool isListening(const std::string& ip, const std::string& port); 40 | //杀死端口 41 | bool killPort(); 42 | 43 | //设置结构体信息 44 | void SetIpv4(); //设置ipv4协议类型 45 | void SetIpv6(); //设置ipv6协议类型 46 | 47 | //内联函数,获取相关信息 48 | int GetsocketFd() { return this->socket_fd; } //获取套接字标识符 49 | struct sockaddr* GetSockAddr() { return (struct sockaddr*)this->this_addr; } //获取结构体地址 50 | void* GetAddr() { return this->this_addr; } //获取套接字ip地址 51 | int GetAddrLen() { return sizeof(&this->this_addr); }//获取套接字ip地址长度 52 | 53 | //判断端口地址的合法性--默认为1024--65535 54 | virtual bool JudgePort(); 55 | //虚启动函数--用以重写所需协议类型(默认TCP/IPV4) 56 | virtual void Start(); 57 | //纯虚运行函数--说明运行情况 58 | virtual void Run() = 0; 59 | //纯虚停止函数--说明停止运行的情况 60 | virtual void Stop() = 0; 61 | 62 | protected: 63 | int socket_fd; //套接字标识符 64 | void* this_addr; //ip地址 65 | }; 66 | 67 | //服务器(基于ipv4) 68 | class CServerSocket : public CSocketBase 69 | { 70 | public: 71 | CServerSocket(); 72 | void Run(); 73 | void Stop(); 74 | 75 | private: 76 | int maxNum; 77 | }; 78 | -------------------------------------------------------------------------------- /src/CTask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "global.h" 12 | #include "Packet.h" 13 | #include "CLoginAndReg.h" 14 | #include "CHeartbeat.h" 15 | #include "CShareMemory.h" 16 | #include "CMsgQueue.h" 17 | #include "CVideoInfo.h" 18 | #include "CCrc.h" 19 | 20 | /* 21 | 线程任务父类 22 | */ 23 | class CTaskBase 24 | { 25 | public: 26 | //构造函数任务参数指针初始化 27 | CTaskBase() {}; 28 | CTaskBase(void* arg) { this->ptrData = arg; } 29 | virtual ~CTaskBase() {}; 30 | //设置任务数据 31 | void SetData(void* data) { this->ptrData = data; } 32 | virtual void Run() = 0; 33 | protected: 34 | void* ptrData; //执行任务的具体参数 35 | }; -------------------------------------------------------------------------------- /src/CThreadPool.cpp: -------------------------------------------------------------------------------- 1 | #include "CThreadPool.h" 2 | 3 | //= = = = = = = = = = = = = = = = = = = = 4 | // @函数名称: CThreadPool(int max_count) 5 | // @函数说明: 构造函数,创建线程池 6 | // @参数说明: max_count最大的线程数量 7 | // @返回值: 无 8 | //= = = = = = = = = = = = = = = = = = = = 9 | CThreadPool::CThreadPool(int maxCount) 10 | { 11 | if (maxCount >= 200) 12 | { 13 | journal->ErrMsgWriteLog("线程池数量超过200", true); 14 | } 15 | //相关数值初始化 16 | this->maxCount = maxCount; 17 | this->m_isQuit = false; 18 | //创建线程同步锁 19 | this->m_mutex = new CMutexLock(); 20 | //创建条件变量 21 | this->m_cond = new CCond(*this->m_mutex); 22 | //创建线程 23 | this->CreateThread(); 24 | } 25 | 26 | //= = = = = = = = = = = = = = = = = = = = 27 | // @函数名称: ~CThreadPool() 28 | // @函数说明: 析构函数, 停止所有的线程任务 29 | // @参数说明: 无 30 | // @返回值: 无 31 | //= = = = = = = = = = = = = = = = = = = = 32 | CThreadPool::~CThreadPool() 33 | { 34 | StopAll(); 35 | } 36 | 37 | //= = = = = = = = = = = = = = = = = = = = 38 | // @函数名称: AddTask(CTaskBase* pTask) 39 | // @函数说明: 往任务队列里添加任务并发出线程同步信号 40 | // @参数说明: 参数1:线程的任务 41 | // @返回值: 无 42 | //= = = = = = = = = = = = = = = = = = = = 43 | void CThreadPool::AddTask(CTaskBase* pTask) 44 | { 45 | //上锁 46 | this->m_mutex->Lock(); 47 | m_taskVec.push_back(pTask); 48 | //发出线程同步信号 49 | this->m_cond->Notify(); 50 | //解锁 51 | this->m_mutex->Unlock(); 52 | } 53 | 54 | //= = = = = = = = = = = = = = = = = = = = 55 | // @函数名称: StopAll() 56 | // @函数说明: 停止所有的线程 57 | // @参数说明: 参数1:线程的任务 58 | // @返回值: 无 59 | //= = = = = = = = = = = = = = = = = = = = 60 | int CThreadPool::StopAll() 61 | { 62 | //避免重复调用 63 | if (m_isQuit) 64 | { 65 | return -1; 66 | } 67 | journal->WriteLog("开始结束所有线程\n"); 68 | m_isQuit = true; 69 | 70 | //唤醒所有等待线程 71 | this->m_cond->NotifyAll(); 72 | 73 | //清理僵尸线程 74 | for (int i = 0; i < maxCount; i++) 75 | { 76 | pthread_join(pthreadId[i], NULL); 77 | } 78 | 79 | //删除线程Id 80 | delete[] pthreadId; 81 | pthreadId = nullptr; 82 | 83 | //清空任务列表 84 | m_taskVec.clear(); 85 | 86 | //销毁互斥锁和条件变量 87 | delete this->m_cond; 88 | this->m_cond = nullptr; 89 | delete this->m_mutex; 90 | this->m_mutex = nullptr; 91 | return 0; 92 | } 93 | 94 | //= = = = = = = = = = = = = = = = = = = = 95 | // @函数名称: GetTask() 96 | // @函数说明: 从任务池中取出任务 97 | // @参数说明: 无 98 | // @返回值: 无 99 | //= = = = = = = = = = = = = = = = = = = = 100 | CTaskBase* CThreadPool::GetTask() 101 | { 102 | vector::iterator iter; 103 | CTaskBase* task = nullptr; 104 | //线程上锁 105 | this->m_mutex->Lock(); 106 | //如果任务列表为空,且线程处于运行状态则等待新任务进入任务队列 107 | //我循环任务队列, 一直循环, 直到任务队列有任务 108 | while (m_taskVec.empty() && !m_isQuit) 109 | { 110 | //循环等待,直到收到一个解除等待信号 111 | printf("没有任务,线程[tid:% lu]阻塞等待...\n", pthread_self()); 112 | this->m_cond->Wait(); 113 | } 114 | //如果处于线程处于退出状态,则退出线程 115 | if (m_isQuit) 116 | { 117 | this->m_mutex->Unlock(); 118 | char str_tmp[MAX_CHAR_LEN] = { "\0" }; 119 | sprintf(str_tmp, "[tid: %lu]\t 线程退出 \n", pthread_self()); 120 | journal->WriteLog(str_tmp); 121 | system("pause"); 122 | pthread_exit(NULL); 123 | exit(-1); 124 | } 125 | //从线程池取出一个任务并处理 126 | printf("收到任务,线程[tid: %lu]运行任务\n", pthread_self()); 127 | 128 | //采用迭代器保证一定能够取出一个任务 129 | iter = m_taskVec.begin(); 130 | if (iter != m_taskVec.end()) 131 | { 132 | task = *iter; 133 | m_taskVec.erase(iter); 134 | } 135 | /* 136 | else 137 | { 138 | journal->ErrMsgWriteLog("任务队列内无任务,且无法阻塞等待, 程序退出", true); 139 | exit(-1); 140 | } 141 | */ 142 | //线程解锁 143 | this->m_mutex->Unlock(); 144 | return task; 145 | } 146 | 147 | //= = = = = = = = = = = = = = = = = = = = 148 | // @函数名称: GetTaskSize() 149 | // @函数说明: 获取任务的大小 150 | // @参数说明: 无 151 | // @返回值: 无 152 | //= = = = = = = = = = = = = = = = = = = = 153 | int CThreadPool::GetTaskSize() 154 | { 155 | this->m_mutex->Lock(); 156 | int size = (int)this->m_taskVec.size(); 157 | this->m_mutex->Unlock(); 158 | return size; 159 | } 160 | 161 | //= = = = = = = = = = = = = = = = = = = = 162 | // @函数名称: ThreadFun(void* arg) 163 | // @函数说明: 类指针,用以访问非静态成员变量 164 | // @参数说明: 无 165 | // @返回值: 无 166 | //= = = = = = = = = = = = = = = = = = = = 167 | void* CThreadPool::ThreadFun(void* arg) 168 | { 169 | //thread为一个线程池的指针,指向整个线程池 170 | CThreadPool* thread = (CThreadPool*)arg; 171 | pthread_t tid = pthread_self(); 172 | char str_tmp[MAX_CHAR_LEN]; 173 | //如果线程池不退出 174 | while (!thread->m_isQuit) 175 | { 176 | //执行任务 177 | CTaskBase* task = thread->GetTask(); 178 | if (task == nullptr) 179 | { 180 | memset(str_tmp, '\0', MAX_CHAR_LEN); 181 | sprintf(str_tmp, "任务获取出错, 线程[tid: %lu]无法执行该任务", tid); 182 | journal->ErrMsgWriteLog(str_tmp, true); 183 | break; 184 | } 185 | task->Run(); 186 | if (task != nullptr) 187 | { 188 | delete task; 189 | task = nullptr; 190 | } 191 | printf("[tid: %lu]线程任务执行完毕, 空闲\n", tid); 192 | } 193 | return (void*)0; 194 | } 195 | 196 | //= = = = = = = = = = = = = = = = = = = = 197 | // @函数名称: CreateThread() 198 | // @函数说明: 创建线程池中的线程 199 | // @参数说明: 无 200 | // @返回值: 无 201 | //= = = = = = = = = = = = = = = = = = = = 202 | int CThreadPool::CreateThread() 203 | { 204 | cout << "创建的最大线程数为: " << this->maxCount << endl; 205 | this->pthreadId = new pthread_t[this->maxCount]; 206 | for (int i = 0; i < maxCount; i++) 207 | { 208 | pthread_create(&pthreadId[i], NULL, ThreadFun, this); 209 | } 210 | return 0; 211 | } -------------------------------------------------------------------------------- /src/CThreadPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "CCond.h" 6 | #include "CTask.h" 7 | using namespace std; 8 | 9 | /* 10 | 线程池类 11 | */ 12 | class CThreadPool 13 | { 14 | public: 15 | CThreadPool(int maxCount); 16 | ~CThreadPool(); 17 | void AddTask(CTaskBase* pTask); //把任务添加到任务队列中 18 | int StopAll(); //退出所有的线程 19 | CTaskBase* GetTask(); //从任务池内得到一个任务 20 | int GetTaskSize(); //获取当前任务队列中的任务数 21 | 22 | protected: 23 | int CreateThread(); //创建线程池中的线程 24 | static void* ThreadFun(void* arg); //新线程的线程回调函数 25 | 26 | //未用到,未实现 27 | //static int MoveToIdle(pthread_t tid); //线程执行结束后,进入空闲线程 28 | //static int MoveToBusy(pthread_t tid); //移入到忙碌线程中 29 | 30 | private: 31 | int maxCount;//最大线程数 32 | CMutexLock* m_mutex;//线程同步锁 33 | CCond* m_cond;//线程状态条件变量 34 | bool m_isQuit;//判断退出标识符 35 | pthread_t* pthreadId; //线程ID 36 | vectorm_taskVec;//任务列表 37 | }; 38 | -------------------------------------------------------------------------------- /src/CTimer.cpp: -------------------------------------------------------------------------------- 1 | #include "CTimer.h" 2 | 3 | //返回值为毫秒 4 | time_value getNow() 5 | { 6 | //tv_usec微妙,tv_sec秒 7 | struct timeval tv; 8 | gettimeofday(&tv, NULL); 9 | return tv.tv_sec * 1000 + tv.tv_usec / 1000; 10 | } 11 | 12 | //加入时间计时器 13 | int CTimer::AddTimer(void* arg, time_value t) 14 | { 15 | timer_time_arg.insert(std::make_pair(t, arg)); 16 | timer_arg_time.insert(std::make_pair(arg, t)); 17 | return 0; 18 | } 19 | 20 | void* CTimer::GetTimer(time_value tnow) 21 | { 22 | std::multimap::iterator pos_time_arg = 23 | timer_time_arg.begin(); 24 | void* arg = pos_time_arg->second; 25 | 26 | if (pos_time_arg == timer_time_arg.end()) 27 | { 28 | return NULL; 29 | } 30 | 31 | if (pos_time_arg->first > tnow) 32 | { 33 | Show(); 34 | return NULL; 35 | } 36 | 37 | timer_time_arg.erase(pos_time_arg); 38 | 39 | std::multimap::iterator pos_arg_time; 40 | 41 | for (pos_arg_time = timer_arg_time.lower_bound(arg); 42 | pos_arg_time != timer_arg_time.upper_bound(arg); ++pos_arg_time) 43 | { 44 | if (pos_arg_time->second == pos_time_arg->first) 45 | { 46 | timer_arg_time.erase(pos_arg_time); 47 | Show(); 48 | return pos_time_arg->second; 49 | } 50 | } 51 | 52 | assert(0); 53 | Show(); 54 | return pos_time_arg->second; 55 | } 56 | void CTimer::Show() const 57 | { 58 | return; 59 | printf("arg_time %zu time_arg %zu \n", timer_arg_time.size(), 60 | timer_time_arg.size()); 61 | } 62 | 63 | void CTimer::RemoteTimer(void* arg) 64 | { 65 | std::multimap::iterator pos_arg_time; 66 | 67 | for (pos_arg_time = timer_arg_time.lower_bound(arg); 68 | pos_arg_time != timer_arg_time.upper_bound(arg);) 69 | { 70 | std::multimap::iterator pos_time_arg; 71 | time_value t = pos_arg_time->second; 72 | 73 | for (pos_time_arg = timer_time_arg.lower_bound(t); 74 | pos_time_arg != timer_time_arg.upper_bound(t);) 75 | { 76 | if (pos_time_arg->second == arg) 77 | { 78 | timer_time_arg.erase(pos_time_arg++); 79 | } 80 | else 81 | { 82 | pos_time_arg++; 83 | } 84 | } 85 | 86 | timer_arg_time.erase(pos_arg_time++); 87 | } 88 | 89 | Show(); 90 | } 91 | 92 | time_value CTimer::GetMinTimer() const 93 | { 94 | if (timer_time_arg.size() == 0) 95 | { 96 | return CTimer::min_timer; 97 | } 98 | 99 | time_value tnow = getNow(); 100 | std::multimap::const_iterator pos_time_arg = 101 | timer_time_arg.begin(); 102 | 103 | time_value t = tnow - pos_time_arg->first; 104 | 105 | if (t >= 0) 106 | { 107 | return 0; 108 | } 109 | return -t; 110 | } -------------------------------------------------------------------------------- /src/CTimer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //定义当前时间的数据类型 10 | typedef long time_value; 11 | 12 | //定义时间事件结构体 13 | struct timer_event 14 | { 15 | time_value times; 16 | void* arg; 17 | int event_type; 18 | }; 19 | 20 | time_value getNow(); 21 | 22 | class CTimer { 23 | static const int64_t min_timer = 1000 * 1; 24 | 25 | public: 26 | CTimer() {} 27 | 28 | virtual ~CTimer() {} 29 | 30 | int AddTimer(void*, time_value); 31 | 32 | void* GetTimer(time_value tnow); 33 | 34 | void RemoteTimer(void*); 35 | 36 | time_value GetMinTimer() const; 37 | 38 | int GetArgTimeSize() const { return (int)timer_arg_time.size(); } 39 | int GetTimeArgSize() const { return (int)timer_time_arg.size(); } 40 | 41 | void Show() const; 42 | 43 | private: 44 | std::multimap timer_arg_time; 45 | std::multimap timer_time_arg; 46 | }; 47 | -------------------------------------------------------------------------------- /src/CUserOpt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CDataBaseOpt.h" 3 | class CUserOpt : public CDataBaseOpt 4 | { 5 | public: 6 | //构造函数 7 | CUserOpt(const char* db_add, char* pKey) :CDataBaseOpt(db_add, pKey) 8 | { 9 | printf("数据库初始化完毕\n"); 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/CVideoInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "CVideoInfo.h" 2 | 3 | CVideoInfo::CVideoInfo() 4 | { 5 | } 6 | 7 | int CVideoInfo::GetVideoProgress(int user_id, char* video_id) 8 | { 9 | //对账号和密码进行加密 10 | AesEncryptor* aes = new AesEncryptor((unsigned char*)p_database->GetKey()); 11 | string en_id = aes->EncryptString(std::to_string(user_id)); 12 | string en_video_id = aes->EncryptString(video_id); 13 | delete aes; 14 | 15 | //sql语句太长可能会导致字符数组sql[]溢出, 从输入的用户名进行长度控制 16 | int res; 17 | char sql[255]; 18 | 19 | //可否查到此数据 20 | snprintf(sql, sizeof(sql), "SELECT currentFrame FROM videoTable WHERE id = '%s' AND uId = '%s';", 21 | en_video_id.c_str(), en_id.c_str()); 22 | char** dbResult; //是 char ** 类型,两个*号 23 | int nRow, nColumn; 24 | res = p_database->GetSqlValue(sql, dbResult, nRow, nColumn); 25 | if (res == true) 26 | { 27 | if (nRow != 0) 28 | { 29 | //res = CTool::char2int(dbResult[1]); 30 | return atoi(dbResult[1]); 31 | } 32 | else 33 | { 34 | //查无此数据 35 | return ANSWER_NAME_ERROR; 36 | } 37 | } 38 | else 39 | { 40 | journal->ErrMsgWriteLog("[数据库操作]查询帧数sql语句执行失败", true); 41 | return SQLOPT_ERROR; 42 | } 43 | } 44 | 45 | int CVideoInfo::DeleteVideoInfo(int user_id, char* video_id) 46 | { 47 | //对账号和密码进行加密 48 | AesEncryptor* aes = new AesEncryptor((unsigned char*)p_database->GetKey()); 49 | string en_id = aes->EncryptString(std::to_string(user_id)); 50 | string en_video_id = aes->EncryptString(video_id); 51 | delete aes; 52 | 53 | char sql[SQL_LEN]; 54 | //查询有无此包 55 | int res = this->GetVideoProgress(user_id, video_id); 56 | if (res == ANSWER_NAME_ERROR) 57 | { 58 | return ANSWER_NAME_ERROR; 59 | } 60 | snprintf(sql, sizeof(sql), "DELETE FROM videoTable WHERE id = '%s' AND uId = '%s';", 61 | en_video_id.c_str(), en_id.c_str()); 62 | res = p_database->SqlOpt(sql); 63 | if (res == false) 64 | { 65 | sprintf(sql, "[数据库操作]数据删除失败:视频ID[%s],用户ID[%d]", video_id, user_id); 66 | journal->ErrMsgWriteLog(sql); 67 | return SQLOPT_ERROR; 68 | } 69 | sprintf(sql, "[数据库操作]数据删除成功:视频ID[%s],用户ID[%d]", video_id, user_id); 70 | journal->WriteLog(sql); 71 | return SQLOPT_SUCCESS; 72 | } 73 | 74 | int CVideoInfo::InsertVideoInfo(int user_id, char* video_id, int frame_num) 75 | { 76 | //对账号和密码进行加密 77 | AesEncryptor* aes = new AesEncryptor((unsigned char*)p_database->GetKey()); 78 | string en_id = aes->EncryptString(std::to_string(user_id)); 79 | //string en_frame_num = aes->EncryptString(std::to_string(frame_num)); 80 | string en_video_id = aes->EncryptString(video_id); 81 | delete aes; 82 | 83 | char sql[SQL_LEN]; 84 | snprintf(sql, sizeof(sql), "INSERT INTO videoTable VALUES('%s', '%s', %d);", 85 | en_video_id.c_str(), en_id.c_str(), frame_num); 86 | int res = p_database->SqlOpt(sql); 87 | if (res == false) 88 | { 89 | sprintf(sql, "[数据库操作]数据插入失败:视频ID[%s],用户ID[%d],帧数[%d]", 90 | video_id, user_id, frame_num); 91 | journal->ErrMsgWriteLog(sql); 92 | return ANSWER_NAME_ERROR; 93 | } 94 | sprintf(sql, "[数据库操作]数据插入成功:视频ID[%s],用户ID[%d],帧数[%d]", video_id, user_id, frame_num); 95 | journal->WriteLog(sql); 96 | return SQLOPT_SUCCESS; 97 | } -------------------------------------------------------------------------------- /src/CVideoInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Packet.h" 3 | #include "global.h" 4 | #include "ctool.h" 5 | #include "CCipher.h" 6 | class CVideoInfo 7 | { 8 | public: 9 | CVideoInfo(); 10 | int GetVideoProgress(int user_id, char* video_id); 11 | int DeleteVideoInfo(int user_id, char* video_id); 12 | int InsertVideoInfo(int user_id, char* video_id, int frame_num); 13 | }; 14 | -------------------------------------------------------------------------------- /src/CXORencode.cpp: -------------------------------------------------------------------------------- 1 | #include "CXORencode.h" 2 | 3 | //len是明文的长度 4 | int CXORencode::XORencode(void* i_block, void* o_block, int key, int len) 5 | { 6 | int* p_src = (int*)i_block; 7 | int* p_dst = (int*)o_block; 8 | int i; 9 | long temp = len / sizeof(int); 10 | for (i = 0; i < temp; i++) 11 | { 12 | p_dst[i] = p_src[i] ^ key; 13 | } 14 | 15 | int j; 16 | char* pKey = (char*)&key; 17 | char* p8Src = (char*)&p_src[i]; 18 | char* p8Dst = (char*)&p_dst[i]; 19 | int temp2 = (int)(len % sizeof(int)); 20 | for (j = 0; j < temp2; j++) 21 | { 22 | p8Dst[j] = p8Src[j] ^ pKey[j]; 23 | } 24 | 25 | return 1; 26 | } -------------------------------------------------------------------------------- /src/CXORencode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class CXORencode 3 | { 4 | /*异或加密解密算法 5 | *i_block:输入数据 6 | *o_block:输出数据 7 | *key:密钥 8 | *len:输入数据长度 9 | *如果输入是明文,则输出是密文 10 | *如果输入是密文,则输出是明文 11 | */ 12 | int XORencode(void* i_block, void* o_block, int key, int len); 13 | }; 14 | -------------------------------------------------------------------------------- /src/FrontTcpServer.cpp: -------------------------------------------------------------------------------- 1 | #include "FrontTcpServer.h" 2 | 3 | //前置服务器 4 | TcpServer::TcpServer() :CEpollBase(DOC_GET_INT("server_set", "max_connectNum"), DOC_GET_INT("server_set", "max_threadNum")) 5 | { 6 | //参数数值初始化 7 | client_addr_len = sizeof(struct sockaddr_in); 8 | client_fd = 0; 9 | tcp_Task = nullptr; 10 | //设置相应的地址信息 11 | this->server_socket = new CServerSocket(); 12 | journal->WriteLog("[前置服务器]套接字设置完毕!"); 13 | 14 | //创建线程池 15 | thread_pool = new CThreadPool(DOC_GET_INT("server_set", "max_threadNum")); 16 | journal->WriteLog("[前置服务器]线程池创建完毕!"); 17 | 18 | //心跳包 19 | this->heart_beat = CSingleton::GetInstance().get(); 20 | journal->WriteLog("[前置服务器]心跳功能初始化完毕!"); 21 | 22 | //发送线程初始化 23 | this->send_Info = new CServerSend(this->thread_pool); 24 | journal->WriteLog("[发送监听线程]启动完毕!"); 25 | 26 | //套接字加入epoll,并进行监听 27 | journal->WriteLog("[前置服务器]正在等待客户端连接…"); 28 | this->AddEpoll(server_socket->GetsocketFd()); 29 | } 30 | 31 | TcpServer::~TcpServer() 32 | { 33 | delete thread_pool; 34 | thread_pool = nullptr; 35 | delete server_socket; 36 | server_socket = nullptr; 37 | } 38 | 39 | //= = = = = = = = = = = = = = = = = = = = 40 | // @函数名称: NewConnection(int clt_fd) 41 | // @函数说明: 纯虚函数实现, 收到新连接后的操作 42 | // @参数说明: 参数1: socket套接字标识符 43 | // @返回值: 无 44 | //= = = = = = = = = = = = = = = = = = = = 45 | void TcpServer::NewConnection(int clt_fd) 46 | { 47 | //accpet 返回已连接套接字 48 | client_fd = accept(clt_fd, (struct sockaddr*)&client_addr, &client_addr_len); 49 | if (client_fd == -1) 50 | { 51 | journal->ErrMsgWriteLog("[前置服务器]accept函数接受新客户端出错"); 52 | return; 53 | } 54 | //将连接的客户端网络添加到epoll中 55 | DoEvent(client_fd, EPOLL_CTL_ADD, EPOLLIN | EPOLLET); 56 | 57 | //讲套接字加入fd链表中 58 | all_fd.push_back(client_fd); 59 | char str_temp[256] = { '\0' }; 60 | sprintf(str_temp, "[前置服务器]客户端%s:%d, 连接成功!加入套接字地址池", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); 61 | journal->WriteLog(str_temp); 62 | 63 | //执行心跳操作 64 | heart_beat->SetTcpKeepAlive(client_fd); 65 | 66 | //超时设置 67 | heart_beat->ReSendAndRecvPack(client_fd, 100); 68 | } 69 | 70 | //= = = = = = = = = = = = = = = = = = = = 71 | // @函数名称: exitsConnection(long socket_fd) 72 | // @函数说明: 纯虚函数实现, 处理已经存在的连接 73 | // @参数说明: 参数1: socket套接字标识符 74 | // @返回值: 无 75 | //= = = = = = = = = = = = = = = = = = = = 76 | void TcpServer::ExitsConnection(int socket_fd_num, unsigned int* pack_num) 77 | { 78 | tcp_Task = new CFrontTask(all_fd, socket_fd_num, pack_num); 79 | //加入任务队列 80 | thread_pool->AddTask(tcp_Task); 81 | } -------------------------------------------------------------------------------- /src/FrontTcpServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "CEpollBase.h" 8 | #include "CThreadPool.h" 9 | #include "CFrontTask.h" 10 | #include "CSocket.h" 11 | #include "CServerSend.h" 12 | #include "Packet.h" 13 | #include "global.h" 14 | 15 | //前置服务器 16 | class TcpServer : public CEpollBase 17 | { 18 | public: 19 | //构造函数 20 | TcpServer(); //前置服务器 21 | 22 | //析构函数 23 | ~TcpServer(); 24 | 25 | //处理新连接 26 | void NewConnection(int clt_fd); 27 | 28 | //处理已经存在的连接 29 | void ExitsConnection(int socket_fd_num, unsigned int* pack_num); 30 | 31 | private: 32 | CFrontTask* tcp_Task; 33 | 34 | private: 35 | 36 | struct sockaddr_in client_addr; //客户端套接字地址 37 | socklen_t client_addr_len; //客户端套接字地址长度 38 | int client_fd; //客户端套接字地址索引 39 | int* pack_num; //记录包号 40 | CHeartbeat* heart_beat; //心跳包 41 | CThreadPool* thread_pool; //线程池类指针 42 | CServerSocket* server_socket; //服务器套接字类指针 43 | CServerSend* send_Info; //向客户端发送信息指针 44 | }; -------------------------------------------------------------------------------- /src/Packet.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKET_H 2 | #define PACKET_H 3 | /* 4 | ////////////////////////////////////////////////////// 5 | 不完全的总结 6 | 1.客户端要发送的包头类型包: 7 | 登陆包、注册包、视频包、请求获取视频帧数包、文件片有包、文件片无包 8 | 9 | 2.客户端要接收的包头类型有: 10 | 包头类型(packet_type):响应包 11 | 包体数值(anser_type):(登陆响应包、注册响应包、视频响应包、文件响应包) 12 | 包体数值(anser_type):(登陆重发包、注册重发包、视频重发包、文件重发包) 13 | 包头类型(packet_type):视频帧数包 14 | 包体数值:视频id,用户id,视频帧数 15 | 3.发送的结构体都要有包头, 接收的结构体不要有包头,请自行修改 16 | 4.CRC校验码,函数输入可以直接拿 接收包体的结构体,包头.包大小 生成 17 | 18 | ////////////////////////////////////////////////////// 19 | 文件业务说明: 20 | 前置添加说明: 21 | 1.添加结构体 22 | //文件包 23 | typedef struct t_PackHead_firstfilepack 24 | { 25 | t_PackHead head; //包头 26 | char file_name[16]; //文件名 27 | int user_id; //用户主键ID 28 | int fileSize; //文件尺寸 29 | char md5[32]; //MD5校验码 30 | }t_FirstFilePack; 31 | 32 | 2.添加宏定义 33 | #define FILE_OK 10243 34 | #define FILE_START 10244 35 | #define DONT_START 10245 36 | #define MD5_ERROR 10246 37 | #define ReqFile 1025 //包头类型 38 | 39 | 客户端: 40 | 1.生成图片文件 41 | 2.根据Packet.h,规定的文件大小,进行分割 42 | 3.往服务器发送t_FirstFilePack,等待接收响应包 43 | 数据为FILE_START, 则进行下一步 44 | 数据为DONT_START, 则弹出提示,服务器目前无法上传 45 | 46 | 4.开始往客户端发包t_FilePack,首包的起始标记包标号记为0 47 | 5.循环发包, 发完包后等待接收包, 48 | 6.接收到请求文件重发包, 根据包号发送相对应的临时文件 49 | 7.接收到为响应包类型为FILE_OK的包, 则弹出上传成功 50 | 接收到MD5_ERROR, 则弹出文件上传校验失败提示 51 | 8.删除临时文件,结束线程任务 52 | 9.定时内未收到包,结束线程,不删除临时文件 53 | 注:如果在线程外收到文件响应包, 向服务器发送t_FilePack结构体包, 54 | int类型数据记为user_id, char数组记为文件名, 包头为ReqFile 55 | 服务器会向客户端发t_VideoInfo结构体包, 56 | int user_id; //用户ID 57 | char video_id[16]; //文件名称 58 | int current_frame; //请求的包号 59 | 包头为ReqFile 60 | 根据信息调取对应的临时文件 61 | ////////////////////////////////////////////////////// 62 | 63 | */ 64 | //基本功能包头类型信息 65 | #define LOGIN 101 //登陆 66 | #define REGISTER 102 //注册 67 | #define GET_PREGRORESS 103 //获取当前帧数包 68 | #define REQUIRE_PREPGRORESS 104 //请求获取帧数包 69 | #define INSERT_VIDEO_INFO 105 //插入视频信息包 70 | #define DELETE_VIDEO_INFO 106 //删除视频 71 | #define FILE_FIRST_PACK 107 //定义文件的第一个包 72 | #define FILE_SEG_EXIST 108 //定义文件分片的包,且包后还有包--记为片有 73 | #define FILE_SEG_NULL 109 //定义文件分片的包,且包后没有包--记为片无 74 | 75 | //基本功能包头类型信息 76 | #define LOGIN 101 //登陆 77 | #define REGISTER 102 //注册 78 | #define GET_PREGRORESS 103 //获取当前帧数包 79 | #define REQUIRE_PREPGRORESS 104 //请求获取帧数包 80 | #define INSERT_VIDEO_INFO 105 //插入视频信息包 81 | #define DELETE_VIDEO_INFO 106 //删除视频 82 | #define FILE_FIRST_PACK 107 //定义文件的第一个包 83 | #define FILE_SEG_EXIST 108 //定义文件分片的包,且包后还有包--记为片有 84 | #define FILE_SEG_NULL 109 //定义文件分片的包,且包后没有包--记为片无 85 | 86 | //应答包包头信息 87 | #define ANSWER 1003 //响应包--包头信息 88 | #define LOGIN_ANSWER 100301 //登陆响应包 89 | #define REG_ANSWER 100302 //注册响应包 90 | #define SELECT_VIDEO_ANSWER 100303 //查询视频响应包 91 | #define DELETE_VIDEO_ANSWER 100304 //删除视频回应包 92 | #define INSERT_VIDEO_ANSWER 100305 //插入视频响应包 93 | #define FILE_ANSWER 100306 //文件回答 94 | //应答包包体信息(一) 95 | #define ANSWER_RESEND 10031 //响应重发包 96 | #define ANSWER_LOGIN_SUCCESS 10032 //应答包回复登录成功 97 | #define ANSWER_REG_SUCCESS 10033 //应答包回复注册成功 98 | #define ANSWER_INSERT_SUCCESS 10034 //应答包回复插入视频信息成功 99 | #define ANSWER_DELETE_SUCCESS 10035 //应答包回复删除视频 100 | #define ANSWER_FILE_START 10036 //应答包回复开始上传文件 101 | #define ANSWER_FILE_SUCCESS 10037 //应答包回复上传文件成功 102 | //应答包包体信息(二) 103 | #define ANSWER_NAME_ERROR -10031 //应答包回复名字错误 104 | #define ANSWER_KEY_ERROR -10032 //应答包回复密码错误 105 | #define ANSWER_DELETE_ERROR -10033 //应答包删除视频错误 106 | #define ANSWER_QUERY_ERROR -10034 //应答包回复查无视频信息 107 | #define ANSWER_INSERT_ERROR -10035 //应答包回复插入视频信息错误 108 | #define ANSWER_FILE_START_ERROR -10036//应答包因为服务发生错误,[别上传] 109 | #define ANSWER_FILE_ERROR -10037 //应答包因为服务发生错误,上传失败 110 | #define ANSWER_MD5_ERROR -10038 //应答包回复上传文件MD5错误 111 | 112 | //重发包包头类型信息--CRC校验码出错 113 | #define CRC_ERR_RESEND 1004 //重发包--包头类型 114 | //重发包包体类型信息 115 | #define RESEND_LOGIN 10041 //登陆重发包 116 | #define RESEND_REGISTER 10042 //注册重发包 117 | #define RESEND_GET_PREGRORESS 10043 //获取当前帧数包重发包 118 | #define RESEND_REQUIRE_PREPGRORESS 10044 //请求获取帧数包重发包 119 | #define RESEND_INSERT 10045 //插入视频信息包重发包 120 | #define RESEND_DELETE 10046 //删除视频重发包 121 | #define RESEND_FILE_FIRST_PACK 10047 //定义文件的第一个包 122 | #define RESEND_FILE_SEG_EXIST 10048 //定义文件分片的包,且包后还有包--记为片有 123 | #define RESEND_FILE_SEG_NULL 100419 //请求重发片有文件包(CRC校验出错) 124 | 125 | //文件重发包包头类型信息 126 | #define FILE_RESEND 1005 //请求重发文件包(没有收到指定文件) 127 | 128 | //相关参数宏定义 129 | #define MAX_CHAR_LEN 256 //char数组最长大小设置 130 | #define PACK_MAX_LEN 1500 //数据包包体的最长长度 131 | #define FILE_LEN 1024 //定义传输的文件的最长长度 132 | #define SQL_LEN 255 //定义数据库数组的长度字段 133 | #define SQLOPT_SUCCESS 1233 //数据库操作成功 134 | #define SQLOPT_ERROR -1233 //定义sql语句操作出错 135 | #define RollBack 852 //进行回退操作 136 | #define MAX_PATH_LEN 512 //最大路径长度 137 | /* 138 | 发送文件思路: 139 | 1. 如果是最后一片, 包头类型设为片无, 否则设为片有 140 | 2. 包头大小设为文件具体的大小,最后一个包不一定是1024长度 141 | 3. 流水号为每一片的编号 142 | 4. CRC校验码设置 143 | 5. 包体里面写入数据 144 | */ 145 | 146 | //包头 147 | typedef struct t_PackHead_head 148 | { 149 | int packet_type; //包类型 150 | int packet_size; //包大小--包含包头+包体 151 | int packet_CRC; //CRC校验码 152 | int packet_num; //定义包的编号 153 | }t_PackHead; 154 | 155 | //暂定的方法: 156 | //1.接收包的结构体, 接收包后,利用字符串数组存储(recv) 157 | //2.然后强转成包头结构体(memcpy) 158 | //3.接着利用包头的结构体的类型来判断收到什么包(switch) 159 | //4.然后将整个字符串数组内存拷贝成对应的包(memcpy) 160 | 161 | //登录包 1003 162 | typedef struct t_PackHead_log 163 | { 164 | int user_id; //用户账号 165 | char pwd[16]; //密码 166 | }t_Login; 167 | 168 | //注册包 169 | typedef struct t_PackHead_reg 170 | { 171 | int user_id; //用户账号 172 | char name[16]; //用户名 173 | char pwd[16]; //用户密码 174 | }t_Register; 175 | 176 | //应答包 177 | typedef struct t_PackHead_answer 178 | { 179 | t_PackHead head; //包头 180 | int anser_type; //应答包的类型 181 | }t_Answer; 182 | 183 | /* 184 | //登陆后,客户端遍历数据库的视频, 分页等(利用二阶段的代码, 可以全部白嫖)。 185 | 点击视频的时候,判断能不能打开, 186 | 能打开,向服务器申请获取视频当前帧数判断与本地帧数是否相同 187 | 相同,播放视频 188 | 不相同,弹出窗口,让客户判断是以本地还是以服务器为准 189 | 不能打开,弹出窗口告知用户,向服务器发送删除该段视频信息包,本地删除该信息 190 | */ 191 | 192 | //请求获取视频当前帧数---请求删除当前视频信息(根据包头的类型而定) 193 | typedef struct t_PackHead_requireprogress 194 | { 195 | int user_id; //用户编号 196 | char video_id[20]; //视频编号 197 | }t_RequireProgress; 198 | 199 | //插入视频信息包 200 | typedef struct t_PackHead_videoInfo 201 | { 202 | int user_id; //用户ID 203 | int current_frame; //视频当前帧数 204 | char video_id[20]; //视频ID 205 | }t_VideoInfo; 206 | 207 | //获取视频当前帧数 208 | typedef struct t_PackHead_getprogress 209 | { 210 | t_PackHead head; //包头 211 | int video_progress; //视频当前帧数 212 | int user_id; //用户编号 213 | char video_id[20]; //视频编号 214 | }t_GetProgress; 215 | 216 | //文件包 217 | typedef struct t_PackHead_filepack 218 | { 219 | t_PackHead head; //包头 220 | int packer_num; //当前包的流水号 221 | int user_id; //用户主键ID 222 | char file_name[20]; //文件名 223 | char data[FILE_LEN]; //文件大小 224 | }t_FilePack; 225 | 226 | //文件包 227 | typedef struct t_PackHead_firstfilepack 228 | { 229 | int user_id; //用户主键ID 230 | int fileSize; //文件大小 231 | char file_name[20]; //文件名 232 | char md5[128]; //MD5校验码 233 | }t_FirstFilePack; 234 | 235 | #endif -------------------------------------------------------------------------------- /src/aes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "string.h" 3 | 4 | class AES 5 | { 6 | public: 7 | AES(unsigned char* key); 8 | virtual ~AES(); 9 | unsigned char* Cipher(unsigned char* input);// 加密,传入的数组大小必须是16字节 10 | unsigned char* InvCipher(unsigned char* input);// 解密,传入的数组也必须是16字节 11 | void* Cipher(void* input, int length = 0);// 可以传入数组,大小必须是16的整数倍,如果不是将会越界操作;如果不传length而默认为0,那么将按照字符串处理,遇'\0'结束 12 | void* InvCipher(void* input, int length);// 必须传入数组和大小,必须是16的整数倍 13 | 14 | private: 15 | unsigned char Sbox[256]; 16 | unsigned char InvSbox[256]; 17 | unsigned char w[11][4][4]; 18 | 19 | void KeyExpansion(unsigned char* key, unsigned char w[][4][4]); 20 | unsigned char FFmul(unsigned char a, unsigned char b); 21 | 22 | void SubBytes(unsigned char state[][4]); 23 | void ShiftRows(unsigned char state[][4]); 24 | void MixColumns(unsigned char state[][4]); 25 | void AddRoundKey(unsigned char state[][4], unsigned char k[][4]); 26 | 27 | void InvSubBytes(unsigned char state[][4]); 28 | void InvShiftRows(unsigned char state[][4]); 29 | void InvMixColumns(unsigned char state[][4]); 30 | }; -------------------------------------------------------------------------------- /src/ctool.cpp: -------------------------------------------------------------------------------- 1 | #include "ctool.h" 2 | #include 3 | #include 4 | 5 | /************************************ 6 | 函数说明:初始化构造函数,无需使用 7 | 函数输入:无 8 | 函数输出:无 9 | *************************************/ 10 | CTool::CTool() 11 | { 12 | } 13 | 14 | /********************************************** 15 | 函数功能:判断所输入的字符串是否是中英文字符 16 | 函数输入:字符串 17 | 函数输出:bool, 是则输出true, 不是则输出为false 18 | 函数名称:judgeCNorEN(string& str) 19 | **********************************************/ 20 | bool CTool::judgeCNorEN(string str) 21 | { 22 | //基本思想: 输入一串字符串,如果是中英文字符,则删除, 最后长度为0,则返回true 23 | //utf-8情况下一个中文字符占3位 24 | 25 | int len = (int)str.length();//字符串长度 26 | int i = 0; //遍历的变量 27 | int num = 0; //记录删除的字符数 28 | char key, key2; //记录字符的信息 29 | string word; //判断一个字符 30 | 31 | //先匹配中文字符的个数 32 | while (i < len) 33 | { 34 | key = str.c_str()[i]; 35 | key2 = str.c_str()[i + 1]; 36 | //判断是否是中文字符 37 | if ((unsigned char)key >= 0Xa1 && (unsigned char)key2 <= 0XFE) 38 | { 39 | if ((unsigned char)key >= 0Xa1 && (unsigned char)key2 <= 0XFE) 40 | { 41 | num += 3; //记录字符数为2 42 | } 43 | } 44 | i = i + 3; 45 | } 46 | 47 | //在查询所有的英文字符的个数 48 | i = 0; 49 | while (i < len) 50 | { 51 | if ((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z')) 52 | { 53 | num++; 54 | } 55 | i++; 56 | } 57 | 58 | //相等则为true, 否则返回false 59 | return (len == num); 60 | } 61 | 62 | /******************************************** 63 | 函数说明:char类型转成int类型 64 | 函数输入:const char*类型字符串(可直接赋值) 65 | 函数输出:int类型 66 | *********************************************/ 67 | int CTool::char2int(const char* str) 68 | { 69 | const char* p = str; 70 | int res = 0; 71 | if (*str == '-' || *str == '+') 72 | { 73 | str++; 74 | } 75 | 76 | //循环转换 77 | while (*str != 0) 78 | { 79 | if (*str < '0' || *str > '9') 80 | { 81 | break; 82 | } 83 | res = res * 10 + *str - '0'; 84 | str++; 85 | } 86 | 87 | if (*p == '-') 88 | { 89 | res = -res; 90 | } 91 | return res; 92 | } 93 | 94 | int32_t CTool::TimerStart(uint64_t interval_ms) 95 | { 96 | { 97 | int32_t timerfd = 0; 98 | struct itimerspec its = { 0 }; 99 | struct itimerspec itsTest = { 0 }; 100 | 101 | timerfd = timerfd_create(CLOCK_MONOTONIC, 0); 102 | if (timerfd < 0) 103 | { 104 | return -1; 105 | } 106 | 107 | /* Start the timer */ 108 | its.it_value.tv_sec = interval_ms / 1000; 109 | its.it_value.tv_nsec = (interval_ms % 1000) * 1000000; 110 | its.it_interval = its.it_value; 111 | 112 | // if (timerfd_settime(timerfd, 0, &its, NULL) < 0) 113 | if (timerfd_settime(timerfd, TFD_TIMER_ABSTIME, &its, NULL) < 0) 114 | { 115 | close(timerfd); 116 | return -1; 117 | } 118 | return timerfd; 119 | } 120 | } -------------------------------------------------------------------------------- /src/ctool.h: -------------------------------------------------------------------------------- 1 | #ifndef CTOOL_H 2 | #define CTOOL_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "global.h" 9 | using namespace std; 10 | 11 | class CTool 12 | { 13 | public: 14 | CTool(); 15 | static bool judgeCNorEN(string str); //判断是否只包含中文和英文 16 | static int char2int(const char* str); //char*转int 17 | static int32_t TimerStart(uint64_t interval_ms);//创建定时器 18 | }; 19 | 20 | template 21 | //获取字符串数组的长度 22 | int getArrayLen(T& array) 23 | { 24 | return (sizeof(array) / sizeof(array[0] - 1)); // 存储字符串的字符数组末尾有一个'\0'字符,需要去掉它 25 | } 26 | 27 | #endif // CTOOL_H 28 | -------------------------------------------------------------------------------- /src/global.cpp: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | //初始化Json文件 3 | CServerJson* p_cserver_config = CSingleton::GetInstance("./config/serverConfig.json").get(); 4 | 5 | //初始化日志文件 6 | CLogger* journal = new CLogger(DOC_GET_STR("journal", "path")); 7 | 8 | //前段往后端共享内存初始化 9 | CShareMemory* f2b_share_memory = new CShareMemory( 10 | DOC_GET_INT("share_memory", "front_key"), DOC_GET_INT("share_memory", "block_size"), DOC_GET_INT("share_memory", "block_num")); 11 | 12 | //后端发往前段共享内存初始化 13 | CShareMemory* b2f_share_memory = new CShareMemory( 14 | DOC_GET_INT("share_memory", "back_key"), DOC_GET_INT("share_memory", "block_size"), DOC_GET_INT("share_memory", "block_num")); 15 | 16 | //消息队列初始化 17 | CMsgQueue* f2b_msg_queue = new CMsgQueue(DOC_GET_INT("msg_queue", "front_msg_key")); 18 | CMsgQueue* b2f_msg_queue = new CMsgQueue(DOC_GET_INT("msg_queue", "back_msg_key")); 19 | int msg_len = sizeof(msg_t) - sizeof(long); //消息队列的长度 20 | 21 | //数据库操作 22 | CUserOpt* p_database = new CUserOpt(DOC_GET_STR("db_info", "db_address"), "11111"); 23 | 24 | const unsigned char auchCRCHi[] = { 25 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 26 | 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 27 | 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 28 | 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 29 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 30 | 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 31 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 32 | 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 33 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 34 | 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 35 | 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 36 | 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 37 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 38 | 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 39 | 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 40 | 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 41 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 42 | 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 43 | 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 44 | 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 45 | 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 46 | 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 47 | 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 48 | 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 49 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 50 | 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 51 | }; 52 | 53 | extern const unsigned char auchCRCLo[] = { 54 | 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 55 | 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 56 | 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 57 | 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 58 | 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 59 | 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 60 | 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 61 | 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 62 | 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 63 | 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 64 | 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 65 | 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 66 | 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 67 | 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 68 | 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 69 | 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 70 | 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 71 | 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 72 | 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 73 | 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 74 | 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 75 | 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 76 | 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 77 | 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 78 | 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 79 | 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 80 | }; -------------------------------------------------------------------------------- /src/global.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CLogger.h" 3 | #include "CServerJson.h" 4 | #include "CShareMemory.h" 5 | #include "CMsgQueue.h" 6 | #include "CUserOpt.h" 7 | #include "global.h" 8 | 9 | #define DOC(X) p_cserver_config->doc[X] 10 | #define DOC_GET_INT(X,Y) p_cserver_config->doc[X][Y].GetInt() 11 | #define DOC_GET_STR(X,Y) p_cserver_config->doc[X][Y].GetString() 12 | 13 | //消息结构体 14 | typedef struct msg 15 | { 16 | long m_type; //定义消息来源, 前段为1, 后端为2 17 | int fun_typ; //定义功能的类型 18 | int index; //定义获取的索引地址信息 19 | int socketFd; //套接字标识符 20 | }msg_t; 21 | 22 | extern CServerJson* p_cserver_config; 23 | extern CLogger* journal; 24 | 25 | extern CShareMemory* f2b_share_memory; //前段发往后端共享内存 26 | extern CShareMemory* b2f_share_memory; //前段发往后端共享内存 27 | 28 | extern CMsgQueue* f2b_msg_queue; //前段发往后端消息队列 29 | extern CMsgQueue* b2f_msg_queue; //后端发往前段消息队列 30 | 31 | extern int msg_len; //消息队列的长度 32 | extern int b2f_msg_len; //消息队列的长度 33 | 34 | extern CUserOpt* p_database; //数据库操作 35 | /************************************************** 36 | * CRC 高位字节值表 37 | **************************************************/ 38 | extern const unsigned char auchCRCHi[]; 39 | /************************************************** 40 | * CRC 低位字节值表 41 | **************************************************/ 42 | extern const unsigned char auchCRCLo[]; -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "FrontTcpServer.h" 2 | #include "BackEndServer.h" 3 | #include "global.h" 4 | #include "CSendTask.h" 5 | #include "CCipher.h" 6 | 7 | void SetKey(char* src_key, char* des_key) 8 | { 9 | AesEncryptor* aes = nullptr; 10 | string des; 11 | int i = 5; 12 | //对密码进行加密 13 | aes = new AesEncryptor((unsigned char*)src_key); 14 | des = aes->EncryptString(src_key); 15 | //设置秘密 16 | if (p_database->ReSetKey((char*)des.c_str()) == false) 17 | { 18 | perror("重设密码失败, 请检查"); 19 | system("pause"); 20 | exit(-1); 21 | } 22 | delete aes; 23 | } 24 | 25 | void checkInfo(const char* info, char* db_key) 26 | { 27 | AesEncryptor* aes = nullptr; 28 | string des; 29 | int i = 5; 30 | while (i--) 31 | { 32 | if (i == 0) 33 | { 34 | cout << "========== ========== ========== ==========" << endl; 35 | cout << " 输入错误次数太多,再见 " << endl; 36 | cout << "========== ========== ========== ==========" << endl; 37 | exit(-1); 38 | } 39 | cout << info; 40 | cin >> db_key; 41 | //对密码进行加密 42 | aes = new AesEncryptor((unsigned char*)db_key); 43 | des = aes->EncryptString(db_key); 44 | //判断密码是否正确 45 | if (p_database->checkKey((char*)des.c_str()) == false) 46 | { 47 | cout << "[Warning]密码输入错误, 请重试!" << endl; 48 | cin.clear(); 49 | delete aes; 50 | continue; 51 | } 52 | delete aes; 53 | break; 54 | } 55 | } 56 | 57 | int main() 58 | { 59 | int i_function; 60 | pid_t fpid; 61 | char* des_key = nullptr; 62 | char* db_key = new (char); 63 | cout << "========== ========== ========== ==========" << endl; 64 | cout << " 欢迎使用 " << endl; 65 | cout << " 随时翻车服务器 " << endl; 66 | cout << "========== ========== ========== ==========" << endl; 67 | 68 | while (true) 69 | { 70 | cin.clear(); 71 | cout << "请选择服务器功能(1.打开服务器, 2.更改数据库密码, 其余按键退出):"; 72 | cin >> i_function; 73 | switch (i_function) 74 | { 75 | case 1: 76 | checkInfo("请输入密码(初始密码123456):", db_key); 77 | //开辟进程 78 | fpid = fork(); 79 | if (fpid < 0) 80 | { 81 | journal->ErrMsgWriteLog("进程开启失败"); 82 | } 83 | //前置服务器 84 | else if (fpid == 0) 85 | { 86 | //写入日志文件临时变量 87 | journal->WriteLog("前置服务器,启动中……"); 88 | TcpServer* my_Server = new TcpServer(); 89 | } 90 | //后置服务器 91 | else 92 | { 93 | //写入日志文件临时变量 94 | journal->WriteLog("后置服务器,启动中……"); 95 | BackEndServer* back_Server = new BackEndServer(); 96 | } 97 | journal->~CLogger(); 98 | break; 99 | case 2: 100 | cout << "请注意! 现阶段更改密码, 原先数据库的数据将全部无法读取!请谨慎操作!" << endl; 101 | cout << "请注意! 现阶段更改密码, 原先数据库的数据将全部无法读取!请谨慎操作!" << endl; 102 | cout << "[确认]请输入1, [返回]任意键" << endl; 103 | cin >> i_function; 104 | if (i_function != 1) 105 | { 106 | continue; 107 | } 108 | checkInfo("请输入原密码(初始密码123456):", db_key); 109 | cout << "请输入新密码:"; 110 | cin >> db_key; 111 | des_key = new (char); 112 | SetKey(db_key, des_key); 113 | break; 114 | default: 115 | system("pause"); 116 | exit(0); 117 | break; 118 | } 119 | } 120 | return 0; 121 | } -------------------------------------------------------------------------------- /src/md5.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (C) 2000 by Robert Hubley. * 3 | * All rights reserved. * 4 | * * 5 | * This software is provided ``AS IS'' and any express or implied * 6 | * warranties, including, but not limited to, the implied warranties of * 7 | * merchantability and fitness for a particular purpose, are disclaimed. * 8 | * In no event shall the authors be liable for any direct, indirect, * 9 | * incidental, special, exemplary, or consequential damages (including, but * 10 | * not limited to, procurement of substitute goods or services; loss of use, * 11 | * data, or profits; or business interruption) however caused and on any * 12 | * theory of liability, whether in contract, strict liability, or tort * 13 | * (including negligence or otherwise) arising in any way out of the use of * 14 | * this software, even if advised of the possibility of such damage. * 15 | * * 16 | ****************************************************************************** 17 | 18 | MD5.H - header file for MD5C.C 19 | 20 | Port to Win32 DLL by Robert Hubley 1/5/2000 21 | 22 | Original Copyright: 23 | 24 | Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 25 | rights reserved. 26 | 27 | License to copy and use this software is granted provided that it 28 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 29 | Algorithm" in all material mentioning or referencing this software 30 | or this function. 31 | 32 | License is also granted to make and use derivative works provided 33 | that such works are identified as "derived from the RSA Data 34 | Security, Inc. MD5 Message-Digest Algorithm" in all material 35 | mentioning or referencing the derived work. 36 | 37 | RSA Data Security, Inc. makes no representations concerning either 38 | the merchantability of this software or the suitability of this 39 | software for any particular purpose. It is provided "as is" 40 | without express or implied warranty of any kind. 41 | 42 | These notices must be retained in any copies of any part of this 43 | documentation and/or software. 44 | */ 45 | /****************************************************************************** 46 | * Copyright (C) 2000 by Robert Hubley. * 47 | * All rights reserved. * 48 | * * 49 | * This software is provided ``AS IS'' and any express or implied * 50 | * warranties, including, but not limited to, the implied warranties of * 51 | * merchantability and fitness for a particular purpose, are disclaimed. * 52 | * In no event shall the authors be liable for any direct, indirect, * 53 | * incidental, special, exemplary, or consequential damages (including, but * 54 | * not limited to, procurement of substitute goods or services; loss of use, * 55 | * data, or profits; or business interruption) however caused and on any * 56 | * theory of liability, whether in contract, strict liability, or tort * 57 | * (including negligence or otherwise) arising in any way out of the use of * 58 | * this software, even if advised of the possibility of such damage. * 59 | * * 60 | ****************************************************************************** 61 | */ 62 | 63 | /****************************************************************************** 64 | * 2002-4-18 Modified by Liguangyi. * 65 | * struct MD5_CTX ==> class MD5_CTX. * 66 | * Take off the Globals Functions * 67 | ****************************************************************************** 68 | */ 69 | 70 | #ifndef _LGY_MD5_H 71 | #define _LGY_MD5_H 72 | 73 | /* MD5 Class. */ 74 | class MD5_CTX { 75 | public: 76 | MD5_CTX(); 77 | virtual ~MD5_CTX(); 78 | bool GetFileMd5(char* pMd5, const char* pFileName); 79 | private: 80 | 81 | unsigned long int state[4]; /* state (ABCD) */ 82 | unsigned long int count[2]; /* number of bits, modulo 2^64 (lsb first) */ 83 | unsigned char buffer[64]; /* input buffer */ 84 | unsigned char PADDING[64]; /* What? */ 85 | 86 | private: 87 | void MD5Init(); 88 | void MD5Update(unsigned char* input, unsigned int inputLen); 89 | void MD5Final(unsigned char digest[16]); 90 | void MD5Transform(unsigned long int state[4], unsigned char block[64]); 91 | void MD5_memcpy(unsigned char* output, unsigned char* input, unsigned int len); 92 | void Encode(unsigned char* output, unsigned long int* input, unsigned int len); 93 | void Decode(unsigned long int* output, unsigned char* input, unsigned int len); 94 | void MD5_memset(unsigned char* output, int value, unsigned int len); 95 | }; 96 | 97 | #endif -------------------------------------------------------------------------------- /src/phase3.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30717.126 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phase3", "phase3.vcxproj", "{6269D1E5-258A-461F-8674-CF555DBDB724}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|ARM = Release|ARM 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|ARM.ActiveCfg = Debug|ARM 21 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|ARM.Build.0 = Debug|ARM 22 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|ARM.Deploy.0 = Debug|ARM 23 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|ARM64.ActiveCfg = Debug|ARM64 24 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|ARM64.Build.0 = Debug|ARM64 25 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|ARM64.Deploy.0 = Debug|ARM64 26 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|x64.ActiveCfg = Debug|x64 27 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|x64.Build.0 = Debug|x64 28 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|x64.Deploy.0 = Debug|x64 29 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|x86.ActiveCfg = Debug|x86 30 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|x86.Build.0 = Debug|x86 31 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Debug|x86.Deploy.0 = Debug|x86 32 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|ARM.ActiveCfg = Release|ARM 33 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|ARM.Build.0 = Release|ARM 34 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|ARM.Deploy.0 = Release|ARM 35 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|ARM64.ActiveCfg = Release|ARM64 36 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|ARM64.Build.0 = Release|ARM64 37 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|ARM64.Deploy.0 = Release|ARM64 38 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|x64.ActiveCfg = Release|x64 39 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|x64.Build.0 = Release|x64 40 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|x64.Deploy.0 = Release|x64 41 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|x86.ActiveCfg = Release|x86 42 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|x86.Build.0 = Release|x86 43 | {6269D1E5-258A-461F-8674-CF555DBDB724}.Release|x86.Deploy.0 = Release|x86 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {715F82C3-A042-43FF-A5E7-F5AB4AF1BA05} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /src/phase3.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/rapidjson/cursorstreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_CURSORSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | 20 | #if defined(__GNUC__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | 25 | #if defined(_MSC_VER) && _MSC_VER <= 1800 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(4702) // unreachable code 28 | RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated 29 | #endif 30 | 31 | RAPIDJSON_NAMESPACE_BEGIN 32 | 33 | //! Cursor stream wrapper for counting line and column number if error exists. 34 | /*! 35 | \tparam InputStream Any stream that implements Stream Concept 36 | */ 37 | template > 38 | class CursorStreamWrapper : public GenericStreamWrapper { 39 | public: 40 | typedef typename Encoding::Ch Ch; 41 | 42 | CursorStreamWrapper(InputStream& is) : 43 | GenericStreamWrapper(is), line_(1), col_(0) {} 44 | 45 | // counting line and column number 46 | Ch Take() { 47 | Ch ch = this->is_.Take(); 48 | if (ch == '\n') { 49 | line_++; 50 | col_ = 0; 51 | } 52 | else { 53 | col_++; 54 | } 55 | return ch; 56 | } 57 | 58 | //! Get the error line number, if error exists. 59 | size_t GetLine() const { return line_; } 60 | //! Get the error column number, if error exists. 61 | size_t GetColumn() const { return col_; } 62 | 63 | private: 64 | size_t line_; //!< Current Line 65 | size_t col_; //!< Current Column 66 | }; 67 | 68 | #if defined(_MSC_VER) && _MSC_VER <= 1800 69 | RAPIDJSON_DIAG_POP 70 | #endif 71 | 72 | #if defined(__GNUC__) 73 | RAPIDJSON_DIAG_POP 74 | #endif 75 | 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ 79 | -------------------------------------------------------------------------------- /src/rapidjson/error/en.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_EN_H_ 16 | #define RAPIDJSON_ERROR_EN_H_ 17 | 18 | #include "error.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(switch - enum) 23 | RAPIDJSON_DIAG_OFF(covered - switch - default) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Maps error code of parsing into error message. 29 | /*! 30 | \ingroup RAPIDJSON_ERRORS 31 | \param parseErrorCode Error code obtained in parsing. 32 | \return the error message. 33 | \note User can make a copy of this function for localization. 34 | Using switch-case is safer for future modification of error codes. 35 | */ 36 | inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { 37 | switch (parseErrorCode) { 38 | case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 39 | 40 | case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); 41 | case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); 42 | 43 | case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); 44 | 45 | case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); 46 | case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); 47 | case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); 48 | 49 | case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); 50 | 51 | case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); 52 | case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); 53 | case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); 54 | case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); 55 | case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); 56 | 57 | case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); 58 | case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); 59 | case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); 60 | 61 | case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); 62 | case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); 63 | 64 | default: return RAPIDJSON_ERROR_STRING("Unknown error."); 65 | } 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #ifdef __clang__ 71 | RAPIDJSON_DIAG_POP 72 | #endif 73 | 74 | #endif // RAPIDJSON_ERROR_EN_H_ 75 | -------------------------------------------------------------------------------- /src/rapidjson/error/error.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_ERROR_H_ 16 | #define RAPIDJSON_ERROR_ERROR_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(padded) 23 | #endif 24 | 25 | /*! \file error.h */ 26 | 27 | /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ 28 | 29 | /////////////////////////////////////////////////////////////////////////////// 30 | // RAPIDJSON_ERROR_CHARTYPE 31 | 32 | //! Character type of error messages. 33 | /*! \ingroup RAPIDJSON_ERRORS 34 | The default character type is \c char. 35 | On Windows, user can define this macro as \c TCHAR for supporting both 36 | unicode/non-unicode settings. 37 | */ 38 | #ifndef RAPIDJSON_ERROR_CHARTYPE 39 | #define RAPIDJSON_ERROR_CHARTYPE char 40 | #endif 41 | 42 | /////////////////////////////////////////////////////////////////////////////// 43 | // RAPIDJSON_ERROR_STRING 44 | 45 | //! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. 46 | /*! \ingroup RAPIDJSON_ERRORS 47 | By default this conversion macro does nothing. 48 | On Windows, user can define this macro as \c _T(x) for supporting both 49 | unicode/non-unicode settings. 50 | */ 51 | #ifndef RAPIDJSON_ERROR_STRING 52 | #define RAPIDJSON_ERROR_STRING(x) x 53 | #endif 54 | 55 | RAPIDJSON_NAMESPACE_BEGIN 56 | 57 | /////////////////////////////////////////////////////////////////////////////// 58 | // ParseErrorCode 59 | 60 | //! Error code of parsing. 61 | /*! \ingroup RAPIDJSON_ERRORS 62 | \see GenericReader::Parse, GenericReader::GetParseErrorCode 63 | */ 64 | enum ParseErrorCode { 65 | kParseErrorNone = 0, //!< No error. 66 | 67 | kParseErrorDocumentEmpty, //!< The document is empty. 68 | kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. 69 | 70 | kParseErrorValueInvalid, //!< Invalid value. 71 | 72 | kParseErrorObjectMissName, //!< Missing a name for object member. 73 | kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. 74 | kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. 75 | 76 | kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. 77 | 78 | kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. 79 | kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. 80 | kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. 81 | kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. 82 | kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. 83 | 84 | kParseErrorNumberTooBig, //!< Number too big to be stored in double. 85 | kParseErrorNumberMissFraction, //!< Miss fraction part in number. 86 | kParseErrorNumberMissExponent, //!< Miss exponent in number. 87 | 88 | kParseErrorTermination, //!< Parsing was terminated. 89 | kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. 90 | }; 91 | 92 | //! Result of parsing (wraps ParseErrorCode) 93 | /*! 94 | \ingroup RAPIDJSON_ERRORS 95 | \code 96 | Document doc; 97 | ParseResult ok = doc.Parse("[42]"); 98 | if (!ok) { 99 | fjournal->WriteLog(stderr, "JSON parse error: %s (%u)", 100 | GetParseError_En(ok.Code()), ok.Offset()); 101 | exit(EXIT_FAILURE); 102 | } 103 | \endcode 104 | \see GenericReader::Parse, GenericDocument::Parse 105 | */ 106 | struct ParseResult { 107 | //!! Unspecified boolean type 108 | typedef bool (ParseResult::* BooleanType)() const; 109 | public: 110 | //! Default constructor, no error. 111 | ParseResult() : code_(kParseErrorNone), offset_(0) {} 112 | //! Constructor to set an error. 113 | ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} 114 | 115 | //! Get the error code. 116 | ParseErrorCode Code() const { return code_; } 117 | //! Get the error offset, if \ref IsError(), 0 otherwise. 118 | size_t Offset() const { return offset_; } 119 | 120 | //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). 121 | operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } 122 | //! Whether the result is an error. 123 | bool IsError() const { return code_ != kParseErrorNone; } 124 | 125 | bool operator==(const ParseResult& that) const { return code_ == that.code_; } 126 | bool operator==(ParseErrorCode code) const { return code_ == code; } 127 | friend bool operator==(ParseErrorCode code, const ParseResult& err) { return code == err.code_; } 128 | 129 | bool operator!=(const ParseResult& that) const { return !(*this == that); } 130 | bool operator!=(ParseErrorCode code) const { return !(*this == code); } 131 | friend bool operator!=(ParseErrorCode code, const ParseResult& err) { return err != code; } 132 | 133 | //! Reset error code. 134 | void Clear() { Set(kParseErrorNone); } 135 | //! Update error code and offset. 136 | void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } 137 | 138 | private: 139 | ParseErrorCode code_; 140 | size_t offset_; 141 | }; 142 | 143 | //! Function pointer type of GetParseError(). 144 | /*! \ingroup RAPIDJSON_ERRORS 145 | 146 | This is the prototype for \c GetParseError_X(), where \c X is a locale. 147 | User can dynamically change locale in runtime, e.g.: 148 | \code 149 | GetParseErrorFunc GetParseError = GetParseError_En; // or whatever 150 | const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); 151 | \endcode 152 | */ 153 | typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); 154 | 155 | RAPIDJSON_NAMESPACE_END 156 | 157 | #ifdef __clang__ 158 | RAPIDJSON_DIAG_POP 159 | #endif 160 | 161 | #endif // RAPIDJSON_ERROR_ERROR_H_ 162 | -------------------------------------------------------------------------------- /src/rapidjson/filereadstream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEREADSTREAM_H_ 16 | #define RAPIDJSON_FILEREADSTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | RAPIDJSON_DIAG_OFF(unreachable - code) 25 | RAPIDJSON_DIAG_OFF(missing - noreturn) 26 | #endif 27 | 28 | RAPIDJSON_NAMESPACE_BEGIN 29 | 30 | //! File byte stream for input using fread(). 31 | /*! 32 | \note implements Stream concept 33 | */ 34 | class FileReadStream { 35 | public: 36 | typedef char Ch; //!< Character type (byte). 37 | 38 | //! Constructor. 39 | /*! 40 | \param fp File pointer opened for read. 41 | \param buffer user-supplied buffer. 42 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 43 | */ 44 | FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 45 | RAPIDJSON_ASSERT(fp_ != 0); 46 | RAPIDJSON_ASSERT(bufferSize >= 4); 47 | Read(); 48 | } 49 | 50 | Ch Peek() const { return *current_; } 51 | Ch Take() { Ch c = *current_; Read(); return c; } 52 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 53 | 54 | // Not implemented 55 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 56 | void Flush() { RAPIDJSON_ASSERT(false); } 57 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 58 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 59 | 60 | // For encoding detection only. 61 | const Ch* Peek4() const { 62 | return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; 63 | } 64 | 65 | private: 66 | void Read() { 67 | if (current_ < bufferLast_) 68 | ++current_; 69 | else if (!eof_) { 70 | count_ += readCount_; 71 | readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); 72 | bufferLast_ = buffer_ + readCount_ - 1; 73 | current_ = buffer_; 74 | 75 | if (readCount_ < bufferSize_) { 76 | buffer_[readCount_] = '\0'; 77 | ++bufferLast_; 78 | eof_ = true; 79 | } 80 | } 81 | } 82 | 83 | std::FILE* fp_; 84 | Ch* buffer_; 85 | size_t bufferSize_; 86 | Ch* bufferLast_; 87 | Ch* current_; 88 | size_t readCount_; 89 | size_t count_; //!< Number of characters read 90 | bool eof_; 91 | }; 92 | 93 | RAPIDJSON_NAMESPACE_END 94 | 95 | #ifdef __clang__ 96 | RAPIDJSON_DIAG_POP 97 | #endif 98 | 99 | #endif // RAPIDJSON_FILESTREAM_H_ 100 | -------------------------------------------------------------------------------- /src/rapidjson/filewritestream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEWRITESTREAM_H_ 16 | #define RAPIDJSON_FILEWRITESTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(unreachable - code) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of C file stream for output using fwrite(). 29 | /*! 30 | \note implements Stream concept 31 | */ 32 | class FileWriteStream { 33 | public: 34 | typedef char Ch; //!< Character type. Only support char. 35 | 36 | FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 37 | RAPIDJSON_ASSERT(fp_ != 0); 38 | } 39 | 40 | void Put(char c) { 41 | if (current_ >= bufferEnd_) 42 | Flush(); 43 | 44 | *current_++ = c; 45 | } 46 | 47 | void PutN(char c, size_t n) { 48 | size_t avail = static_cast(bufferEnd_ - current_); 49 | while (n > avail) { 50 | std::memset(current_, c, avail); 51 | current_ += avail; 52 | Flush(); 53 | n -= avail; 54 | avail = static_cast(bufferEnd_ - current_); 55 | } 56 | 57 | if (n > 0) { 58 | std::memset(current_, c, n); 59 | current_ += n; 60 | } 61 | } 62 | 63 | void Flush() { 64 | if (current_ != buffer_) { 65 | size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); 66 | if (result < static_cast(current_ - buffer_)) { 67 | // failure deliberately ignored at this time 68 | // added to avoid warn_unused_result build errors 69 | } 70 | current_ = buffer_; 71 | } 72 | } 73 | 74 | // Not implemented 75 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 76 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 77 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 78 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 79 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 80 | 81 | private: 82 | // Prohibit copy constructor & assignment operator. 83 | FileWriteStream(const FileWriteStream&); 84 | FileWriteStream& operator=(const FileWriteStream&); 85 | 86 | std::FILE* fp_; 87 | char* buffer_; 88 | char* bufferEnd_; 89 | char* current_; 90 | }; 91 | 92 | //! Implement specialized version of PutN() with memset() for better performance. 93 | template<> 94 | inline void PutN(FileWriteStream& stream, char c, size_t n) { 95 | stream.PutN(c, n); 96 | } 97 | 98 | RAPIDJSON_NAMESPACE_END 99 | 100 | #ifdef __clang__ 101 | RAPIDJSON_DIAG_POP 102 | #endif 103 | 104 | #endif // RAPIDJSON_FILESTREAM_H_ 105 | -------------------------------------------------------------------------------- /src/rapidjson/fwd.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FWD_H_ 16 | #define RAPIDJSON_FWD_H_ 17 | 18 | #include "rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | 22 | // encodings.h 23 | 24 | template struct UTF8; 25 | template struct UTF16; 26 | template struct UTF16BE; 27 | template struct UTF16LE; 28 | template struct UTF32; 29 | template struct UTF32BE; 30 | template struct UTF32LE; 31 | template struct ASCII; 32 | template struct AutoUTF; 33 | 34 | template 35 | struct Transcoder; 36 | 37 | // allocators.h 38 | 39 | class CrtAllocator; 40 | 41 | template 42 | class MemoryPoolAllocator; 43 | 44 | // stream.h 45 | 46 | template 47 | struct GenericStringStream; 48 | 49 | typedef GenericStringStream > StringStream; 50 | 51 | template 52 | struct GenericInsituStringStream; 53 | 54 | typedef GenericInsituStringStream > InsituStringStream; 55 | 56 | // stringbuffer.h 57 | 58 | template 59 | class GenericStringBuffer; 60 | 61 | typedef GenericStringBuffer, CrtAllocator> StringBuffer; 62 | 63 | // filereadstream.h 64 | 65 | class FileReadStream; 66 | 67 | // filewritestream.h 68 | 69 | class FileWriteStream; 70 | 71 | // memorybuffer.h 72 | 73 | template 74 | struct GenericMemoryBuffer; 75 | 76 | typedef GenericMemoryBuffer MemoryBuffer; 77 | 78 | // memorystream.h 79 | 80 | struct MemoryStream; 81 | 82 | // reader.h 83 | 84 | template 85 | struct BaseReaderHandler; 86 | 87 | template 88 | class GenericReader; 89 | 90 | typedef GenericReader, UTF8, CrtAllocator> Reader; 91 | 92 | // writer.h 93 | 94 | template 95 | class Writer; 96 | 97 | // prettywriter.h 98 | 99 | template 100 | class PrettyWriter; 101 | 102 | // document.h 103 | 104 | template 105 | class GenericMember; 106 | 107 | template 108 | class GenericMemberIterator; 109 | 110 | template 111 | struct GenericStringRef; 112 | 113 | template 114 | class GenericValue; 115 | 116 | typedef GenericValue, MemoryPoolAllocator > Value; 117 | 118 | template 119 | class GenericDocument; 120 | 121 | typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; 122 | 123 | // pointer.h 124 | 125 | template 126 | class GenericPointer; 127 | 128 | typedef GenericPointer Pointer; 129 | 130 | // schema.h 131 | 132 | template 133 | class IGenericRemoteSchemaDocumentProvider; 134 | 135 | template 136 | class GenericSchemaDocument; 137 | 138 | typedef GenericSchemaDocument SchemaDocument; 139 | typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; 140 | 141 | template < 142 | typename SchemaDocumentType, 143 | typename OutputHandler, 144 | typename StateAllocator> 145 | class GenericSchemaValidator; 146 | 147 | typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; 148 | 149 | RAPIDJSON_NAMESPACE_END 150 | 151 | #endif // RAPIDJSON_RAPIDJSONFWD_H_ 152 | -------------------------------------------------------------------------------- /src/rapidjson/internal/clzll.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_CLZLL_H_ 16 | #define RAPIDJSON_CLZLL_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(_MSC_VER) && !defined(UNDER_CE) 21 | #include 22 | #if defined(_WIN64) 23 | #pragma intrinsic(_BitScanReverse64) 24 | #else 25 | #pragma intrinsic(_BitScanReverse) 26 | #endif 27 | #endif 28 | 29 | RAPIDJSON_NAMESPACE_BEGIN 30 | namespace internal { 31 | inline uint32_t clzll(uint64_t x) { 32 | // Passing 0 to __builtin_clzll is UB in GCC and results in an 33 | // infinite loop in the software implementation. 34 | RAPIDJSON_ASSERT(x != 0); 35 | 36 | #if defined(_MSC_VER) && !defined(UNDER_CE) 37 | unsigned long r = 0; 38 | #if defined(_WIN64) 39 | _BitScanReverse64(&r, x); 40 | #else 41 | // Scan the high 32 bits. 42 | if (_BitScanReverse(&r, static_cast(x >> 32))) 43 | return 63 - (r + 32); 44 | 45 | // Scan the low 32 bits. 46 | _BitScanReverse(&r, static_cast(x & 0xFFFFFFFF)); 47 | #endif // _WIN64 48 | 49 | return 63 - r; 50 | #elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) 51 | // __builtin_clzll wrapper 52 | return static_cast(__builtin_clzll(x)); 53 | #else 54 | // naive version 55 | uint32_t r = 0; 56 | while (!(x & (static_cast(1) << 63))) { 57 | x <<= 1; 58 | ++r; 59 | } 60 | 61 | return r; 62 | #endif // _MSC_VER 63 | } 64 | 65 | #define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll 66 | } // namespace internal 67 | RAPIDJSON_NAMESPACE_END 68 | 69 | #endif // RAPIDJSON_CLZLL_H_ 70 | -------------------------------------------------------------------------------- /src/rapidjson/internal/dtoa.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | // This is a C++ header-only implementation of Grisu2 algorithm from the publication: 16 | // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with 17 | // integers." ACM Sigplan Notices 45.6 (2010): 233-243. 18 | 19 | #ifndef RAPIDJSON_DTOA_ 20 | #define RAPIDJSON_DTOA_ 21 | 22 | #include "itoa.h" // GetDigitsLut() 23 | #include "diyfp.h" 24 | #include "ieee754.h" 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | namespace internal { 28 | #ifdef __GNUC__ 29 | RAPIDJSON_DIAG_PUSH 30 | RAPIDJSON_DIAG_OFF(effc++) 31 | RAPIDJSON_DIAG_OFF(array - bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 32 | #endif 33 | 34 | inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { 35 | while (rest < wp_w && delta - rest >= ten_kappa && 36 | (rest + ten_kappa < wp_w || /// closer 37 | wp_w - rest > rest + ten_kappa - wp_w)) { 38 | buffer[len - 1]--; 39 | rest += ten_kappa; 40 | } 41 | } 42 | 43 | inline int CountDecimalDigit32(uint32_t n) { 44 | // Simple pure C++ implementation was faster than __builtin_clz version in this situation. 45 | if (n < 10) return 1; 46 | if (n < 100) return 2; 47 | if (n < 1000) return 3; 48 | if (n < 10000) return 4; 49 | if (n < 100000) return 5; 50 | if (n < 1000000) return 6; 51 | if (n < 10000000) return 7; 52 | if (n < 100000000) return 8; 53 | // Will not reach 10 digits in DigitGen() 54 | //if (n < 1000000000) return 9; 55 | //return 10; 56 | return 9; 57 | } 58 | 59 | inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { 60 | static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; 61 | const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); 62 | const DiyFp wp_w = Mp - W; 63 | uint32_t p1 = static_cast(Mp.f >> -one.e); 64 | uint64_t p2 = Mp.f & (one.f - 1); 65 | int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] 66 | *len = 0; 67 | 68 | while (kappa > 0) { 69 | uint32_t d = 0; 70 | switch (kappa) { 71 | case 9: d = p1 / 100000000; p1 %= 100000000; break; 72 | case 8: d = p1 / 10000000; p1 %= 10000000; break; 73 | case 7: d = p1 / 1000000; p1 %= 1000000; break; 74 | case 6: d = p1 / 100000; p1 %= 100000; break; 75 | case 5: d = p1 / 10000; p1 %= 10000; break; 76 | case 4: d = p1 / 1000; p1 %= 1000; break; 77 | case 3: d = p1 / 100; p1 %= 100; break; 78 | case 2: d = p1 / 10; p1 %= 10; break; 79 | case 1: d = p1; p1 = 0; break; 80 | default:; 81 | } 82 | if (d || *len) 83 | buffer[(*len)++] = static_cast('0' + static_cast(d)); 84 | kappa--; 85 | uint64_t tmp = (static_cast(p1) << -one.e) + p2; 86 | if (tmp <= delta) { 87 | *K += kappa; 88 | GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); 89 | return; 90 | } 91 | } 92 | 93 | // kappa = 0 94 | for (;;) { 95 | p2 *= 10; 96 | delta *= 10; 97 | char d = static_cast(p2 >> -one.e); 98 | if (d || *len) 99 | buffer[(*len)++] = static_cast('0' + d); 100 | p2 &= one.f - 1; 101 | kappa--; 102 | if (p2 < delta) { 103 | *K += kappa; 104 | int index = -kappa; 105 | GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); 106 | return; 107 | } 108 | } 109 | } 110 | 111 | inline void Grisu2(double value, char* buffer, int* length, int* K) { 112 | const DiyFp v(value); 113 | DiyFp w_m, w_p; 114 | v.NormalizedBoundaries(&w_m, &w_p); 115 | 116 | const DiyFp c_mk = GetCachedPower(w_p.e, K); 117 | const DiyFp W = v.Normalize() * c_mk; 118 | DiyFp Wp = w_p * c_mk; 119 | DiyFp Wm = w_m * c_mk; 120 | Wm.f++; 121 | Wp.f--; 122 | DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); 123 | } 124 | 125 | inline char* WriteExponent(int K, char* buffer) { 126 | if (K < 0) { 127 | *buffer++ = '-'; 128 | K = -K; 129 | } 130 | 131 | if (K >= 100) { 132 | *buffer++ = static_cast('0' + static_cast(K / 100)); 133 | K %= 100; 134 | const char* d = GetDigitsLut() + K * 2; 135 | *buffer++ = d[0]; 136 | *buffer++ = d[1]; 137 | } 138 | else if (K >= 10) { 139 | const char* d = GetDigitsLut() + K * 2; 140 | *buffer++ = d[0]; 141 | *buffer++ = d[1]; 142 | } 143 | else 144 | *buffer++ = static_cast('0' + static_cast(K)); 145 | 146 | return buffer; 147 | } 148 | 149 | inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { 150 | const int kk = length + k; // 10^(kk-1) <= v < 10^kk 151 | 152 | if (0 <= k && kk <= 21) { 153 | // 1234e7 -> 12340000000 154 | for (int i = length; i < kk; i++) 155 | buffer[i] = '0'; 156 | buffer[kk] = '.'; 157 | buffer[kk + 1] = '0'; 158 | return &buffer[kk + 2]; 159 | } 160 | else if (0 < kk && kk <= 21) { 161 | // 1234e-2 -> 12.34 162 | std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); 163 | buffer[kk] = '.'; 164 | if (0 > k + maxDecimalPlaces) { 165 | // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 166 | // Remove extra trailing zeros (at least one) after truncation. 167 | for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) 168 | if (buffer[i] != '0') 169 | return &buffer[i + 1]; 170 | return &buffer[kk + 2]; // Reserve one zero 171 | } 172 | else 173 | return &buffer[length + 1]; 174 | } 175 | else if (-6 < kk && kk <= 0) { 176 | // 1234e-6 -> 0.001234 177 | const int offset = 2 - kk; 178 | std::memmove(&buffer[offset], &buffer[0], static_cast(length)); 179 | buffer[0] = '0'; 180 | buffer[1] = '.'; 181 | for (int i = 2; i < offset; i++) 182 | buffer[i] = '0'; 183 | if (length - kk > maxDecimalPlaces) { 184 | // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 185 | // Remove extra trailing zeros (at least one) after truncation. 186 | for (int i = maxDecimalPlaces + 1; i > 2; i--) 187 | if (buffer[i] != '0') 188 | return &buffer[i + 1]; 189 | return &buffer[3]; // Reserve one zero 190 | } 191 | else 192 | return &buffer[length + offset]; 193 | } 194 | else if (kk < -maxDecimalPlaces) { 195 | // Truncate to zero 196 | buffer[0] = '0'; 197 | buffer[1] = '.'; 198 | buffer[2] = '0'; 199 | return &buffer[3]; 200 | } 201 | else if (length == 1) { 202 | // 1e30 203 | buffer[1] = 'e'; 204 | return WriteExponent(kk - 1, &buffer[2]); 205 | } 206 | else { 207 | // 1234e30 -> 1.234e33 208 | std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); 209 | buffer[1] = '.'; 210 | buffer[length + 1] = 'e'; 211 | return WriteExponent(kk - 1, &buffer[0 + length + 2]); 212 | } 213 | } 214 | 215 | inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { 216 | RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); 217 | Double d(value); 218 | if (d.IsZero()) { 219 | if (d.Sign()) 220 | *buffer++ = '-'; // -0.0, Issue #289 221 | buffer[0] = '0'; 222 | buffer[1] = '.'; 223 | buffer[2] = '0'; 224 | return &buffer[3]; 225 | } 226 | else { 227 | if (value < 0) { 228 | *buffer++ = '-'; 229 | value = -value; 230 | } 231 | int length, K; 232 | Grisu2(value, buffer, &length, &K); 233 | return Prettify(buffer, length, K, maxDecimalPlaces); 234 | } 235 | } 236 | 237 | #ifdef __GNUC__ 238 | RAPIDJSON_DIAG_POP 239 | #endif 240 | } // namespace internal 241 | RAPIDJSON_NAMESPACE_END 242 | 243 | #endif // RAPIDJSON_DTOA_ 244 | -------------------------------------------------------------------------------- /src/rapidjson/internal/ieee754.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_IEEE754_ 16 | #define RAPIDJSON_IEEE754_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | class Double { 23 | public: 24 | Double() {} 25 | Double(double d) : d_(d) {} 26 | Double(uint64_t u) : u_(u) {} 27 | 28 | double Value() const { return d_; } 29 | uint64_t Uint64Value() const { return u_; } 30 | 31 | double NextPositiveDouble() const { 32 | RAPIDJSON_ASSERT(!Sign()); 33 | return Double(u_ + 1).Value(); 34 | } 35 | 36 | bool Sign() const { return (u_ & kSignMask) != 0; } 37 | uint64_t Significand() const { return u_ & kSignificandMask; } 38 | int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } 39 | 40 | bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } 41 | bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } 42 | bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } 43 | bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } 44 | bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } 45 | 46 | uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } 47 | int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } 48 | uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } 49 | 50 | static int EffectiveSignificandSize(int order) { 51 | if (order >= -1021) 52 | return 53; 53 | else if (order <= -1074) 54 | return 0; 55 | else 56 | return order + 1074; 57 | } 58 | 59 | private: 60 | static const int kSignificandSize = 52; 61 | static const int kExponentBias = 0x3FF; 62 | static const int kDenormalExponent = 1 - kExponentBias; 63 | static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); 64 | static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); 65 | static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); 66 | static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); 67 | 68 | union { 69 | double d_; 70 | uint64_t u_; 71 | }; 72 | }; 73 | } // namespace internal 74 | RAPIDJSON_NAMESPACE_END 75 | 76 | #endif // RAPIDJSON_IEEE754_ 77 | -------------------------------------------------------------------------------- /src/rapidjson/internal/meta.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_META_H_ 16 | #define RAPIDJSON_INTERNAL_META_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #ifdef __GNUC__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | 25 | #if defined(_MSC_VER) && !defined(__clang__) 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(6334) 28 | #endif 29 | 30 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 31 | #include 32 | #endif 33 | 34 | //@cond RAPIDJSON_INTERNAL 35 | RAPIDJSON_NAMESPACE_BEGIN 36 | namespace internal { 37 | // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching 38 | template struct Void { typedef void Type; }; 39 | 40 | /////////////////////////////////////////////////////////////////////////////// 41 | // BoolType, TrueType, FalseType 42 | // 43 | template struct BoolType { 44 | static const bool Value = Cond; 45 | typedef BoolType Type; 46 | }; 47 | typedef BoolType TrueType; 48 | typedef BoolType FalseType; 49 | 50 | /////////////////////////////////////////////////////////////////////////////// 51 | // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr 52 | // 53 | 54 | template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; 55 | template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; 56 | template struct SelectIfCond : SelectIfImpl::template Apply {}; 57 | template struct SelectIf : SelectIfCond {}; 58 | 59 | template struct AndExprCond : FalseType {}; 60 | template <> struct AndExprCond : TrueType {}; 61 | template struct OrExprCond : TrueType {}; 62 | template <> struct OrExprCond : FalseType {}; 63 | 64 | template struct BoolExpr : SelectIf::Type {}; 65 | template struct NotExpr : SelectIf::Type {}; 66 | template struct AndExpr : AndExprCond::Type {}; 67 | template struct OrExpr : OrExprCond::Type {}; 68 | 69 | /////////////////////////////////////////////////////////////////////////////// 70 | // AddConst, MaybeAddConst, RemoveConst 71 | template struct AddConst { typedef const T Type; }; 72 | template struct MaybeAddConst : SelectIfCond {}; 73 | template struct RemoveConst { typedef T Type; }; 74 | template struct RemoveConst { typedef T Type; }; 75 | 76 | /////////////////////////////////////////////////////////////////////////////// 77 | // IsSame, IsConst, IsMoreConst, IsPointer 78 | // 79 | template struct IsSame : FalseType {}; 80 | template struct IsSame : TrueType {}; 81 | 82 | template struct IsConst : FalseType {}; 83 | template struct IsConst : TrueType {}; 84 | 85 | template 86 | struct IsMoreConst 87 | : AndExpr::Type, typename RemoveConst::Type>, 88 | BoolType::Value >= IsConst::Value> >::Type {}; 89 | 90 | template struct IsPointer : FalseType {}; 91 | template struct IsPointer : TrueType {}; 92 | 93 | /////////////////////////////////////////////////////////////////////////////// 94 | // IsBaseOf 95 | // 96 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 97 | 98 | template struct IsBaseOf 99 | : BoolType< ::std::is_base_of::value> {}; 100 | 101 | #else // simplified version adopted from Boost 102 | 103 | template struct IsBaseOfImpl { 104 | RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); 105 | RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); 106 | 107 | typedef char(&Yes)[1]; 108 | typedef char(&No)[2]; 109 | 110 | template 111 | static Yes Check(const D*, T); 112 | static No Check(const B*, int); 113 | 114 | struct Host { 115 | operator const B* () const; 116 | operator const D* (); 117 | }; 118 | 119 | enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; 120 | }; 121 | 122 | template struct IsBaseOf 123 | : OrExpr, BoolExpr > >::Type {}; 124 | 125 | #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS 126 | 127 | ////////////////////////////////////////////////////////////////////////// 128 | // EnableIf / DisableIf 129 | // 130 | template struct EnableIfCond { typedef T Type; }; 131 | template struct EnableIfCond { /* empty */ }; 132 | 133 | template struct DisableIfCond { typedef T Type; }; 134 | template struct DisableIfCond { /* empty */ }; 135 | 136 | template 137 | struct EnableIf : EnableIfCond {}; 138 | 139 | template 140 | struct DisableIf : DisableIfCond {}; 141 | 142 | // SFINAE helpers 143 | struct SfinaeTag {}; 144 | template struct RemoveSfinaeTag; 145 | template struct RemoveSfinaeTag { typedef T Type; }; 146 | 147 | #define RAPIDJSON_REMOVEFPTR_(type) \ 148 | typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ 149 | < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type 150 | 151 | #define RAPIDJSON_ENABLEIF(cond) \ 152 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 153 | ::Type * = NULL 154 | 155 | #define RAPIDJSON_DISABLEIF(cond) \ 156 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 157 | ::Type * = NULL 158 | 159 | #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ 160 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 161 | ::Type 163 | 164 | #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ 165 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 166 | ::Type 168 | } // namespace internal 169 | RAPIDJSON_NAMESPACE_END 170 | //@endcond 171 | 172 | #if defined(_MSC_VER) && !defined(__clang__) 173 | RAPIDJSON_DIAG_POP 174 | #endif 175 | 176 | #ifdef __GNUC__ 177 | RAPIDJSON_DIAG_POP 178 | #endif 179 | 180 | #endif // RAPIDJSON_INTERNAL_META_H_ 181 | -------------------------------------------------------------------------------- /src/rapidjson/internal/pow10.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_POW10_ 16 | #define RAPIDJSON_POW10_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | //! Computes integer powers of 10 in double (10.0^n). 23 | /*! This function uses lookup table for fast and accurate results. 24 | \param n non-negative exponent. Must <= 308. 25 | \return 10.0^n 26 | */ 27 | inline double Pow10(int n) { 28 | static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 29 | 1e+0, 30 | 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 31 | 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 32 | 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 33 | 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 34 | 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 35 | 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 36 | 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 37 | 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 38 | 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 39 | 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 40 | 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 41 | 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 42 | 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 43 | 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 44 | 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 45 | 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 46 | }; 47 | RAPIDJSON_ASSERT(n >= 0 && n <= 308); 48 | return e[n]; 49 | } 50 | } // namespace internal 51 | RAPIDJSON_NAMESPACE_END 52 | 53 | #endif // RAPIDJSON_POW10_ 54 | -------------------------------------------------------------------------------- /src/rapidjson/internal/stack.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STACK_H_ 16 | #define RAPIDJSON_INTERNAL_STACK_H_ 17 | 18 | #include "../allocators.h" 19 | #include "swap.h" 20 | #include 21 | 22 | #if defined(__clang__) 23 | RAPIDJSON_DIAG_PUSH 24 | RAPIDJSON_DIAG_OFF(c++98 - compat) 25 | #endif 26 | 27 | RAPIDJSON_NAMESPACE_BEGIN 28 | namespace internal { 29 | /////////////////////////////////////////////////////////////////////////////// 30 | // Stack 31 | 32 | //! A type-unsafe stack for storing different types of data. 33 | /*! \tparam Allocator Allocator for allocating stack memory. 34 | */ 35 | template 36 | class Stack { 37 | public: 38 | // Optimization note: Do not allocate memory for stack_ in constructor. 39 | // Do it lazily when first Push() -> Expand() -> Resize(). 40 | Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { 41 | } 42 | 43 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 44 | Stack(Stack&& rhs) 45 | : allocator_(rhs.allocator_), 46 | ownAllocator_(rhs.ownAllocator_), 47 | stack_(rhs.stack_), 48 | stackTop_(rhs.stackTop_), 49 | stackEnd_(rhs.stackEnd_), 50 | initialCapacity_(rhs.initialCapacity_) 51 | { 52 | rhs.allocator_ = 0; 53 | rhs.ownAllocator_ = 0; 54 | rhs.stack_ = 0; 55 | rhs.stackTop_ = 0; 56 | rhs.stackEnd_ = 0; 57 | rhs.initialCapacity_ = 0; 58 | } 59 | #endif 60 | 61 | ~Stack() { 62 | Destroy(); 63 | } 64 | 65 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 66 | Stack& operator=(Stack&& rhs) { 67 | if (&rhs != this) 68 | { 69 | Destroy(); 70 | 71 | allocator_ = rhs.allocator_; 72 | ownAllocator_ = rhs.ownAllocator_; 73 | stack_ = rhs.stack_; 74 | stackTop_ = rhs.stackTop_; 75 | stackEnd_ = rhs.stackEnd_; 76 | initialCapacity_ = rhs.initialCapacity_; 77 | 78 | rhs.allocator_ = 0; 79 | rhs.ownAllocator_ = 0; 80 | rhs.stack_ = 0; 81 | rhs.stackTop_ = 0; 82 | rhs.stackEnd_ = 0; 83 | rhs.initialCapacity_ = 0; 84 | } 85 | return *this; 86 | } 87 | #endif 88 | 89 | void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { 90 | internal::Swap(allocator_, rhs.allocator_); 91 | internal::Swap(ownAllocator_, rhs.ownAllocator_); 92 | internal::Swap(stack_, rhs.stack_); 93 | internal::Swap(stackTop_, rhs.stackTop_); 94 | internal::Swap(stackEnd_, rhs.stackEnd_); 95 | internal::Swap(initialCapacity_, rhs.initialCapacity_); 96 | } 97 | 98 | void Clear() { stackTop_ = stack_; } 99 | 100 | void ShrinkToFit() { 101 | if (Empty()) { 102 | // If the stack is empty, completely deallocate the memory. 103 | Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) 104 | stack_ = 0; 105 | stackTop_ = 0; 106 | stackEnd_ = 0; 107 | } 108 | else 109 | Resize(GetSize()); 110 | } 111 | 112 | // Optimization note: try to minimize the size of this function for force inline. 113 | // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. 114 | template 115 | RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { 116 | // Expand the stack if needed 117 | if (RAPIDJSON_UNLIKELY(static_cast(sizeof(T) * count) > (stackEnd_ - stackTop_))) 118 | Expand(count); 119 | } 120 | 121 | template 122 | RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { 123 | Reserve(count); 124 | return PushUnsafe(count); 125 | } 126 | 127 | template 128 | RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { 129 | RAPIDJSON_ASSERT(stackTop_); 130 | RAPIDJSON_ASSERT(static_cast(sizeof(T) * count) <= (stackEnd_ - stackTop_)); 131 | T* ret = reinterpret_cast(stackTop_); 132 | stackTop_ += sizeof(T) * count; 133 | return ret; 134 | } 135 | 136 | template 137 | T* Pop(size_t count) { 138 | RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); 139 | stackTop_ -= count * sizeof(T); 140 | return reinterpret_cast(stackTop_); 141 | } 142 | 143 | template 144 | T* Top() { 145 | RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); 146 | return reinterpret_cast(stackTop_ - sizeof(T)); 147 | } 148 | 149 | template 150 | const T* Top() const { 151 | RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); 152 | return reinterpret_cast(stackTop_ - sizeof(T)); 153 | } 154 | 155 | template 156 | T* End() { return reinterpret_cast(stackTop_); } 157 | 158 | template 159 | const T* End() const { return reinterpret_cast(stackTop_); } 160 | 161 | template 162 | T* Bottom() { return reinterpret_cast(stack_); } 163 | 164 | template 165 | const T* Bottom() const { return reinterpret_cast(stack_); } 166 | 167 | bool HasAllocator() const { 168 | return allocator_ != 0; 169 | } 170 | 171 | Allocator& GetAllocator() { 172 | RAPIDJSON_ASSERT(allocator_); 173 | return *allocator_; 174 | } 175 | 176 | bool Empty() const { return stackTop_ == stack_; } 177 | size_t GetSize() const { return static_cast(stackTop_ - stack_); } 178 | size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } 179 | 180 | private: 181 | template 182 | void Expand(size_t count) { 183 | // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. 184 | size_t newCapacity; 185 | if (stack_ == 0) { 186 | if (!allocator_) 187 | ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); 188 | newCapacity = initialCapacity_; 189 | } 190 | else { 191 | newCapacity = GetCapacity(); 192 | newCapacity += (newCapacity + 1) / 2; 193 | } 194 | size_t newSize = GetSize() + sizeof(T) * count; 195 | if (newCapacity < newSize) 196 | newCapacity = newSize; 197 | 198 | Resize(newCapacity); 199 | } 200 | 201 | void Resize(size_t newCapacity) { 202 | const size_t size = GetSize(); // Backup the current size 203 | stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); 204 | stackTop_ = stack_ + size; 205 | stackEnd_ = stack_ + newCapacity; 206 | } 207 | 208 | void Destroy() { 209 | Allocator::Free(stack_); 210 | RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack 211 | } 212 | 213 | // Prohibit copy constructor & assignment operator. 214 | Stack(const Stack&); 215 | Stack& operator=(const Stack&); 216 | 217 | Allocator* allocator_; 218 | Allocator* ownAllocator_; 219 | char* stack_; 220 | char* stackTop_; 221 | char* stackEnd_; 222 | size_t initialCapacity_; 223 | }; 224 | } // namespace internal 225 | RAPIDJSON_NAMESPACE_END 226 | 227 | #if defined(__clang__) 228 | RAPIDJSON_DIAG_POP 229 | #endif 230 | 231 | #endif // RAPIDJSON_STACK_H_ 232 | -------------------------------------------------------------------------------- /src/rapidjson/internal/strfunc.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ 16 | #define RAPIDJSON_INTERNAL_STRFUNC_H_ 17 | 18 | #include "../stream.h" 19 | #include 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | namespace internal { 23 | //! Custom strlen() which works on different character types. 24 | /*! \tparam Ch Character type (e.g. char, wchar_t, short) 25 | \param s Null-terminated input string. 26 | \return Number of characters in the string. 27 | \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. 28 | */ 29 | template 30 | inline SizeType StrLen(const Ch* s) { 31 | RAPIDJSON_ASSERT(s != 0); 32 | const Ch* p = s; 33 | while (*p) ++p; 34 | return SizeType(p - s); 35 | } 36 | 37 | template <> 38 | inline SizeType StrLen(const char* s) { 39 | return SizeType(std::strlen(s)); 40 | } 41 | 42 | template <> 43 | inline SizeType StrLen(const wchar_t* s) { 44 | return SizeType(std::wcslen(s)); 45 | } 46 | 47 | //! Returns number of code points in a encoded string. 48 | template 49 | bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { 50 | RAPIDJSON_ASSERT(s != 0); 51 | RAPIDJSON_ASSERT(outCount != 0); 52 | GenericStringStream is(s); 53 | const typename Encoding::Ch* end = s + length; 54 | SizeType count = 0; 55 | while (is.src_ < end) { 56 | unsigned codepoint; 57 | if (!Encoding::Decode(is, &codepoint)) 58 | return false; 59 | count++; 60 | } 61 | *outCount = count; 62 | return true; 63 | } 64 | } // namespace internal 65 | RAPIDJSON_NAMESPACE_END 66 | 67 | #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ 68 | -------------------------------------------------------------------------------- /src/rapidjson/internal/swap.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_SWAP_H_ 16 | #define RAPIDJSON_INTERNAL_SWAP_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(__clang__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(c++98 - compat) 23 | #endif 24 | 25 | RAPIDJSON_NAMESPACE_BEGIN 26 | namespace internal { 27 | //! Custom swap() to avoid dependency on C++ header 28 | /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. 29 | \note This has the same semantics as std::swap(). 30 | */ 31 | template 32 | inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { 33 | T tmp = a; 34 | a = b; 35 | b = tmp; 36 | } 37 | } // namespace internal 38 | RAPIDJSON_NAMESPACE_END 39 | 40 | #if defined(__clang__) 41 | RAPIDJSON_DIAG_POP 42 | #endif 43 | 44 | #endif // RAPIDJSON_INTERNAL_SWAP_H_ 45 | -------------------------------------------------------------------------------- /src/rapidjson/istreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ 16 | #define RAPIDJSON_ISTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | #include 21 | 22 | #ifdef __clang__ 23 | RAPIDJSON_DIAG_PUSH 24 | RAPIDJSON_DIAG_OFF(padded) 25 | #elif defined(_MSC_VER) 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized 28 | #endif 29 | 30 | RAPIDJSON_NAMESPACE_BEGIN 31 | 32 | //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. 33 | /*! 34 | The classes can be wrapped including but not limited to: 35 | 36 | - \c std::istringstream 37 | - \c std::stringstream 38 | - \c std::wistringstream 39 | - \c std::wstringstream 40 | - \c std::ifstream 41 | - \c std::fstream 42 | - \c std::wifstream 43 | - \c std::wfstream 44 | 45 | \tparam StreamType Class derived from \c std::basic_istream. 46 | */ 47 | 48 | template 49 | class BasicIStreamWrapper { 50 | public: 51 | typedef typename StreamType::char_type Ch; 52 | 53 | //! Constructor. 54 | /*! 55 | \param stream stream opened for read. 56 | */ 57 | BasicIStreamWrapper(StreamType& stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 58 | Read(); 59 | } 60 | 61 | //! Constructor. 62 | /*! 63 | \param stream stream opened for read. 64 | \param buffer user-supplied buffer. 65 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 66 | */ 67 | BasicIStreamWrapper(StreamType& stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 68 | RAPIDJSON_ASSERT(bufferSize >= 4); 69 | Read(); 70 | } 71 | 72 | Ch Peek() const { return *current_; } 73 | Ch Take() { Ch c = *current_; Read(); return c; } 74 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 75 | 76 | // Not implemented 77 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 78 | void Flush() { RAPIDJSON_ASSERT(false); } 79 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 80 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 81 | 82 | // For encoding detection only. 83 | const Ch* Peek4() const { 84 | return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; 85 | } 86 | 87 | private: 88 | BasicIStreamWrapper(); 89 | BasicIStreamWrapper(const BasicIStreamWrapper&); 90 | BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); 91 | 92 | void Read() { 93 | if (current_ < bufferLast_) 94 | ++current_; 95 | else if (!eof_) { 96 | count_ += readCount_; 97 | readCount_ = bufferSize_; 98 | bufferLast_ = buffer_ + readCount_ - 1; 99 | current_ = buffer_; 100 | 101 | if (!stream_.read(buffer_, static_cast(bufferSize_))) { 102 | readCount_ = static_cast(stream_.gcount()); 103 | *(bufferLast_ = buffer_ + readCount_) = '\0'; 104 | eof_ = true; 105 | } 106 | } 107 | } 108 | 109 | StreamType& stream_; 110 | Ch peekBuffer_[4], * buffer_; 111 | size_t bufferSize_; 112 | Ch* bufferLast_; 113 | Ch* current_; 114 | size_t readCount_; 115 | size_t count_; //!< Number of characters read 116 | bool eof_; 117 | }; 118 | 119 | typedef BasicIStreamWrapper IStreamWrapper; 120 | typedef BasicIStreamWrapper WIStreamWrapper; 121 | 122 | #if defined(__clang__) || defined(_MSC_VER) 123 | RAPIDJSON_DIAG_POP 124 | #endif 125 | 126 | RAPIDJSON_NAMESPACE_END 127 | 128 | #endif // RAPIDJSON_ISTREAMWRAPPER_H_ 129 | -------------------------------------------------------------------------------- /src/rapidjson/memorybuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYBUFFER_H_ 16 | #define RAPIDJSON_MEMORYBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! Represents an in-memory output byte stream. 24 | /*! 25 | This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. 26 | 27 | It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. 28 | 29 | Differences between MemoryBuffer and StringBuffer: 30 | 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 31 | 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. 32 | 33 | \tparam Allocator type for allocating memory buffer. 34 | \note implements Stream concept 35 | */ 36 | template 37 | struct GenericMemoryBuffer { 38 | typedef char Ch; // byte 39 | 40 | GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 41 | 42 | void Put(Ch c) { *stack_.template Push() = c; } 43 | void Flush() {} 44 | 45 | void Clear() { stack_.Clear(); } 46 | void ShrinkToFit() { stack_.ShrinkToFit(); } 47 | Ch* Push(size_t count) { return stack_.template Push(count); } 48 | void Pop(size_t count) { stack_.template Pop(count); } 49 | 50 | const Ch* GetBuffer() const { 51 | return stack_.template Bottom(); 52 | } 53 | 54 | size_t GetSize() const { return stack_.GetSize(); } 55 | 56 | static const size_t kDefaultCapacity = 256; 57 | mutable internal::Stack stack_; 58 | }; 59 | 60 | typedef GenericMemoryBuffer<> MemoryBuffer; 61 | 62 | //! Implement specialized version of PutN() with memset() for better performance. 63 | template<> 64 | inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { 65 | std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 71 | -------------------------------------------------------------------------------- /src/rapidjson/memorystream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYSTREAM_H_ 16 | #define RAPIDJSON_MEMORYSTREAM_H_ 17 | 18 | #include "stream.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(unreachable - code) 23 | RAPIDJSON_DIAG_OFF(missing - noreturn) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Represents an in-memory input byte stream. 29 | /*! 30 | This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. 31 | 32 | It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. 33 | 34 | Differences between MemoryStream and StringStream: 35 | 1. StringStream has encoding but MemoryStream is a byte stream. 36 | 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 37 | 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). 38 | \note implements Stream concept 39 | */ 40 | struct MemoryStream { 41 | typedef char Ch; // byte 42 | 43 | MemoryStream(const Ch* src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} 44 | 45 | Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } 46 | Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } 47 | size_t Tell() const { return static_cast(src_ - begin_); } 48 | 49 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 50 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 51 | void Flush() { RAPIDJSON_ASSERT(false); } 52 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 53 | 54 | // For encoding detection only. 55 | const Ch* Peek4() const { 56 | return Tell() + 4 <= size_ ? src_ : 0; 57 | } 58 | 59 | const Ch* src_; //!< Current read position. 60 | const Ch* begin_; //!< Original head of the string. 61 | const Ch* end_; //!< End of stream. 62 | size_t size_; //!< Size of the stream. 63 | }; 64 | 65 | RAPIDJSON_NAMESPACE_END 66 | 67 | #ifdef __clang__ 68 | RAPIDJSON_DIAG_POP 69 | #endif 70 | 71 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 72 | -------------------------------------------------------------------------------- /src/rapidjson/ostreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_OSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. 29 | /*! 30 | The classes can be wrapped including but not limited to: 31 | 32 | - \c std::ostringstream 33 | - \c std::stringstream 34 | - \c std::wpstringstream 35 | - \c std::wstringstream 36 | - \c std::ifstream 37 | - \c std::fstream 38 | - \c std::wofstream 39 | - \c std::wfstream 40 | 41 | \tparam StreamType Class derived from \c std::basic_ostream. 42 | */ 43 | 44 | template 45 | class BasicOStreamWrapper { 46 | public: 47 | typedef typename StreamType::char_type Ch; 48 | BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} 49 | 50 | void Put(Ch c) { 51 | stream_.put(c); 52 | } 53 | 54 | void Flush() { 55 | stream_.flush(); 56 | } 57 | 58 | // Not implemented 59 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 60 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 61 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 62 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 63 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 64 | 65 | private: 66 | BasicOStreamWrapper(const BasicOStreamWrapper&); 67 | BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); 68 | 69 | StreamType& stream_; 70 | }; 71 | 72 | typedef BasicOStreamWrapper OStreamWrapper; 73 | typedef BasicOStreamWrapper WOStreamWrapper; 74 | 75 | #ifdef __clang__ 76 | RAPIDJSON_DIAG_POP 77 | #endif 78 | 79 | RAPIDJSON_NAMESPACE_END 80 | 81 | #endif // RAPIDJSON_OSTREAMWRAPPER_H_ 82 | -------------------------------------------------------------------------------- /src/rapidjson/stream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #include "rapidjson.h" 16 | 17 | #ifndef RAPIDJSON_STREAM_H_ 18 | #define RAPIDJSON_STREAM_H_ 19 | 20 | #include "encodings.h" 21 | 22 | RAPIDJSON_NAMESPACE_BEGIN 23 | 24 | /////////////////////////////////////////////////////////////////////////////// 25 | // Stream 26 | 27 | /*! \class rapidjson::Stream 28 | \brief Concept for reading and writing characters. 29 | 30 | For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). 31 | 32 | For write-only stream, only need to implement Put() and Flush(). 33 | 34 | \code 35 | concept Stream { 36 | typename Ch; //!< Character type of the stream. 37 | 38 | //! Read the current character from stream without moving the read cursor. 39 | Ch Peek() const; 40 | 41 | //! Read the current character from stream and moving the read cursor to next character. 42 | Ch Take(); 43 | 44 | //! Get the current read cursor. 45 | //! \return Number of characters read from start. 46 | size_t Tell(); 47 | 48 | //! Begin writing operation at the current read pointer. 49 | //! \return The begin writer pointer. 50 | Ch* PutBegin(); 51 | 52 | //! Write a character. 53 | void Put(Ch c); 54 | 55 | //! Flush the buffer. 56 | void Flush(); 57 | 58 | //! End the writing operation. 59 | //! \param begin The begin write pointer returned by PutBegin(). 60 | //! \return Number of characters written. 61 | size_t PutEnd(Ch* begin); 62 | } 63 | \endcode 64 | */ 65 | 66 | //! Provides additional information for stream. 67 | /*! 68 | By using traits pattern, this type provides a default configuration for stream. 69 | For custom stream, this type can be specialized for other configuration. 70 | See TEST(Reader, CustomStringStream) in readertest.cpp for example. 71 | */ 72 | template 73 | struct StreamTraits { 74 | //! Whether to make local copy of stream for optimization during parsing. 75 | /*! 76 | By default, for safety, streams do not use local copy optimization. 77 | Stream that can be copied fast should specialize this, like StreamTraits. 78 | */ 79 | enum { copyOptimization = 0 }; 80 | }; 81 | 82 | //! Reserve n characters for writing to a stream. 83 | template 84 | inline void PutReserve(Stream& stream, size_t count) { 85 | (void)stream; 86 | (void)count; 87 | } 88 | 89 | //! Write character to a stream, presuming buffer is reserved. 90 | template 91 | inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { 92 | stream.Put(c); 93 | } 94 | 95 | //! Put N copies of a character to a stream. 96 | template 97 | inline void PutN(Stream& stream, Ch c, size_t n) { 98 | PutReserve(stream, n); 99 | for (size_t i = 0; i < n; i++) 100 | PutUnsafe(stream, c); 101 | } 102 | 103 | /////////////////////////////////////////////////////////////////////////////// 104 | // GenericStreamWrapper 105 | 106 | //! A Stream Wrapper 107 | /*! \tThis string stream is a wrapper for any stream by just forwarding any 108 | \treceived message to the origin stream. 109 | \note implements Stream concept 110 | */ 111 | 112 | #if defined(_MSC_VER) && _MSC_VER <= 1800 113 | RAPIDJSON_DIAG_PUSH 114 | RAPIDJSON_DIAG_OFF(4702) // unreachable code 115 | RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated 116 | #endif 117 | 118 | template > 119 | class GenericStreamWrapper { 120 | public: 121 | typedef typename Encoding::Ch Ch; 122 | GenericStreamWrapper(InputStream& is) : is_(is) {} 123 | 124 | Ch Peek() const { return is_.Peek(); } 125 | Ch Take() { return is_.Take(); } 126 | size_t Tell() { return is_.Tell(); } 127 | Ch* PutBegin() { return is_.PutBegin(); } 128 | void Put(Ch ch) { is_.Put(ch); } 129 | void Flush() { is_.Flush(); } 130 | size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } 131 | 132 | // wrapper for MemoryStream 133 | const Ch* Peek4() const { return is_.Peek4(); } 134 | 135 | // wrapper for AutoUTFInputStream 136 | UTFType GetType() const { return is_.GetType(); } 137 | bool HasBOM() const { return is_.HasBOM(); } 138 | 139 | protected: 140 | InputStream& is_; 141 | }; 142 | 143 | #if defined(_MSC_VER) && _MSC_VER <= 1800 144 | RAPIDJSON_DIAG_POP 145 | #endif 146 | 147 | /////////////////////////////////////////////////////////////////////////////// 148 | // StringStream 149 | 150 | //! Read-only string stream. 151 | /*! \note implements Stream concept 152 | */ 153 | template 154 | struct GenericStringStream { 155 | typedef typename Encoding::Ch Ch; 156 | 157 | GenericStringStream(const Ch* src) : src_(src), head_(src) {} 158 | 159 | Ch Peek() const { return *src_; } 160 | Ch Take() { return *src_++; } 161 | size_t Tell() const { return static_cast(src_ - head_); } 162 | 163 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 164 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 165 | void Flush() { RAPIDJSON_ASSERT(false); } 166 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 167 | 168 | const Ch* src_; //!< Current read position. 169 | const Ch* head_; //!< Original head of the string. 170 | }; 171 | 172 | template 173 | struct StreamTraits > { 174 | enum { copyOptimization = 1 }; 175 | }; 176 | 177 | //! String stream with UTF8 encoding. 178 | typedef GenericStringStream > StringStream; 179 | 180 | /////////////////////////////////////////////////////////////////////////////// 181 | // InsituStringStream 182 | 183 | //! A read-write string stream. 184 | /*! This string stream is particularly designed for in-situ parsing. 185 | \note implements Stream concept 186 | */ 187 | template 188 | struct GenericInsituStringStream { 189 | typedef typename Encoding::Ch Ch; 190 | 191 | GenericInsituStringStream(Ch* src) : src_(src), dst_(0), head_(src) {} 192 | 193 | // Read 194 | Ch Peek() { return *src_; } 195 | Ch Take() { return *src_++; } 196 | size_t Tell() { return static_cast(src_ - head_); } 197 | 198 | // Write 199 | void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } 200 | 201 | Ch* PutBegin() { return dst_ = src_; } 202 | size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } 203 | void Flush() {} 204 | 205 | Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } 206 | void Pop(size_t count) { dst_ -= count; } 207 | 208 | Ch* src_; 209 | Ch* dst_; 210 | Ch* head_; 211 | }; 212 | 213 | template 214 | struct StreamTraits > { 215 | enum { copyOptimization = 1 }; 216 | }; 217 | 218 | //! Insitu string stream with UTF8 encoding. 219 | typedef GenericInsituStringStream > InsituStringStream; 220 | 221 | RAPIDJSON_NAMESPACE_END 222 | 223 | #endif // RAPIDJSON_STREAM_H_ 224 | -------------------------------------------------------------------------------- /src/rapidjson/stringbuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_STRINGBUFFER_H_ 16 | #define RAPIDJSON_STRINGBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 22 | #include // std::move 23 | #endif 24 | 25 | #include "internal/stack.h" 26 | 27 | #if defined(__clang__) 28 | RAPIDJSON_DIAG_PUSH 29 | RAPIDJSON_DIAG_OFF(c++98 - compat) 30 | #endif 31 | 32 | RAPIDJSON_NAMESPACE_BEGIN 33 | 34 | //! Represents an in-memory output stream. 35 | /*! 36 | \tparam Encoding Encoding of the stream. 37 | \tparam Allocator type for allocating memory buffer. 38 | \note implements Stream concept 39 | */ 40 | template 41 | class GenericStringBuffer { 42 | public: 43 | typedef typename Encoding::Ch Ch; 44 | 45 | GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 46 | 47 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 48 | GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} 49 | GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { 50 | if (&rhs != this) 51 | stack_ = std::move(rhs.stack_); 52 | return *this; 53 | } 54 | #endif 55 | 56 | void Put(Ch c) { *stack_.template Push() = c; } 57 | void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } 58 | void Flush() {} 59 | 60 | void Clear() { stack_.Clear(); } 61 | void ShrinkToFit() { 62 | // Push and pop a null terminator. This is safe. 63 | *stack_.template Push() = '\0'; 64 | stack_.ShrinkToFit(); 65 | stack_.template Pop(1); 66 | } 67 | 68 | void Reserve(size_t count) { stack_.template Reserve(count); } 69 | Ch* Push(size_t count) { return stack_.template Push(count); } 70 | Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } 71 | void Pop(size_t count) { stack_.template Pop(count); } 72 | 73 | const Ch* GetString() const { 74 | // Push and pop a null terminator. This is safe. 75 | *stack_.template Push() = '\0'; 76 | stack_.template Pop(1); 77 | 78 | return stack_.template Bottom(); 79 | } 80 | 81 | //! Get the size of string in bytes in the string buffer. 82 | size_t GetSize() const { return stack_.GetSize(); } 83 | 84 | //! Get the length of string in Ch in the string buffer. 85 | size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } 86 | 87 | static const size_t kDefaultCapacity = 256; 88 | mutable internal::Stack stack_; 89 | 90 | private: 91 | // Prohibit copy constructor & assignment operator. 92 | GenericStringBuffer(const GenericStringBuffer&); 93 | GenericStringBuffer& operator=(const GenericStringBuffer&); 94 | }; 95 | 96 | //! String buffer with UTF8 encoding 97 | typedef GenericStringBuffer > StringBuffer; 98 | 99 | template 100 | inline void PutReserve(GenericStringBuffer& stream, size_t count) { 101 | stream.Reserve(count); 102 | } 103 | 104 | template 105 | inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { 106 | stream.PutUnsafe(c); 107 | } 108 | 109 | //! Implement specialized version of PutN() with memset() for better performance. 110 | template<> 111 | inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { 112 | std::memset(stream.stack_.Push(n), c, n * sizeof(c)); 113 | } 114 | 115 | RAPIDJSON_NAMESPACE_END 116 | 117 | #if defined(__clang__) 118 | RAPIDJSON_DIAG_POP 119 | #endif 120 | 121 | #endif // RAPIDJSON_STRINGBUFFER_H_ 122 | --------------------------------------------------------------------------------