http客户端-基于boost开发
http客户端-基于boost开发
基于BOOST编写的http客户端,作为BOOST开发学习之用。目前支持功能:
- http协议,单向链接返回http response code 200
- 可content type 为text或image下载到本地
- 仅支持http返回code为200,不支持3XX、4XX等
- 暂不支持chunk传输,chunk代码待调试
- 日志文件,提供类ACE的输出方式,如LOG((LOG_DEBUG,"[%T(%t)] test begin %d %s\n"), int_num_2, string_test.c_str());
- 数据缓冲区,当前为new方式,后续可更改为从boost pool获取
- 。。。
1 类关系图
2 核心代码
2.1 IOServer,提供asio线程环境
1 #pragma once 2 #include "boost/serialization/singleton.hpp" 3 #include "boost/asio.hpp" 4 #include "boost/thread.hpp" 5 #include "boost/bind.hpp" 6 #include "Event.h" 7 #include "../concurrent/IRunable.h" 8 #include "SimpleLog.h" 9 class IO_Server : public IRunable 10 { 11 public: 12 IO_Server(): bExit(false) 13 { 14 } 15 boost::asio::io_service* GetIOS() 16 { 17 return &ios; 18 } 19 void ActiveIOS() 20 { 21 boost::unique_lock<boost::mutex> lock(mu); 22 if (ios.stopped()) 23 { 24 cond.notify_one(); 25 } 26 } 27 void Exit() 28 { 29 ios.stop(); 30 bExit = true; 31 } 32 private: 33 virtual int Run() 34 { 35 LOG((LOG_DEBUG,"[%T(%t)] ios server run ,id = %d\n", boost::this_thread::get_id())); 36 ios.stop(); 37 while (1) 38 { 39 // 设置退出线程 40 if (bExit) 41 { 42 break; 43 } 44 // 45 { 46 boost::unique_lock<boost::mutex> lock(mu); 47 if (ios.stopped()) 48 { 49 cond.wait(mu); 50 } 51 } 52 if (ios.stopped()) 53 { 54 ios.reset(); 55 ios.run(); 56 } 57 } 58 return 0; 59 } 60 private: 61 boost::asio::io_service ios; //所有的asio都要有个ios 62 boost::mutex mu; 63 boost::condition_variable_any cond; 64 bool bExit; 65 }; 66 typedef boost::serialization::singleton<IO_Server> IOS;
2.2 task及sock资源管理器
1 #pragma once 2 #include "ios.h" 3 #include "handle.h" 4 #include "ios.h" 5 #include "SimpleLog.h" 6 #include "../concurrent/ThreadPool.h" 7 #include "../concurrent/IRunable.h" 8 #include "MsgQueue.h" 9 /************************************************************************/ 10 /* Handle的集合.多线程共享 */ 11 /************************************************************************/ 12 typedef boost::shared_ptr<IRunable> IRunablePtr; 13 typedef CMsgQueue<IRunablePtr> IRunPtrQueue; 14 template<class CLIENT> 15 class HandleSet : public IRunable 16 { 17 public: 18 HandleSet() 19 { 20 bExit = false; 21 nHighWaterMark = 5; 22 nClientUsed = 0; 23 24 m_poThreadPool = boost::shared_ptr<ThreadPool>(new ThreadPool("HandleSet_Pool", 1, boost::thread::hardware_concurrency())); 25 //启动ioserver线程 26 IO_Server& ioserver = IOS::get_mutable_instance(); 27 m_poThreadPool->Start(&ioserver); 28 //启动 29 m_poThreadPool->Start(this); 30 } 31 ~HandleSet(){} 32 //加入一个task 33 void AddTask(TaskPtr task) 34 { 35 boost::unique_lock<boost::mutex> lock(mu); 36 ClientHandlePtr client; 37 if (!GetFreeClient(client)) 38 { 39 tasks.push_back(task); 40 return; 41 } 42 client->Busy(true); 43 client->HTTP_Connect(task); 44 InterlockedIncrement(&nClientUsed); 45 IOS::get_mutable_instance().ActiveIOS(); 46 } 47 48 //设置client水位标 49 void HighWaterMark(int mark) 50 { 51 nHighWaterMark = mark; 52 } 53 54 void NotifyComplete(ClientHandle* client, const boost::system::error_code& ec, 55 CMsgBlock& msg) 56 { 57 switch (ec.value()) 58 { 59 case 0: //正常退出 60 { 61 boost::unique_lock<boost::mutex> lock(mu); 62 client->pTask->Finish(SUCCESS, msg); 63 client->Busy(false); 64 client->Reset(); 65 InterlockedDecrement(&nClientUsed); 66 } 67 break; 68 case 2: //远端关闭连接 69 { 70 71 } 72 break; 73 } 74 } 75 private: 76 //找出一个空闲的client 77 bool GetFreeClient(ClientHandlePtr& ptr) 78 { 79 if (clients.size() >= nHighWaterMark && nClientUsed >= nHighWaterMark) 80 { 81 return false; 82 } 83 //空队列,创建一个新的 84 if (clients.empty()) 85 { 86 ptr = CreateNewHandle(); 87 clients.push_back(ptr); 88 return true; 89 } 90 //非空则找出一个空闲 91 LiClientHandlePtr::iterator iter = clients.begin(); 92 for ( ;iter != clients.end(); iter++) 93 { 94 ClientHandlePtr client = *iter; 95 if (!client->Busy()) 96 { 97 ptr = client; 98 return true; 99 } 100 } 101 //无空闲且饱和 102 if (nClientUsed < nHighWaterMark) 103 { 104 ptr = CreateNewHandle(); 105 clients.push_back(ptr); 106 return true; 107 } 108 return false; 109 } 110 ClientHandlePtr CreateNewHandle() 111 { 112 return ClientHandlePtr( 113 new CLIENT(IOS::get_mutable_instance().GetIOS(), boost::bind(&HandleSet::NotifyComplete, this, _1, _2, _3))); 114 } 115 private: 116 virtual int Run() 117 { 118 LOG((LOG_DEBUG,"[%T(%t)] handleSet %s thread run\n", typeid(this).name())); 119 while (1) 120 { 121 // 设置退出线程 122 if (bExit) 123 { 124 break; 125 } 126 { 127 boost::unique_lock<boost::mutex> lock(mu); 128 if (!tasks.empty()) 129 { 130 ClientHandlePtr client; 131 if (GetFreeClient(client)) 132 { 133 TaskPtr task = tasks.front(); 134 tasks.pop_front(); 135 client->Busy(true); 136 client->HTTP_Connect(task); 137 InterlockedIncrement(&nClientUsed); 138 } 139 IOS::get_mutable_instance().ActiveIOS(); 140 } 141 } 142 boost::this_thread::sleep_for(boost::chrono::milliseconds(10)); 143 144 //线程池模式 145 /*if (queue.empty()) 146 { 147 boost::this_thread::sleep_for(boost::chrono::milliseconds(20)); 148 continue; 149 } 150 151 IRunablePtr ptrTask; 152 queue.dequeue_head(ptrTask, 10); 153 154 if (ptrTask) 155 { 156 m_poThreadPool->Start(ptrTask); 157 }*/ 158 } 159 return 0; 160 } 161 private: 162 int nHighWaterMark; //并发执行数量为1--nHighWaterMark 163 LiClientHandlePtr clients; 164 165 TaskPtrList tasks; 166 long nClientUsed; 167 bool bExit; 168 boost::mutex mu; 169 170 boost::shared_ptr<ThreadPool> m_poThreadPool; ///<线程池共享指针 171 IRunPtrQueue queue; 172 };
2.3 socket工厂模式虚接口,供资源管理器调用
1 #pragma once 2 /************************************************************************/ 3 /* 提供网络行为 */ 4 /************************************************************************/ 5 #include <string> 6 #include "boost/smart_ptr.hpp" 7 #include "boost/asio.hpp" 8 #include "boost/date_time/posix_time/posix_time.hpp" 9 #include "boost/thread.hpp" 10 #include "MsgBlock.h" 11 #include "SimpleLog.h" 12 #include "userTask.h" 13 using namespace boost; 14 using namespace boost::asio; 15 using namespace std; 16 17 class ClientHandle; 18 typedef boost::shared_ptr<ip::tcp::socket> sock_ptr; 19 typedef boost::shared_ptr<ClientHandle> ClientHandlePtr; 20 typedef std::list<ClientHandlePtr> LiClientHandlePtr; 21 22 typedef boost::function<void(ClientHandle* handle, 23 const boost::system::error_code& ec, CMsgBlock&)> NotifyCompleteFunc; 24 25 class ClientHandle 26 { 27 public: 28 ClientHandle(boost::asio::io_service* ios, NotifyCompleteFunc completeFun); 29 ~ClientHandle(); 30 public: //主动请求 31 void HTTP_Connect(TaskPtr task); 32 //http send请求 33 void HTTP_Send(CMsgBlock& block); 34 //http close 35 void HTTP_Close(); 36 //http recv,接收到数据后回调 37 void HTTP_Recv(); 38 bool Busy(); 39 void Busy(bool busy); 40 void Reset(); 41 public: //回调函数 42 //http send,接收到数据后回调 43 virtual void CB_Send(const boost::system::error_code& ec, size_t len) = 0; 44 //http recv,接收到数据后回调 45 virtual void CB_Recv(const boost::system::error_code& ec, size_t len) = 0; 46 //http connect result,连接结果回调 47 virtual void CB_HTTP_Connect_Result(const boost::system::error_code& ec) = 0; 48 //http result, 返回错误码及第一次数据 49 virtual int CB_HTTP_CODE(int retCode, CMsgBlock& block) = 0; 50 //连接超时 51 virtual void CB_HTTP_Timeout() = 0; 52 //对端关闭连接 53 virtual void CB_Remote_Close() = 0; 54 public: 55 TaskPtr pTask; 56 protected: 57 //写缓冲区和写指针 58 CMsgBlock _rdBuf; 59 CMsgBlock _wrBuf; 60 DWORD lastDataTime; //活动时间 61 long recvSz; //累计接收数据量 62 //记录任务 63 sock_ptr sock; 64 boost::asio::ip::tcp::endpoint ep; 65 bool bBusy; 66 NotifyCompleteFunc _completeFun; 67 };
2.4 socket管理实例
1 //http recv,接收到数据后回调 2 void ITsoftware_Index::CB_Send(const boost::system::error_code& ec, size_t len) 3 { 4 if (ec) 5 { 6 //错误,调用返回 7 return; 8 } 9 if (len == _wrBuf.Size()) 10 { 11 _rdBuf.Reset(); 12 sock->async_read_some(boost::asio::buffer(_rdBuf.Base() + _rdBuf.WtPtr(), _rdBuf.Space()), 13 bind(&ClientHandle::CB_Recv, this, _1, _2)); 14 } 15 else 16 { 17 sock->async_write_some(boost::asio::buffer(_wrBuf.Base() + len, _wrBuf.Size() - len), 18 bind(&ClientHandle::CB_Send, this, _1, _2)); 19 } 20 } 21 22 //http recv,接收到数据后回调 23 void ITsoftware_Index::CB_Recv(const boost::system::error_code& ec, size_t len) 24 { 25 if (ec || !pTask) 26 { 27 return; 28 } 29 recvSz += len; 30 _rdBuf.WtPtr(len); 31 32 bool bLastData = (_rdBuf.Space() > 0)? true : false; //缓冲区未接收满,说明当前数据已经收完 33 34 int ret = 0; 35 if (!pTask->_head.bReady) 36 { 37 ret = ParseHead(_rdBuf); 38 if (ret == 0) //头未收完,继续接收 39 { 40 sock->async_read_some(boost::asio::buffer(_rdBuf.Base() + _rdBuf.WtPtr(), _rdBuf.Space()), 41 bind(&ClientHandle::CB_Recv, this, _1, _2)); 42 return; 43 } 44 // 返回为http的代码 45 ret = CB_HTTP_CODE(ret, _rdBuf); 46 } 47 48 switch (ret) 49 { 50 case -1: 51 { 52 sock->shutdown(ip::tcp::socket::shutdown_both); 53 sock->close(); 54 _completeFun(this, ec, parseOnlineBlock); 55 parseOnlineBlock.Reset(); 56 } 57 break; 58 case 0: 59 { 60 int retWriteData = 0; 61 if (_rdBuf.Size() > 0) 62 { 63 retWriteData = WriteData(_rdBuf); //处理数据流 64 } 65 _rdBuf.Reset(); 66 if (retWriteData == -1) 67 { 68 sock->shutdown(ip::tcp::socket::shutdown_both); 69 sock->close(); 70 _completeFun(this, ec, parseOnlineBlock); 71 parseOnlineBlock.Reset(); 72 } 73 else 74 { 75 sock->async_read_some(boost::asio::buffer(_rdBuf.Base() + _rdBuf.WtPtr(), _rdBuf.Space()), 76 bind(&ClientHandle::CB_Recv, this, _1, _2)); 77 } 78 } 79 break; 80 case 1: 81 { 82 83 } 84 break; 85 } 86 } 87 //http connect result,连接结果回调 88 void ITsoftware_Index::CB_HTTP_Connect_Result(const boost::system::error_code& ec) 89 { 90 if (ec) 91 { 92 //错误,调用返回 93 return; 94 } 95 std::string getContent = "GET " + pTask->_info.URI + " HTTP/1.1\r\n"; 96 getContent += "Host: " + pTask->_info.host + "\r\n"; 97 getContent += "Connection: keep-alive\r\n"; 98 getContent += "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36\r\n"; 99 getContent += "Accept-Encoding: gzip, deflate\r\n"; 100 getContent += "Accept-Language: zh-CN,zh;q=0.8\r\n\r\n"; 101 102 _wrBuf.Reset(); 103 _wrBuf.Write(getContent.c_str(), getContent.length()); 104 HTTP_Send(_wrBuf); 105 } 106 107 //http recv,收到全部数据后回调,httpcode=200 108 int ITsoftware_Index::CB_HTTP_CODE(int retCode, CMsgBlock& block) 109 { 110 int ret = 0; 111 //准备文件及缓冲区 112 if (retCode == 200) 113 { 114 if (pTask->HasFlag(CONTENT_TYPE_DOWNLOAD)) //开启下载 115 { 116 if (pTask->_head.nContentType == CONTENT_TYPE_IMAGE || 117 pTask->_head.nContentType == CONTENT_TYPE_TEXT) 118 { 119 char sss[100] = {0}; 120 sprintf_s(sss, 100, "%d", InterlockedIncrement(&filenameprev)); 121 pTask->FilePtr(std::string(sss) + pTask->_info.lastName); //创建文件 122 if (!pTask->FilePtr()) //文件创建失败,则接收失败 123 { 124 ret = -1; 125 //LOG((LOG_DEBUG,"[%T(%t)] create file failed, %s \n", pTask->_url.c_str())); 126 } 127 } 128 } 129 if (pTask->HasFlag(CONTENT_TYPE_PARSEONLINE)) //调用完成后回传给task 130 { 131 if (pTask->_head.bContentLength) 132 { 133 parseOnlineBlock.Capacity(pTask->_head.nContentLength); 134 } 135 else if (pTask->_head.bChunked) 136 { 137 parseOnlineBlock.Capacity(block.Capacity() * 2); 138 } 139 if (parseOnlineBlock.Capacity() == 0) 140 { 141 ret = -1; 142 //LOG((LOG_DEBUG,"[%T(%t)] create parseOnlineBlock buffer failed, %s \n", pTask->_url.c_str())); 143 } 144 } 145 } 146 //重定向 147 else if (300 < retCode && retCode < 399) 148 { 149 ret = -1; //中断当前 150 } 151 return ret; 152 } 153 154 //连接超时 155 void ITsoftware_Index::CB_HTTP_Timeout() 156 { 157 158 } 159 //对端关闭连接 160 void ITsoftware_Index::CB_Remote_Close() 161 { 162 163 } 164 165 int ITsoftware_Index::ParseHead(CMsgBlock& _block) 166 { 167 int ret = 0; 168 int rnrn = Tools::KMPFind(_block.Base(), _block.Size(), RNRN, RNRN_SIZE); 169 if (rnrn != -1) 170 { 171 //头收完全,处理http头 172 char* cRnrn = new char[rnrn + 1 + 2]; 173 ZeroMemory(cRnrn,rnrn+1); 174 memcpy(cRnrn, _block.Base(), rnrn + 2); 175 if (pTask->_head.ParseHead(cRnrn )) 176 { 177 pTask->_head.bReady = true; 178 //数据移位,把头去掉,保证缓冲区内都是数据体 179 int remain = _block.Size() - rnrn -4; //剩余长度 180 char* remain_begin_pos = _block.Base() + rnrn + 4; 181 _block.Reset(); //读写指针置零 182 _block.Write(remain_begin_pos, remain); //重新写入 183 ret = pTask->_head.code; 184 } 185 else //文件头出错,关闭连接 186 { 187 ret = -1; 188 //LOG((LOG_DEBUG,"[%T(%t)] recv http head parse error, %s\n, %s \n", pTask->_url.c_str() ,cRnrn)); 189 } 190 delete cRnrn; 191 } 192 else 193 { 194 //没有收到\r\n\r\n,则表明头还没收完全 195 ret = 0; 196 } 197 return ret; 198 } 199 200 int ITsoftware_Index::WriteData(CMsgBlock& _block) 201 { 202 int ret = 0; 203 if(pTask->_head.bContentLength) 204 { 205 if (pTask->HasFlag(CONTENT_TYPE_DOWNLOAD) && 206 (pTask->_head.nContentType == CONTENT_TYPE_IMAGE || pTask->_head.nContentType == CONTENT_TYPE_TEXT)) 207 { 208 if (!pTask->FilePtr()->bad()) 209 { 210 pTask->FilePtr()->write(_block.Base(), _block.Size()); 211 } 212 } 213 if (pTask->HasFlag(CONTENT_TYPE_PARSEONLINE)) 214 { 215 parseOnlineBlock.Write(_block.Base(), _block.Size()); 216 } 217 if (recvSz >= pTask->_head.nContentLength) 218 { 219 if (pTask->HasFlag(CONTENT_TYPE_DOWNLOAD) && 220 (pTask->_head.nContentType == CONTENT_TYPE_IMAGE || pTask->_head.nContentType == CONTENT_TYPE_TEXT)) 221 { 222 pTask->FilePtr()->close(); 223 } 224 ret = -1; 225 } 226 } 227 else if (pTask->_head.bChunked) 228 { 229 // //chunk,通过辨识末尾7位是否是HTTP_END,来判断数据是否已接收完整 230 // if(_block.RdPtr() > HTTP_END_SIZE) 231 // { 232 // char cend[HTTP_END_SIZE+1]= {0}; 233 // memcpy(cend, _block.Base() + _block.Size() - 7, HTTP_END_SIZE); 234 // int cmp = strcmp(cend,HTTP_END); 235 // if (cmp != 0) 236 // { 237 // //未接收完整,继续接收 238 // return 0; 239 // } 240 // } 241 // //数据接收完全,把chunk的长度字符全部删除 242 // int beginPos = rnrn + 4; 243 // while (true) 244 // { 245 // int rnBegin = Tools::KMPFind(_block.Base(), _block.Size(), RN, RN_SIZE, beginPos); 246 // if (rnBegin != -1) 247 // { 248 // char* tets = _block.Base() + rnBegin; 249 // //计算出chunk的长度 250 // char* cchunk = new char[rnBegin - rnrn - 4 + 1]; 251 // ZeroMemory(cchunk, rnBegin - rnrn - 4 + 1); 252 // memcpy(cchunk, _block.Base() + rnrn + 4, rnBegin - rnrn - 4); 253 // int chunk = strtol(cchunk,NULL,16); 254 // delete cchunk; 255 // if (chunk ==0) 256 // break; 257 // //copy chunck的字节到body 258 // result.Write(_block.Base() + rnBegin + RN_SIZE, chunk); 259 // beginPos = rnBegin + chunk+RN_SIZE*2; 260 // } 261 // else 262 // break; 263 } 264 return ret; 265 }
2.5 下发任务
1 #pragma once 2 #include <string> 3 #include "boost/bind.hpp" 4 #include "boost/function.hpp" 5 #include "boost/smart_ptr.hpp" 6 #include "SimpleLog.h" 7 #include "MsgBlock.h" 8 #include "httphead.h" 9 #include "Tools.h" 10 using namespace std; 11 class Task; 12 13 enum NotifyType{ 14 SUCCESS, 15 FAILED 16 }; 17 18 typedef boost::function<void(NotifyType,const std::string&)> NotifyFunc; 19 typedef boost::shared_ptr<Task> TaskPtr; 20 typedef std::list<TaskPtr> TaskPtrList; 21 22 class Task 23 { 24 public: 25 static TaskPtr CreateTask(std::string url, long flag = CONTENT_TYPE_NONE, std::string downPath = "") 26 { 27 return boost::shared_ptr<Task>(new Task(url, flag, downPath)); 28 } 29 public: 30 virtual ~Task() 31 { 32 if (_file) 33 { 34 _file->close(); 35 } 36 } 37 virtual void Finish(NotifyType type, CMsgBlock& retMsg) 38 { 39 LOG((LOG_DEBUG, "[%T(%t)] NotifyComplete %d, %s \n", type, _url.c_str())); 40 // if (type == SUCCESS) 41 // { 42 // std::vector<std::string> vecs; 43 // Tools::HttpStringOpt::ExtractAllUrl(std::string(result.Base(), result.Size()), vecs); 44 // } 45 } 46 inline ofstreamPtr FilePtr() 47 { 48 return _file; 49 } 50 inline void FilePtr(std::string filename) 51 { 52 if (_file) 53 { 54 _file->close(); 55 } 56 std::string filepath = _downloadPath + std::string("/") + filename; 57 ofstreamPtr ptr = Tools::GetNewFile(filepath); 58 _file.swap(ptr); 59 } 60 Task(const Task& t) 61 { 62 _url = t._url; 63 } 64 Task* operator= (const Task& t) 65 { 66 _url = t._url; 67 } 68 inline bool HasFlag(long flag) 69 { 70 return flag & _flag; 71 } 72 private: 73 Task(std::string url, long flag, std::string downPath) 74 :_url(url), 75 _flag(flag), 76 _downloadPath(downPath) 77 { 78 _head.Reset(); 79 Tools::HttpStringOpt::SpliterHttpUrl(_url, _info); 80 } 81 public: 82 std::string _url; 83 long _flag; 84 HttpHead _head; 85 std::string _downloadPath; //下载目录 86 UrlInfo _info; 87 private: 88 ofstreamPtr _file; 89 };
2.5 缓冲数据块
1 #pragma once 2 #include "boost/smart_ptr.hpp" 3 #ifndef DEFAULT_BUF_SIZE 4 #define DEFAULT_BUF_SIZE 1024 5 #endif 6 class CMsgBlock; 7 typedef boost::shared_ptr<CMsgBlock> MsgBlockPtr; 8 9 /************************************************************************/ 10 /* 简易数据缓冲区 */ 11 /************************************************************************/ 12 class CMsgBlock 13 { 14 public: 15 CMsgBlock(){ 16 Reset(); 17 _block = NULL; 18 _capacity = 0; 19 } 20 CMsgBlock(int sz){ 21 Reset(); 22 _block = NULL; 23 _capacity = 0; 24 Capacity(sz); 25 } 26 ~CMsgBlock(){ 27 if (_block != NULL) 28 { 29 delete [] _block; 30 _block = NULL; 31 } 32 } 33 //重置缓冲区,仅移动指针 34 void Reset() 35 { 36 _rdPrt = 0; 37 _wrPtr = 0; 38 } 39 //获取数据块大小 40 int Size() 41 { 42 return _wrPtr - _rdPrt; 43 } 44 //获取缓冲区容量 45 int Capacity() 46 { 47 return _capacity; 48 } 49 //获取剩余空间 50 int Space() 51 { 52 return _capacity - _wrPtr; 53 } 54 // 获取基址 55 char* Base() 56 { 57 return _block; 58 } 59 //读地址 60 int RdPtr() 61 { 62 return _rdPrt; 63 } 64 void RdPtr(int ptr) 65 { 66 _rdPrt += ptr; 67 } 68 //写地址 69 int WtPtr() 70 { 71 return _wrPtr; 72 } 73 void WtPtr(int ptr) 74 { 75 _wrPtr += ptr; 76 } 77 //重置缓冲区大小 78 bool Capacity(int sz) 79 { 80 if (_capacity >= sz) 81 return true; 82 else 83 { 84 char* temp = new char[sz]; 85 if (temp == NULL) 86 return false; 87 if (_block) 88 { 89 memcpy(temp,_block,_capacity); 90 delete [] _block; 91 } 92 _block = temp; 93 _capacity = sz; 94 } 95 return true; 96 } 97 //写缓冲区 98 bool Write(const char* buf,int leng) 99 { 100 //缓冲区可写区域不足 101 if (Space() < leng) 102 { 103 //重置缓冲区 104 if (!Capacity(_capacity + 2*leng + DEFAULT_BUF_SIZE )) 105 return false; 106 } 107 memcpy(_block + _wrPtr,buf,leng); 108 _wrPtr += leng; 109 return true; 110 } 111 void Copy(CMsgBlock* block) 112 { 113 if (block != this) 114 { 115 this->Reset(); 116 this->Write(block->Base(),block->Size()); 117 } 118 } 119 void Copy(CMsgBlock& block) 120 { 121 Copy(&block); 122 } 123 private: 124 char* _block; //数据块 125 unsigned int _rdPrt; //读指针 126 unsigned int _wrPtr; //写指针 127 unsigned int _capacity; //容量 128 };
2.6 日志输出
1 //输出日志 2 void Log(LogType type,const char *format_str, ...) 3 { 4 5 //调整缓冲区 6 _block.Reset(); 7 8 va_list argp; 9 va_start (argp, format_str); 10 while (*format_str != '\0') 11 { 12 if (*format_str != '%') 13 { 14 _block.Write(format_str,1); 15 } 16 else if (format_str[1] == '%') // An "escaped" '%' (just print one '%'). 17 { 18 format_str++; // Store first % 19 } 20 else 21 { 22 char format[128] = {0}; // 临时变量,保存%转换的临时结果 23 int len = 0; 24 format_str++; // Copy in the % 25 26 switch (*format_str) 27 { 28 case '-': case '+': case '0': case ' ': case '#': 29 case '1': case '2': case '3': case '4': case '5': 30 case '6': case '7': case '8': case '9': case '.': 31 case 'L': case 'h': 32 //*fp++ = *format_str; 33 break; 34 case 'l': // Source file line number 35 len = sprintf_s (format,128,"%d",__LINE__); 36 _block.Write(format,len); 37 break; 38 case 'N': // Source file name 39 len = sprintf_s (format,128,"%s",__FILE__); 40 _block.Write(format,len); 41 break; 42 case 'n': // Program name 43 len = sprintf_s (format,128,"%s","<unknown>"); 44 _block.Write(format,len); 45 break; 46 case 'P': // Process ID 47 len = sprintf_s (format,128,"%d", (int)getpid()); 48 _block.Write(format,len); 49 break; 50 case 'T': // Format the timestamp in hour:minute:sec:usec format. 51 { 52 std::string strColTime = Tools::GetCurrentTime(); 53 _block.Write(strColTime.c_str(), strColTime.length()); 54 } 55 break; 56 case 't': // Format thread id. 57 len = sprintf_s (format,128,"%d", boost::this_thread::get_id()); 58 _block.Write(format,len); 59 break; 60 case 's': 61 {// String 62 char *str1 = va_arg (argp, char *); 63 _block.Write(str1,strlen(str1)); 64 break; 65 } 66 case 'd': 67 case 'i': 68 case 'o': 69 case 'u': 70 case 'x': 71 case 'X': 72 len = sprintf_s (format,128,"%d",va_arg (argp, int)); 73 _block.Write(format,len); 74 break; 75 default: 76 _block.Write(format_str,1); 77 break; 78 } 79 } 80 ++format_str; 81 } 82 //末尾结束符号 83 char c('\0'); 84 _block.Write(&c,1); 85 //输出缓冲区 86 if (BIT_ENABLED (_flags,STDERR)) // This is taken care of by our caller. 87 { 88 int const fwrite_result = fprintf (stderr,"%s",_block.Base()); 89 ::fflush (stderr); 90 } 91 if (BIT_ENABLED (_flags,OSTREAM)) 92 { 93 if (_ostream != NULL) 94 { 95 *_ostream << _block.Base(); 96 _ostream->flush(); 97 } 98 } 99 va_end (argp); 100 }