說明
為何要寫這篇文章 ,之前看過阿二的夢想船的<:tcpserver> http://www.cppblog.com/richbirdandy/archive/2010/09/10/123994.html
無奈程式碼太多,看起繁瑣.所以 準備 以流程圖簡化,便於理解.也方便自己以後使用.
本文內容 是基於window api分析的.
本文的poco是1.4.6p4 (2014-04-18)版本的. 雖然現在poco版本是1.6 但調用改動不大.
poco下載網址:http://pocoproject.org/releases/
本文分析以 TimeServer.cpp 作為入口分析:
關於開始前的了解:
1,Inline 內聯函數:可以參考:
http://blog.sina.com.cn/s/blog_90e888f50100zgo2.html
主要是提升執行效率.
2,類別成員函數的 重載,重寫,隱藏,
參考:
dazhong159 的
http://blog.csdn.net/dazhong159/article/details/7844369
3,select模型的原理:
引用
很幽默的解說六種Socket I/O模型
http://blog.csdn.net/normalnotebook/article/details/999840
的內容:
for i:=0 to fd_read.fd_count-1 do //注意,fd_count
是同步操作.
老陳非常想看到女兒的信。以至於他每隔10分鐘就下樓檢查信箱,看是否有女兒的信~~~~~
在這種情況下,"下樓檢查信箱"然後回到樓上耽誤了老陳太多的時間,以至於老陳無法做其他工作。
select模型和老陳的這種情況非常相似:周而復始地去檢查......如果有數據......接收/發送.......
<span>..... MainSock :</span>=<span> socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); addr.sin_family :</span>=<span> AF_INET; addr.sin_port :</span>= htons(<span>5678</span><span>); addr.sin_addr.S_addr :</span>=<span> htonl(INADDR_ANY); bind( MainSock, @addr, </span><span>sizeof</span><span>(addr) ); listen( MainSock, </span><span>5</span><span> ); </span><span>while</span> (not Terminated) <span>do</span><span> begin FD_ZERO( fd_read ); FD_SET( MainSock, fd_read ); timeout.tv_sec :</span>= <span>0</span><span>; timeout.tv_usec :</span>= <span>500</span><span>; </span><span>if</span> <span>select</span>( <span>0</span>, @fd_read, nil, nil, @timeout ) > <span>0</span> then <span>//</span><span>至少有1个等待Accept的connection</span> <span> begin </span><span>if</span><span> FD_ISSET( MainSock, fd_read ) then begin </span><span>for</span> i:=<span>0</span> to fd_read.fd_count-<span>1</span> <span>do</span> <span>//</span><span>注意,fd_count <= 64,也就是说select只能同时管理最多64个连接</span> <span> begin len :</span>= <span>sizeof</span><span>(addr); ASock :</span>=<span> accept( MainSock, addr, len ); </span><span>if</span> ASock <><span> INVALID_SOCKET then ....</span><span>//</span><span>为ASock创建一个新的线程,在新的线程中再不停地select</span> <span> end; end; end; end; </span><span>//</span><span>while (not self.Terminated)</span> <span> shutdown( MainSock, SD_BOTH ); closesocket( MainSock ); end;<br></span></span>
所以,select模型,只能用於一般的小型連接....高並發是不行的.
4,
對建構函式初始化順序的理解
C++建構函式按下列順序被呼叫:
(1)任何虛擬基底類別的建構子依照它們被繼承的順序建構;
(2)任何非虛擬基底類別的建構子依照它們被繼承的順序建構;
(4)類別自己的建構子。
5,關於 FastMutex 互斥變數
bool NotificationQueue::empty() const
{
FastMutex::ScopedLock lock(_mutex);
}
在 empty() 執行完成後 呼叫 ~FastMutex::ScopedLock析構函數來釋放.
window下是使用的臨界區:
class Foundation_API MutexImpl
{
protected:
MutexImpl();
~MutexImpl();
void lockImpl();
bool tryLockImpl();
private:
CRITICAL_SECTION _cs;//臨界區};
window下使用
_thread = (HANDLE) _beginthreadex(NULL, _stackSize, ent, this, 0, &threadId);
執行緒的操作.
7,等待事件,連線請求的同步是使用的
WaitForSingleObject(這也是我的最愛)
透過SetEvent () ,ResetEvent() 來啟動重置.
8,static_cast reinterpret_cast dynamic_cast 的使用.
可參考:
http://www.cnblogs.com/bastard/archive/2011/12/14/2288117.html
http://www.cnblogs.com/jerry19880126/archive/2012/08/14/2638192.html
像程式碼中:
void* pThread;
reinterpret_cast
//reinterpret_cas 這個轉換是最「不安全」的,兩個沒有任何關係的類別指標之間轉換都可以用這個轉換實現,舉個例子
_threadId = static_cast
//static_cast 用於基本的資料型別轉換(char,int),以及指標之間的轉換
9,關於智能(靈巧)指針auto_ptr.
auto_ptr 簡單點說,就是 保證創建的資源 在退出時能被free(無論有沒有異常)
std::auto_ptrAutoPtr
可以直接 在
template
class auto_ptr
{ // wrap an object pointer to ensure destruction
More Effective C++中文版.pdf 7.4 Item M28:靈巧(smart)指標 章節(baidu 查到下載)
http://blog.chinaunix.net/uid-9525959-id-2001803.html
中的片段:
如何避免使用auto_ptr的缺陷
auto_ptr并不是完美无缺的,它的确很方便,但也有缺陷,在使用时要注意避免。首先,不要将auto_ptr对象作为STL容器的元素。C++标准明确禁止这样做,否则可能会碰到不可预见的结果。
auto_ptr的另一个缺陷是将数组作为auto_ptr的参数:
auto_ptr
记住不管什么时候使用数组的new操作时,必须要用delete[]来摧毁数组。因为auto_ptr的析构函数只对非数组类型起作用。所以数组是不能被正确摧毁的话,程序的行为是不明确的。总之,auto_ptr控制一个由new分配的单对象指针,仅此而已。
不过C++ 11标准中解决了这问题:
unique_ptr
smart pointer with unique object ownership semantics
只能有一个主人的指针,可以用于STL容器
shared_ptr
smart pointer with shared object ownership semantics
可共享的指针
weak_ptr
weak reference to an object managed by std::shared_ptr
弱引用指针
auto_ptr
smart pointer with strict object ownership semantics
只能有一个主人的指针,不能用于STL容器
走远了,想深入(不要想多了-_- ),请baidu...
看完上面之些,发现是不是觉得 各种知识又巩固了.
所以还是要看开源代码,之前公司整死不用开源的...哎...
开始
代码中主要使用类的关系
图片过宽,不能显示(请 在新标签中打开图片.谢谢.)
主要的几个类:
1,TCPServer 主服务,负责 调用select 模型,来处理 连接消息的变化.
2,PooledThread 是线程池.当被激活时,调用 TCPServerDispatcher::run() 来处理收到包后的具体请求.而 TCPServerDispatcher::run() 中调用
TimeServerConnection.run(). TimeServerConnection.run()通过子类隐藏 来实现 程序员 自定义 功能. 不得不说写POCO的大牛利害.
3,TCPServerDispatcher,派遣管理者(先这么叫吧). 接收消息变化,放入队列.管理 连接数.
当放入队列时,会激活 PooledThread 中的事件 .
PooledThread 又反过来 激活 TCPServerDispatcher::run() [姑且叫 有条件时相互激活吧 ]
4,TCPServerConnection.实现具体行为,通过继承由子类的 run() 来自定义实现 功能.
5,TCPServerConnectionFactory 负责创建和管理 TCPServerConnection.
6,TCPServerParams 这个参数管理 ,就不说了.你懂的.
看完主要几个类的介绍,其它流程都应该懂大概了.
流程图:
由于图太长的关系多,
图片过宽,不能显示(请 在新标签中打开图片.谢谢.)
先看看 PooledThread 的流程吧
再看下TCPServer 主宰的流程
图片过宽,不能显示(请 在新标签中打开图片.谢谢.)
先到这儿,还没有写完.
我们可以改变什么:
ThreadPool(<span>int</span> minCapacity = <span>2</span><span>, </span><span>int</span> maxCapacity = <span>16</span><span>, </span><span>int</span> idleTime = <span>60</span><span>, </span><span>int</span> stackSize =<span> POCO_THREAD_STACK_SIZE); </span><span>///</span><span> Creates a thread pool with minCapacity threads. </span><span>///</span><span> If required, up to maxCapacity threads are created </span><span>///</span><span> a NoThreadAvailableException exception is thrown. </span><span>///</span><span> If a thread is running idle for more than idleTime seconds, </span><span>///</span><span> and more than minCapacity threads are running, the thread </span><span>///</span><span> is killed. Threads are created with given stack size.</span>
增加线程池中线程数(费话!),来加快select 中处理.
个人愚见,可能有些没写明白.还望高手指点.
谢谢.
以上就介绍了关于 Poco::TCPServer框架 (windows 下使用的是 select模型) 学习笔记.,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。