程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 關於 Poco::TCPServer框架 (windows 下使用的是 select模型) 學習筆記.,pocotcpserver

關於 Poco::TCPServer框架 (windows 下使用的是 select模型) 學習筆記.,pocotcpserver

編輯:關於PHP編程

關於 Poco::TCPServer框架 (windows 下使用的是 select模型) 學習筆記.,pocotcpserver


 

說明

為何要寫這篇文章 ,之前看過阿二的夢想船的<Poco::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 <= 64,也就是說select只能同時管理最多64個連接

           是同步操作.

老陳非常想看到女兒的信。以至於他每隔10分鐘就下樓檢查信箱,看是否有女兒的信~~~~~
在這種情況下,"下樓檢查信箱"然後回到樓上耽誤了老陳太多的時間,以至於老陳無法做其他工作。
select模型和老陳的這種情況非常相似:周而復始地去檢查......如果有數據......接收/發送.......

.....
 MainSock := socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
 addr.sin_family := AF_INET;
 addr.sin_port := htons(5678);
 addr.sin_addr.S_addr := htonl(INADDR_ANY);
 bind( MainSock, @addr, sizeof(addr) );
 listen( MainSock, 5 );
 
 while (not Terminated) do
 begin
 FD_ZERO( fd_read );
 FD_SET( MainSock, fd_read );
 timeout.tv_sec := 0;
 timeout.tv_usec := 500;
 if select( 0, @fd_read, nil, nil, @timeout ) > 0 then //至少有1個等待Accept的connection
 begin
 if FD_ISSET( MainSock, fd_read ) then
 begin
 for i:=0 to fd_read.fd_count-1 do //注意,fd_count <= 64,也就是說select只能同時管理最多64個連接
 begin
 len := sizeof(addr);
 ASock := accept( MainSock, addr, len );
 if ASock <> INVALID_SOCKET then
 ....//為ASock創建一個新的線程,在新的線程中再不停地select
 end; 
 end; 
 end; 
 end; //while (not self.Terminated)
 
 shutdown( MainSock, SD_BOTH );
 closesocket( MainSock );
 end;

所以,select模型,只能用於一般的小型連接....高並發是不行的.

 

4,

對構造函數初始化順序的理解

C++構造函數按下列順序被調用:
(1)任何虛擬基類的構造函數按照它們被繼承的順序構造;
(2)任何非虛擬基類的構造函數按照它們被繼承的順序構造;
(3)任何成員對象的構造函數按照它們聲明的順序調用;
(4)類自己的構造函數。

 

5,關於 FastMutex 互斥變量

 

bool NotificationQueue::empty() const
{
FastMutex::ScopedLock lock(_mutex);
return _nfQueue.empty();
}

在 empty() 執行完成後 調用 ~FastMutex::ScopedLock析構函數來釋放.

window下是使用的臨界區:

class Foundation_API MutexImpl
{
protected:
MutexImpl();
~MutexImpl();
void lockImpl();
bool tryLockImpl();
bool tryLockImpl(long milliseconds);
void unlockImpl();

private:
CRITICAL_SECTION _cs;//臨界區
};

   可以看見,windows 下環境使用的臨界區.

 

6,關於線程:

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<ThreadImpl*>(pThread)->_pRunnableTarget->run();

//reinterpret_cas 這個轉換是最“不安全”的,兩個沒有任何關系的類指針之間轉換都可以用這個轉換實現,舉個例子

 

_threadId = static_cast<DWORD>(threadId);

//static_cast 用於基本的數據類型轉換(char,int),及指針之間的轉換

 

9,關於智能(靈巧)指針auto_ptr.

auto_ptr 簡單點說,就是 保證創建的資源 在退出時能被free(無論有沒有異常)

std::auto_ptr<TCPServerConnection> pConnection(_pConnectionFactory->createConnection(pCNf->socket()));

AutoPtr<Notification> pNf = _queue.waitDequeueNotification(idleTime);

可以直接 在<memory>中找到

template<class _Ty>
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<char>  pstr (new char[12] ); //數組;為定義
 
    記住不管什麼時候使用數組的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 這個參數管理 ,就不說了.你懂的.

7,NotificationQueue 把 連接 放入隊列.進行管理.

 

看完主要幾個類的介紹,其它流程都應該懂大概了.

 

流程圖:

由於圖太長的關系多,

圖片過寬,不能顯示(請 在新標簽中打開圖片.謝謝.)

先看看 PooledThread 的流程吧

 

 

 再看下TCPServer 主宰的流程
圖片過寬,不能顯示(請 在新標簽中打開圖片.謝謝.)

 

 

 

 

 

 

 

 

 

 

 

 

 

windows 下的select的確性能不太行,而linux 版本是用的epoll.

epoll相對select 要高效點.可參考:http://blog.csdn.net/legion8169/article/details/1637154

但poco tcpserver 中是有線程池操作的,所以說來效率不會太低.

 

 

 

先到這兒,還沒有寫完.

我們可以改變什麼:

    ThreadPool(int minCapacity = 2,
        int maxCapacity = 16,
        int idleTime = 60,
        int stackSize = POCO_THREAD_STACK_SIZE);
        /// Creates a thread pool with minCapacity threads.
        /// If required, up to maxCapacity threads are created
        /// a NoThreadAvailableException exception is thrown.
        /// If a thread is running idle for more than idleTime seconds,
        /// and more than minCapacity threads are running, the thread
        /// is killed. Threads are created with given stack size.

增加線程池中線程數(費話!),來加快select 中處理.

在中等程序中,增加  TCPSelect Manage進程,  來負責與多個  TcpServer 的進程通信.

即再增加一個管理者(中間鍵,或activemq之類),來加強並發能力,

或者直接使用linux 環境 ,即用了epoll 來實現高效性.

 

個人愚見,可能有些沒寫明白.還望高手指點.

謝謝.

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved