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;
View Code

 

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 };
View Code

 

 

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 };
View Code

 

 

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 }
View Code

 

 

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 };
View Code

 

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 };
View Code

 

 

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     }
View Code  

 

posted on 2018-07-13 14:54  炽离  阅读(3177)  评论(0编辑  收藏  举报

导航