ACE開發(fā)指南(初級(jí))_第1頁(yè)
ACE開發(fā)指南(初級(jí))_第2頁(yè)
ACE開發(fā)指南(初級(jí))_第3頁(yè)
ACE開發(fā)指南(初級(jí))_第4頁(yè)
ACE開發(fā)指南(初級(jí))_第5頁(yè)
已閱讀5頁(yè),還剩77頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

CJ-000032-RAS-001 開發(fā)指南MadebyExpertTeam上海超捷系統(tǒng)集成有限公司,199777/82 ACE開發(fā)指南(初級(jí))文檔信息作者鄭明智創(chuàng)建日期200版本1.0部門名稱開發(fā)部修訂文檔歷史記錄日期版本說明作者2001.0Reactor鄭明智2006-12-271.1增加Proactor的內(nèi)容鄭明智2006-12-281.2增加ACETask的內(nèi)容鄭明智

目錄1. 介紹 11.1 目的 11.2 文檔協(xié)定 11.3 閱讀者建議 11.4 術(shù)語(yǔ)說明 11.5 翻譯約定 21.6 相關(guān)資料 21.7 參考文獻(xiàn) 21.8 補(bǔ)充說明 22. ACE簡(jiǎn)介及環(huán)境搭建 32.1 ACE簡(jiǎn)介 32.2 本指南的主要內(nèi)容 32.3 獲取ACE 42.4 編譯ACE 42.4.1 為什么要編譯ACE 42.4.2 在Window上編譯 42.4.3 在Linux上編譯 52.5 前行的路標(biāo) 63. ACEReactor框架 63.1 Reactor(反應(yīng)器)框架 63.1.1 ACE_Event_Handler(事件處理器) 73.1.2 ACE_Reactor 93.2 Acceptor(接受器)-Connector(連接器)框架 113.2.1 ACE_Svc_Handler(服務(wù)處理器) 123.2.2 ACE_Acceptor 143.2.3 ACE_Connector 153.3 ACEReactorServer(Demo) 173.3.1 需求 173.3.2 實(shí)現(xiàn) 173.3.3 ACE工具類 253.3.4 Server改進(jìn) 263.4 ACEReactorClient(Demo) 293.4.1 需求 293.4.2 實(shí)現(xiàn)I 293.4.3 使用超時(shí)機(jī)制發(fā)送消息 333.4.4 實(shí)現(xiàn)II 333.5 前行的路標(biāo) 374. ACEProactor框架 384.1 Proactor(前攝器)框架 384.1.1 異步I/O工廠類 394.1.2 ACE_Handler(完成處理器) 414.1.3 ACE_Message_Block 424.1.4 ACE_Proactor 434.2 前攝式Acceptor-Connector框架 444.2.1 ACE_Service_Handler 454.2.2 ACE_Asynch_Acceptor 464.2.3 ACE_Asynch_Connector 464.3 既生Proactor,何生Reactor(二者的應(yīng)用范圍) 464.4 ACEProactorServer(Demo) 474.4.1 需求 474.4.2 實(shí)現(xiàn) 474.5 前行的路標(biāo) 545. ACETask框架 555.1 我們的新需求 555.2 Task(任務(wù))框架 555.3 ACE_Message_Queue 565.4 ACE_Task 595.5 Demo(ReactorClient的改寫) 615.5.1 需求 615.5.2 實(shí)現(xiàn) 615.6 基本的線程安全性 715.6.1 互斥體(Mutex) 715.6.2 守衛(wèi)(Guard) 755.7 前行的路標(biāo) 766. 總結(jié) 777. 常見問題 77CJ-000028-RAS-001 開發(fā)指南MadebyExpertTeam介紹目的本指南作為使用ACE框架開發(fā)應(yīng)用程序的參考,以期能夠?qū)κ褂肁CE框架的同事有所幫助。文檔協(xié)定本文檔的書寫遵循公司定義的文檔規(guī)范。本指南寫作時(shí),ACE最新的穩(wěn)定版本為5.5版。本指南中觀點(diǎn)和代碼并不保證適用于后續(xù)的ACE版本。本指南旨在幫助新手入門,如果您已對(duì)ACE有一定使用經(jīng)驗(yàn)并想更深入了解ACE,建議您閱讀ACE的相關(guān)書籍。閱讀者建議本指南假定閱讀者有C++的開發(fā)經(jīng)驗(yàn)和通信程序的開發(fā)經(jīng)驗(yàn),文檔中C++及Socket等開發(fā)知識(shí)及相關(guān)概念不再贅述。術(shù)語(yǔ)說明C/SClient/Server客戶端/服務(wù)器架構(gòu)Client客戶端Server服務(wù)器ACE自適配通信環(huán)境(AdaptiveCommunicationEnvironment)Reactor反應(yīng)器,高效的事件多路分離和分派提供可擴(kuò)展的面向?qū)ο罂蚣躊roactor前攝器aio異步I/OAsynchronousI/O異步I/OEpollLinux從2.6開始支持的異步事件I/O技術(shù)翻譯約定Method/Function方法NestedClass內(nèi)部類Callback回調(diào)HookMethod掛鉤方法Handle句柄Template模板Daemon守護(hù)Override/Overwrite覆蓋Overload重載相關(guān)資料ACE-5.5.zipMagicC++3.5參考文獻(xiàn)[1]ACE程序員指南–網(wǎng)絡(luò)與系統(tǒng)編程的實(shí)用設(shè)計(jì)模式[2]C++網(wǎng)絡(luò)編程(卷1)運(yùn)用ACE和模式消除復(fù)雜性[3]C++網(wǎng)絡(luò)編程(卷2)基于ACE和框架的系統(tǒng)化復(fù)用[4]ACE自適配通信環(huán)境中文技術(shù)文檔–中篇ACE程序員教程[5]ACEAPI列表[6]ACE源代碼補(bǔ)充說明[1]本文檔中提到的資料,工具,代碼都放在了相關(guān)資料放在\\0\upload\開發(fā)部\技術(shù)組\ACE目錄下。[2]如果您發(fā)現(xiàn)本指南有錯(cuò)誤或者疏漏,請(qǐng)通知\o"發(fā)郵件給作者"作者修改,以使本指南能夠更好的幫助大家。ACE簡(jiǎn)介及環(huán)境搭建ACE簡(jiǎn)介ACE自適配通信環(huán)境(AdaptiveCommunicationEnvironment)是面向?qū)ο蟮目蚣芎凸ぞ甙?,它為通信軟件?shí)現(xiàn)了核心的并發(fā)和分布式模式。ACE包含的多種組件可以幫助通信軟件的開發(fā)獲得更好的靈活性、效率、可靠性和可移植性。ACE中的組件可用于以下幾種目的:并發(fā)和同步進(jìn)程間通信(IPC)內(nèi)存管理定時(shí)器信號(hào)文件系統(tǒng)管理線程管理事件多路分離和處理器分派連接建立和服務(wù)初始化軟件的靜態(tài)和動(dòng)態(tài)配置、重配置分層協(xié)議構(gòu)建和流式框架分布式通信服務(wù):名字、日志、時(shí)間同步、事件路由和網(wǎng)絡(luò)鎖定,等等。上面是比較官方的介紹??傊绻阆胗肅++實(shí)現(xiàn)一個(gè)通信程序,而你又不想糾纏于Windows/Linux等各平臺(tái)不同的Socket細(xì)節(jié),那就可以考慮ACE框架。ACE經(jīng)過10余年的開發(fā),已經(jīng)不僅僅是通信的包,還實(shí)現(xiàn)了很多其它功能比如內(nèi)存管理,文件系統(tǒng)管理等,可以滿足您大多數(shù)開發(fā)的需要。而且ACE是被全世界很多項(xiàng)目采用的可以稱的上是電信級(jí)別的框架。ACE是跨平臺(tái)的,完全可以在Windows上開發(fā),運(yùn)行在Linux上(當(dāng)然,與Java不完全相同的是您需要重新編譯鏈接。而且如果您的程序使用了GUI的包,這么做是行不通的)。ACE的簡(jiǎn)介就到這里。當(dāng)我們使用ACE開發(fā)了一些程序,對(duì)ACE有了一定的認(rèn)識(shí)之后,再回過頭來進(jìn)一步認(rèn)識(shí)ACE。本指南的主要內(nèi)容本指南的目標(biāo)是ACE零基礎(chǔ)到可以用ACE開發(fā)一些簡(jiǎn)單的C/S程序。因此本指南的主要內(nèi)容有:1.ACE的獲取編譯 首先介紹如何搭建ACE開發(fā)環(huán)境的問題。2.ACEReactor/Proactor框架 接下來本文并不打算像其它ACE的書籍從ACE歷史介紹,基礎(chǔ)機(jī)制講起,而是直接進(jìn)入Reactor/Proactor框架的介紹及使用這2個(gè)框架來開發(fā)程序,給初學(xué)者最想要的東西。3.ACE其他機(jī)制 最后對(duì)ACE的其他框架機(jī)制等做一概要介紹,比如ACE_Task機(jī)制,線程管理,同步機(jī)制等。獲取ACE從服務(wù)器上獲取ACE-5.5.zip?;蛘邚?previous_versions/下載你需要的ACE版本。編譯ACE為什么要編譯ACE應(yīng)用程序在鏈接及運(yùn)行時(shí)需要使用ACE的庫(kù)和dll文件(Windows),而你下載的包里沒有這些文件或者不適合你的平臺(tái)。這時(shí)候就需要自己編譯ACE。編譯一般來說需要花很長(zhǎng)時(shí)間。注1:項(xiàng)目組的其他人或者公司里的同事可能已經(jīng)有編譯好的庫(kù)文件,如果你不想花時(shí)間編譯ACE,可以向其他人索取。服務(wù)器上有ace5.3版本在gcc2.96/3.23編譯通過的rpm文件,如果適合你的平臺(tái),直接安裝即可。注2:下面的在Windows/Linux編譯部分取自陳昕發(fā)的貼,本文做了適當(dāng)修改。文中目錄等請(qǐng)注意修改成符合你的環(huán)境的目錄等。陳昕原貼在8/bbs/viewthread.php?tid=1085&fpage=1在Window上編譯1.解壓縮到本地目錄例:解壓縮到C:\ACE_wrappers2.查看安裝向?qū)CE有自帶的安裝向?qū)募﨏:\ACE_wrappers\ACE-INSTALL.html查看ACE-INSTALL.html文件中的BuildingandInstallingACEonWindowswithMicrosoftVisualC++章節(jié),按照上面所寫即可,下面是對(duì)此過程的總結(jié)3.確定編譯環(huán)境本文使用的是C++.netframework1.1,以下為該編譯環(huán)境下的步驟4.新建config.h文件由于ACE支持很多操作系統(tǒng),因此必須建立一個(gè)config.h文件,在該文件包含相應(yīng)的操作系統(tǒng)的頭文件,從而讓ACE知道將在什么操作系統(tǒng)下進(jìn)行編譯進(jìn)入C:\ACE_wrappers\ace目錄,新建config.h文件,在config.h文件中添加#include"ace/config-win32.h"如果系統(tǒng)為Windows98/Me,那么需要添加#defineACE_HAS_WINNT40如果需要使用標(biāo)準(zhǔn)C++的類庫(kù)(例iostream等),那么需要添加#defineACE_HAS_STANDARD_CPP_LIBRARY1如果需要使用MFC(不推薦),那么需要添加#defineACE_HAS_MFC1

5.設(shè)置環(huán)境變量開始->運(yùn)行->cmdsetACE_ROOT=C:\ACE_wrappers6.使用.net環(huán)境編譯打開ACE.sln,可進(jìn)行debug/release編譯7.生成.lib.dll文件生成的lib和dll文件在C:\ACE_wrappers\lib。在Linux上編譯注:該步驟使用ACE-5.4.7測(cè)試成功1.解壓縮到本地目錄例:#pwd/home/xchen#tar-xzvfACE.tar.gz2.設(shè)置環(huán)境變量#su–#vi/etc/profile在exportPATHUSERLOGNAMEMAILHOSTNAMEHISTSIZEINPUTRC下加入以下兩行exportACE_ROOT=/usr/local/ACE_wrappersexportLD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ACE_ROOT/ace#./etc/profile3.建立編譯環(huán)境#cd/home/xchen/ACE_wrappers#mkdirbuild#cdbuild#../configure4.配置config.h文件../configure之后,系統(tǒng)會(huì)在/home/xchen/ACE_wrappers/build下建立ace/conig.h文件在//ACEconfigurationheaderfile下行添加#include"ace/config-linux.h"5.編譯#cd/home/xchen/ACE_wrappers/build#make6.生成.so文件生成的so文件在/home/xchen/ACE_wrappers/build/ace/.libs目錄下。前行的路標(biāo)對(duì)ACE感興趣,可以訪問ACE網(wǎng)站:/%7Eschmidt/ACE.htmlACE的YahooGroup:/group/ace-users/ACE開發(fā)者論壇(中文):/Index.htmlACEReactor框架Reactor(反應(yīng)器)框架在編寫通訊程序時(shí),如果服務(wù)器需要處理多個(gè)客戶端的連接,傳統(tǒng)做法是為每個(gè)客戶端創(chuàng)建一個(gè)進(jìn)程或者線程。在大多數(shù)情況下,這種方法是可以解決問題的。但是,在某些情況下,進(jìn)程線程創(chuàng)建維護(hù)并發(fā)的開銷是無法讓人接受的。而ACEReactor框架通過事件多路分離器,只需要用一個(gè)進(jìn)程或者線程就可以處理多個(gè)客戶端的連接的事件。而且用戶程序使用Reactor框架也非常的簡(jiǎn)單,只需要做3件事情:1)從ACE_Event_Handler派生子類,并Overwrite特定的事件虛回調(diào)方法。(比如handle_input,handle_timeout)。2)向ACE_Reactor類登記你剛才創(chuàng)建的ACE_Event_Handler子類。3)運(yùn)行ACE_Reactor事件循環(huán)。Reactor的含義—被動(dòng)反應(yīng),可以讓我們理解它的精髓:它是事件驅(qū)動(dòng)的,就像Windows的事件驅(qū)動(dòng)一樣。下面是ACEReactor框架的類圖和描述。ACE類描述ACE_Time_Value提供時(shí)間和持續(xù)時(shí)間(Duration)的可移植,規(guī)范化的表示ACE_Event_Handler抽象類,其定義的掛鉤(hook)方法是ACE_Reactor回調(diào)的目標(biāo)。大多數(shù)通過ACE開發(fā)的應(yīng)用事件處理器都是ACE_Event_Handler的后代。ACE_Timer_Queue抽象類,定義定時(shí)器隊(duì)列的能力和接口。ACE含有多種派生自ACE_Timer_Queue的類,為不同的定時(shí)機(jī)制提供了靈活的支持。ACE_Reactor提供了一個(gè)接口,用來在ACE框架中管理事件處理器登記,并執(zhí)行事件循環(huán)來驅(qū)動(dòng)事件檢測(cè),多路分離和分派。我們這里只關(guān)心ACE_Event_Handler和ACE_Reactor類。ACE_Event_Handler(事件處理器)ACE_Event_Handler是ACE中所有反應(yīng)式事件處理器的基類。其接口如下所示:方法描述ACE_Event_Handler()指派與事件處理器相關(guān)聯(lián)的ACE_Reactor指針。~ACE_Event_Handler()將其自身從反應(yīng)器的通知機(jī)制中移出。handle_input()輸入事件(如連接或數(shù)據(jù)事件)發(fā)生時(shí)的掛鉤(hook)方法。handle_output()輸出事件成為可能時(shí)(如流控制緩和或非阻塞式連接完成時(shí))被調(diào)用的掛鉤方法。handle_exception()異常事件(如TCP緊急數(shù)據(jù)的到達(dá))發(fā)生時(shí)被調(diào)用的掛鉤方法。handle_timeout()在定時(shí)器到期時(shí)被調(diào)用的掛鉤方法。handle_signal()OS發(fā)出信號(hào)時(shí)(或是POSIX信號(hào),或是Windows同步對(duì)象遷移到激發(fā)(Signaled)狀態(tài)時(shí))被調(diào)用的掛鉤方法。handle_close()在其他handle_*()掛鉤方法返回-1或者當(dāng)ACE_Reactor::remove_handler()被顯式調(diào)用來解除事件處理器的登記時(shí),執(zhí)行用戶定義的中止活動(dòng)的掛鉤方法。get_handle()返回底層的I/O句柄。如果事件處理器只處理時(shí)間驅(qū)動(dòng)的時(shí)間,該方法可實(shí)現(xiàn)為no-op(空操作)reactor()訪問器,用于獲取/設(shè)置可與ACE_Event_Handler相關(guān)聯(lián)的ACE_Reactor指針。priority()訪問器,用于獲取/設(shè)置事件處理器的優(yōu)先級(jí)。在開發(fā)一個(gè)普通的C/S應(yīng)用程序時(shí),只需Overwritehandle_input()和handle_close()這2個(gè)回調(diào)方法也就足夠了??梢栽赗eactor的定時(shí)器隊(duì)列設(shè)置定時(shí)器(參考下面的Reactor接口),當(dāng)超時(shí)事件發(fā)生時(shí)handle_timeout()會(huì)來處理超時(shí)時(shí)應(yīng)執(zhí)行的操作。下面討論一下使用ACE_Event_Handler時(shí)注意的3個(gè)方面:1.事件類型:在向Reactor登記事件處理器的時(shí)候,必須指定事件類型。事件類型定義在ACE_Event_Handler中,包括下面幾種:事件類型描述READ_MASK指定輸入事件(如數(shù)據(jù)出現(xiàn)在socket或文件句柄上)。反應(yīng)器分派handle_input()來處理輸入事件。WRITE_MASK指定輸出事件(如在流控制緩和時(shí))。反應(yīng)器分派handle_output()來處理輸出事件。EXCEPT_MASK指定異常事件(如緊急數(shù)據(jù)出現(xiàn)在socket上)。反應(yīng)器分派handle_exception()來處理異常事件。ACCEPT_MASK指定被動(dòng)模式的連接事件。反應(yīng)器分派handle_input()來處理連接事件。CONNECT_MASK指定非阻塞式連接的完成。反應(yīng)器分派handle_output()來處理非阻塞式連接的完成事件??梢詫?duì)這些事件進(jìn)行組合(|)來高效的定義一組事件。這組事件被填充在ACE_Reactor::register_handler()方法的ACE_Reactor_Mask參數(shù)。2.掛鉤方法的返回值登記的事件發(fā)生時(shí),反應(yīng)器會(huì)分派相應(yīng)的handle_*()來處理。而這些方法的返回值需注意:返回值描述0指示反應(yīng)器應(yīng)繼續(xù)為此事件處理器檢測(cè)和分派所登記的事件。對(duì)于需要重復(fù)處理一個(gè)事件的事件處理器(比如當(dāng)有數(shù)據(jù)可讀時(shí)從Socket讀取數(shù)據(jù)),這種行為是常見的。>0也指示反應(yīng)器應(yīng)繼續(xù)為此事件處理器檢測(cè)和分派所登記的事件。此外,如果在處理了某個(gè)I/O事件后返回值大于0,反應(yīng)器將在阻塞它的事件多路分離器之前,再次在句柄上分派此事件處理器。-1指示反應(yīng)器停止為此事件處理器檢測(cè)已登記的事件。在反應(yīng)器移除此事件處理器之前,它調(diào)用事件處理器的handle_close()方法,傳給該方法正在被解除登記的事件的ACE_Reactor_Mask值。所以,我們?cè)谑褂肦eactor框架來開發(fā)C/S程序時(shí),一般應(yīng)在handle_*()方法里返回0。3.清理事件處理器handle_close()方法會(huì)在某個(gè)掛鉤方法決定要進(jìn)行清理時(shí)被調(diào)用。handle_close()方法可隨即進(jìn)行用戶定義的關(guān)閉活動(dòng),如釋放內(nèi)存,關(guān)閉IPC對(duì)象等。Reactor框架會(huì)忽略handle_close()方法的返回值。如上所述,Reactor只會(huì)在掛鉤方法返回負(fù)值,或事件處理器被顯式移除時(shí)調(diào)用handle_close(),而不會(huì)在IPC機(jī)制到達(dá)文件末尾或I/O句柄被本地或遠(yuǎn)程關(guān)閉時(shí)調(diào)用handle_close()。因此,應(yīng)用必須檢測(cè)I/O句柄何時(shí)關(guān)閉,并采取措施。比如,當(dāng)recv()或read()調(diào)用返回0時(shí),事件處理器應(yīng)從handle_*()方法里返回-1,或調(diào)用ACE_Reactor::remove_handler()。ACE_ReactorACE_Reactor是Reactor模式的核心類,Reactor模式的注冊(cè)事件處理器,運(yùn)行事件循環(huán)等功能都要通過這個(gè)類來進(jìn)行。ACE_Reactor實(shí)現(xiàn)了Fa?ade模式,為應(yīng)用程序提供了各種訪問Reactor框架特性的接口。1.初始化和析構(gòu)方法:方法描述ACE_Reactor()open()這兩個(gè)方法創(chuàng)建并初始化反應(yīng)器的實(shí)例。~ACE_Reactor()close()這兩個(gè)方法清理反應(yīng)器在初始化時(shí)分配的資源。2.事件處理器管理方法方法描述register_handler()為基于I/O和信號(hào)的事件登記事件處理器remove_handler()移除某事件處理器,使其不再參加基于I/O和信號(hào)的事件分派suspend_handler()暫時(shí)停止分派事件給某事件處理器resume_handler()恢復(fù)為先前掛起的事件處理器分配事件mask_ops()獲取,設(shè)置,增加或者清除與某事件處理器相關(guān)的事件類型及掩碼schedule_wakeup()將指定的掩碼增加到某事件管理器的條目中,該處理器在之前必須已通過register_handler()登記過。cancel_wakeup()從某事件處理器的條目中清除指定的掩碼,但并不移除該事件處理器3.事件循環(huán)(Event-loop)方法方法描述handle_events()等待事件發(fā)生,并隨即分派與之相關(guān)聯(lián)的事件處理器。可通過超時(shí)參數(shù)限制花費(fèi)在等待事件上的時(shí)間。run_reactor_event_loop()反復(fù)調(diào)用handle_events()方法,直至其失敗,或者reactor_event_loop_done()返回1,或者超時(shí)(可選)。end_reactor_event_loop()指示反應(yīng)器關(guān)閉其事件循環(huán)。reactor_event_loop_done()在反應(yīng)器的事件循環(huán)被end_reactor_event_loop()調(diào)用結(jié)束時(shí)返回14.定時(shí)器管理方法方法描述schedule_timer()登記一個(gè)事件處理器,它將在用戶規(guī)定的時(shí)間后被執(zhí)行。cancel_timer()取消一個(gè)或多個(gè)之前登記的定時(shí)器。我們可以使用這兩個(gè)方法來使代碼具有超時(shí)特性,當(dāng)超時(shí)發(fā)生時(shí),事件處理器的handle_timeout()方法會(huì)被調(diào)用。5.通知方法反應(yīng)器擁有一種通知機(jī)制,應(yīng)用可將其用于把事件和事件處理器插入反應(yīng)器的分派引擎中。方法描述notify()將事件(及可選的事件處理器)插入反應(yīng)器的事件檢測(cè)器中,從而使其在反應(yīng)器下次等待事件時(shí)被處理max_notify_iterations()設(shè)置反應(yīng)器將在其通知機(jī)制中分派的處理器的最大數(shù)目。purge_pending_notifications()從反應(yīng)器的通知機(jī)制中清除指定的事件處理器或所有事件處理器6.實(shí)用方法(UtilityMethod)方法描述instance()靜態(tài)方法,返回指向單體(Singleton)ACE_Reactor的指針。這是通過Singleton模式和Double-CheckedLockingOptimization模式來創(chuàng)建和管理的。owner()使某個(gè)線程“擁有”反應(yīng)器的事件循環(huán)。因?yàn)榇蟛糠值膽?yīng)用程序都需要實(shí)現(xiàn)Server或者Client端的內(nèi)容,所以下面我們將分別實(shí)現(xiàn)一個(gè)Reactor的Server和Client。ACE也提供了實(shí)現(xiàn)Server和Client的半成品,Acceptor和Connector框架。Acceptor(接受器)-Connector(連接器)框架下面是Acceptor-Connector框架類的類圖。圖中我們可以看到ACE_Acceptor,ACE_Connector繼承自我們前面提到的ACE_Event_Handler。然后ACE_Svc_Handler是繼承自ACE_Task的,而ACE_Task其實(shí)也是ACE_Event_Handler的后代。根據(jù)前面提到的Reactor開發(fā)3步驟,我們只需要將ACE_Svc_Handler登記到Reactor即可進(jìn)行事件處理。對(duì)我們開發(fā)應(yīng)用程序而言,我們只需要關(guān)心ACE_Acceptor,ACE_Connector,ACE_Svc_Handler這3個(gè)類。ACE類描述ACE_Svc_Handler表示某個(gè)已連接服務(wù)的本地端,其中含有一個(gè)用于與相連對(duì)端通信的IPC端點(diǎn)。ACE_Acceptor該工廠被動(dòng)的等待接受連接,并隨即初始化一個(gè)ACE_Svc_Handler來響應(yīng)來自對(duì)端的主動(dòng)連接請(qǐng)求。ACE_Connector該工廠主動(dòng)的連接到對(duì)端接受器,并隨即初始化一個(gè)ACE_Svc_Handler與其相連對(duì)端通信。通俗的說,ACE_Acceptor就是我們要實(shí)現(xiàn)的Server,ACE_Connector就是我們要實(shí)現(xiàn)的Client。當(dāng)Client連接到Server時(shí),會(huì)創(chuàng)建一個(gè)ACE_Svc_Handler來處理事件(比如接收到數(shù)據(jù),連接被斷開等);而Server端也會(huì)為每個(gè)Client創(chuàng)建一個(gè)ACE_Svc_Handler來處理事件。ACE_Svc_Handler(服務(wù)處理器)如上所述,ACE_Svc_Handler就是用來處理事件,那么主要需要處理那些事件呢?1.服務(wù)創(chuàng)建和激活方法方法描述ACE_Svc_Handler()由接受器或連接器在創(chuàng)建服務(wù)處理器時(shí)調(diào)用的構(gòu)造方法open()由接受器或連接器自動(dòng)調(diào)用來初始化服務(wù)處理器的掛鉤方法。ACE_Svc_Handler已經(jīng)在open方法里,把自己登記到Reactor事件循環(huán),登記的事件類型為READ_MASK。所以我們的代碼將變得更加簡(jiǎn)單。2.服務(wù)處理方法方法描述svc()ACE_Svc_Handler從ACE_Task繼承來的svc()掛鉤方法。在服務(wù)處理器的activate()方法被調(diào)用后,其大部分后續(xù)處理都可在svc()掛鉤方法中執(zhí)行。handle_*()ACE_Svc_Handler從ACE_Event_Handler繼承的handle_*()方法。因此,服務(wù)處理器可以向反應(yīng)器登記自身,以在它感興趣的各種事件發(fā)生時(shí)接收像handle_input()這樣的回調(diào)。peer()返回指向底層PEER_STREAM的引用。服務(wù)處理器的PEER_STREAM是在其open()掛鉤方法被調(diào)用時(shí)就緒的。任何處理方法都可使用這個(gè)訪問器來獲取指向已連接的IPC機(jī)制的引用。3.服務(wù)關(guān)閉方法方法描述destroy()可以用來直接關(guān)閉服務(wù)處理器handle_close()通過來自反應(yīng)器的回調(diào)調(diào)用destroy()close()從服務(wù)處理器退出時(shí)調(diào)用handle_close()應(yīng)用可以直接調(diào)用destroy()來關(guān)閉服務(wù)處理器。該方法執(zhí)行了以下步驟:1)從反應(yīng)器處移除處理器2)取消任何與此處理器相關(guān)的定時(shí)器3)關(guān)閉對(duì)端流對(duì)象,以免發(fā)生句柄泄漏4)如果對(duì)象是被動(dòng)態(tài)分配的,將其刪除,以免內(nèi)存泄漏。下面討論一下如何在代碼中使用ACE_Svc_Handler。1.ACE_Svc_Handler是一個(gè)類模板,定義它的子類時(shí),要指定模板的類型。PEER_STREAM:底層傳遞數(shù)據(jù)流的類型,Socket連接使用ACE_SOCK_StreamSYNCH_STRATEGY:同步策略,可以使用ACE_NULL_SYNCH(無同步),ACE_MT_SYNCH(ACE默認(rèn)提供的同步策略)。2.子類覆蓋事件類型相應(yīng)的handle_*()方法。ACE_AcceptorACE_Acceptor是一個(gè)工廠,它實(shí)現(xiàn)了Acceptor-Connector中的Acceptor角色。也就是說起到了Server的作用。首先我們看一下ACE_Acceptor提供了那些接口:1.初始化,析構(gòu)及訪問器方法方法描述ACE_Acceptor()open()將接受器的被動(dòng)IPC端點(diǎn)綁定到特定地址,比如TCP端口或者IPC主機(jī)地址,然后對(duì)連接請(qǐng)求的到達(dá)進(jìn)行監(jiān)聽~ACE_Acceptor()close()關(guān)閉接受器的IPC端點(diǎn),并釋放資源。acceptor()返回指向底層PEER_ACCEPTOR的引用。2.連接建立和服務(wù)處理器初始化方法方法描述handle_input()當(dāng)連接請(qǐng)求從對(duì)端連接器到達(dá)時(shí),反應(yīng)器會(huì)調(diào)用此模板方法。它可以使用在下面概述的3個(gè)方法來使用“被動(dòng)地連接IPC端點(diǎn)并創(chuàng)建和激活與其相關(guān)聯(lián)的服務(wù)處理器”所必需的各步驟自動(dòng)化。make_svc_handler()該工廠方法創(chuàng)建服務(wù)處理器來處理通過其已連接的IPC端點(diǎn),從對(duì)端服務(wù)發(fā)出的數(shù)據(jù)請(qǐng)求accept_svc_handler()該掛鉤方法使用接受器的被動(dòng)模式IPC端點(diǎn)來創(chuàng)建已連接的IPC端點(diǎn),并將此端點(diǎn)與和服務(wù)處理器相關(guān)聯(lián)的一個(gè)I/O句柄封裝在一起activate_svc_handler()該掛鉤方法調(diào)用服務(wù)處理器的open(),使服務(wù)處理器完成對(duì)自己的初始化。下面的順序圖詳細(xì)的描述了當(dāng)連接請(qǐng)求到達(dá)時(shí),ACE_Acceptor所做的工作:那么我們?cè)趹?yīng)用程序中如何使用ACE_Acceptor呢?1.首先,實(shí)現(xiàn)ACE_Svc_Handler子類,然后覆蓋相應(yīng)的handle_*()事件回調(diào)方法。2.沒有特殊需要的情況下,我們不需要?jiǎng)?chuàng)建ACE_Acceptor的子類,只須定義它的實(shí)例即可。ACE_Acceptor是一個(gè)類模板,定義它的實(shí)例時(shí),要指定模板的類型。SVC_Handler:指定Acceptor對(duì)應(yīng)的ACE_Svc_Handler,當(dāng)有連接請(qǐng)求時(shí),Acceptor會(huì)創(chuàng)建一個(gè)新的ACE_Svc_Handler來處理對(duì)端的事件。PEER_ACCEPTOR:它能夠被動(dòng)的接受客戶連接,常被指定為ACE的各個(gè)IPCWrapperFa?ade。對(duì)于Socket來說,可以指定為ACE_SOCK_Acceptor。3.使用Open()方法,即可啟動(dòng)服務(wù)器,開始監(jiān)聽客戶機(jī)事件。對(duì)于Socket來說,Open方法需要使用一個(gè)ACE_INET_Addr。ACE_Connector同ACE_Acceptor相同,ACE_Connector也是一個(gè)工廠,它實(shí)現(xiàn)了Acceptor-Connector中的Connector角色。也就是說起到了Client的作用。ACE_Connector的接口有:1.連接器初始化,析構(gòu)方法以及訪問器方法方法描述ACE_Connector()open()用于初始化連接器的方法~ACE_Connector()close()釋放連接器所用的資源connector()返回指向底層的PEER_CONNECTOR的引用2.連接建立和服務(wù)處理器初始化方法:可用于主動(dòng)地建立連接,并對(duì)服務(wù)處理器進(jìn)行初始化。方法描述connect()應(yīng)用會(huì)在想要將某個(gè)服務(wù)處理器連接到監(jiān)聽的對(duì)端時(shí),調(diào)用這個(gè)模板方法。它可以使用下面的3個(gè)方法來使“主動(dòng)連接某個(gè)IPC端點(diǎn),創(chuàng)建并激活與其相關(guān)聯(lián)的服務(wù)處理器”所必需的各步驟自動(dòng)化。make_svc_handler()該工廠方法提供服務(wù)處理器,后者會(huì)使用已連接的IPC端點(diǎn)connect_svc_handler()該掛鉤方法使用服務(wù)處理器的IPC端點(diǎn)來同步或異步地主動(dòng)連接端點(diǎn)activate_svc_handler()該掛鉤方法調(diào)用服務(wù)處理器的open()掛鉤方法,后者允許服務(wù)處理器在連接建立之后完成對(duì)其自身的初始化。handle_output()在異步發(fā)起的連接請(qǐng)求完成之后,反應(yīng)器會(huì)調(diào)用這個(gè)模板方法。它調(diào)用activate_svc_handler()方法,以讓服務(wù)處理器對(duì)其自身進(jìn)行初始化。cancel()取消某服務(wù)處理器,其連接之前是異步發(fā)起的。調(diào)用者—不是連接器—負(fù)責(zé)關(guān)閉服務(wù)處理器。與Acceptor有些不同的是,Connector在連接時(shí)可以選擇同步或異步連接。因?yàn)閷?duì)于Acceptor來說,建立連接通常是即時(shí)的,而主動(dòng)連接建立就要花較長(zhǎng)的一段時(shí)間,尤其是廣域網(wǎng)。我們這里只討論同步連接的情形。下面的順序圖詳細(xì)的描述了異步連接建立中的各步驟:接下來討論一下在應(yīng)用程序中如何使用ACE_Connector呢?(同ACE_Acceptor基本類似)1.首先,實(shí)現(xiàn)ACE_Svc_Handler子類,然后覆蓋相應(yīng)的handle_*()事件回調(diào)方法。2.沒有特殊需要的情況下,我們也不需要?jiǎng)?chuàng)建ACE_Connector的子類,只須定義它的實(shí)例即可。ACE_Connector是一個(gè)類模板,定義它的實(shí)例時(shí),要指定模板的類型。SVC_Handler:指定Connector對(duì)應(yīng)的ACE_Svc_Handler,同服務(wù)器建立連接時(shí),Connector會(huì)創(chuàng)建一個(gè)新的ACE_Svc_Handler來處理對(duì)端的事件。PEER_Connector:它能夠主動(dòng)的建立客戶連接,常被指定為ACE的各個(gè)IPCWrapperFa?ade。對(duì)于Socket來說,可以指定為ACE_SOCK_Connector。3.使用connect()方法去主動(dòng)連接。connect方法里的參數(shù)有你剛才創(chuàng)建的ACE_Svc_Handler子類的指針和待連接的PEER_Address(對(duì)于Socket來說,是ACE_INET_Addr)。ACEReactorServer(Demo)需求下面我們實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Server端,這個(gè)Server能夠處理多個(gè)Client的連接,在收到Client的消息后,原封不動(dòng)的將消息再發(fā)還給Client。實(shí)現(xiàn)接下來我們一步一步實(shí)現(xiàn)它(在RedHat9,使用MagicC++開發(fā),最終的代碼可以在前面指定位置獲得):1.使用MagicC++在Linux服務(wù)器上建立一個(gè)新工程ReactorServer2.如果系統(tǒng)不能從環(huán)境變量等找到include的ACE頭文件,那么你需要在項(xiàng)目設(shè)定的Compile項(xiàng)中指定。比如/home/work/ACE_wrappers3.在項(xiàng)目設(shè)定的Link的選項(xiàng)卡中,庫(kù)文件處加入ACE庫(kù)的支持。同上,如果系統(tǒng)不能從環(huán)境變量等找到ACE庫(kù)文件,你也需要在下面的Librarydirectories中指定。4.準(zhǔn)備工作做好之后,下面我們創(chuàng)建服務(wù)處理器。創(chuàng)建新類ServerHandler,繼承自ACE_Svc_Handler。修改頭文件ServiceHandler.h。1)由于我們創(chuàng)建的是Socket服務(wù)器,ACE_Svc_Handler的模板里PEER_STREAM被指定為ACE_SOCK_STREAM,同時(shí)我們不需要使用同步機(jī)制,模板里的SYNCH_STRATEGY被指定為ACE_NULL_SYNCH。classServerHandler:publicACE_Svc_Handler<ACE_SOCK_STREAM,ACE_NULL_SYNCH>2)我們只關(guān)心輸入事件,也就是客戶端發(fā)來的消息,覆蓋handle_input方法。 virtualinthandle_input(ACE_HANDLEfd=ACE_INVALID_HANDLE);下面是ServiceHandler.h的完整代碼#ifndefSERVERHANDLER_H#defineSERVERHANDLER_H #include"ace/Svc_Handler.h"#include"ace/SOCK_Stream.h" classServerHandler:publicACE_Svc_Handler<ACE_SOCK_STREAM,ACE_NULL_SYNCH>{ public: virtualinthandle_input(ACE_HANDLEfd=ACE_INVALID_HANDLE);};#endif5.下面我們來實(shí)現(xiàn)ServiceHandler的handle_input方法。修改cpp文件ServiceHandler.cpp。1)在handle_input方法里,我們定義了一個(gè)4096的char數(shù)組。并出始化該數(shù)組。 constintINPUT_SIZE=4096; charbuffer[INPUT_SIZE]; memset(buffer,0,INPUT_SIZE);2)然后使用底層的peer來接收收到的消息,recv返回了收到的消息的length。 intrecv_cnt=this->peer().recv(buffer,sizeof(buffer));3)如果length<=0,說明對(duì)端的連接被斷開,這時(shí)候應(yīng)返回-1,指示反應(yīng)器停止為此事件處理器檢測(cè)已登記的事件。 if(recv_cnt<=0) { printf("Connectionclose\n"); return-1; }4)然后我們?cè)偈褂玫讓拥膒eer將收到的消息原封不動(dòng)的發(fā)回去。 this->peer().send(buffer,recv_cnt); 5)handle_input結(jié)束時(shí),我們應(yīng)該返回0,當(dāng)下次有消息到來時(shí),仍能被此服務(wù)處理器處理。 return0;下面是ServiceHandler.cpp的完整代碼#include"ServerHandler.h" intServerHandler::handle_input(ACE_HANDLE){ constintINPUT_SIZE=4096; charbuffer[INPUT_SIZE]; memset(buffer,0,INPUT_SIZE); intrecv_cnt=this->peer().recv(buffer,sizeof(buffer)); if(recv_cnt<=0) { printf("Connectionclose\n"); return-1; } this->peer().send(buffer,recv_cnt); return0;}6.最后我們實(shí)現(xiàn)main方法,增加ReactorServer.cpp文件1)在main方法,首先定義監(jiān)聽的IP地址,對(duì)于我們的Server應(yīng)用來說,只須指定監(jiān)聽的端口即可。我們?cè)?000端口監(jiān)聽。(ACE_INET_Addr后面介紹) ACE_INET_Addrport_to_accept(9000);2)定義我們的Server,Acceptor模板類的SVC_Handler指定為我們剛剛實(shí)現(xiàn)的ServerHandler,PEER_ACCEPTOR指定為ACE_SOCK_Acceptor。然后使用open方法開始監(jiān)聽。 ACE_Acceptor<ServerHandler,ACE_SOCK_ACCEPTOR>server; if(server.open(port_to_accept)==-1) { return-1; }3)接下來運(yùn)行ACE_Reactor事件循環(huán)。 ACE_Reactor::instance()->run_reactor_event_loop();下面是ReactorServer.cpp的完整代碼#include"ace/Reactor.h"#include"ace/Acceptor.h"#include"ace/SOCK_Acceptor.h" #include"ServerHandler.h"intmain(intargc,char*argv[]){ ACE_INET_Addrport_to_accept(9000); ACE_Acceptor<ServerHandler,ACE_SOCK_ACCEPTOR>server; if(server.open(port_to_accept)==-1) { return-1; } ACE_Reactor::instance()->run_reactor_event_loop(); return0;}7.接下來編譯,運(yùn)行ReactorServer8.下面我們使用一個(gè)客戶端來測(cè)試一下。這里使用的是SocketTest,一個(gè)Java寫的Socket測(cè)試工具,你可以在前面指定的位置上找到它。打開SocketTest,輸入我們的Server所在的IP地址和端口后,點(diǎn)擊Connect。連接之后,在下面的Message框里輸入一句話,然后點(diǎn)Send按鈕,我們就會(huì)看到Conversationwithhost框里看到我們發(fā)過去的消息,以及服務(wù)器原封不動(dòng)回復(fù)的消息。9.上面的測(cè)試說明我們的服務(wù)器是按照我們的預(yù)想工作的,下面我們?cè)贉y(cè)試一下同時(shí)有幾個(gè)客戶端連接服務(wù)器的情況。我們?cè)俅蜷_2個(gè)SocketTest,重復(fù)前面的操作。10.多個(gè)客戶端同時(shí)連上去也沒有關(guān)系,我們的Server同樣能很好的運(yùn)行。這個(gè)Server實(shí)現(xiàn)了以下功能:在指定端口監(jiān)聽處理多個(gè)客戶端的請(qǐng)求將接受到的消息回復(fù)給客戶端這個(gè)Server是跨平臺(tái)的,只需在不同平臺(tái)分別編譯運(yùn)行。而我們完成這些功能只用了:一個(gè)線程幾十行代碼幾分鐘的時(shí)間由此可見,使用ACE的好處是我們無需再關(guān)心Socket等連接的細(xì)節(jié),也無需關(guān)心為每個(gè)客戶端創(chuàng)建線程,我們只需專注業(yè)務(wù)邏輯,這極大的提高了我們的效率。ACE工具類前面我們?cè)诰帉慡erver時(shí)用到了ACE_INET_Addr,其實(shí)ACE提供了很多的工具類(宏)。下面對(duì)這些工具類做一簡(jiǎn)單的介紹,更詳細(xì)的內(nèi)容請(qǐng)自行閱讀參考資料。作用類(宏)描述地址包裝類ACE_INET_AddrACE_INET_Addr類封裝了Internet域地址族(AF_INET)。該類派生自ACE中的ACE_Addr。它的多種構(gòu)造器可用于初始化對(duì)象,使其具有特定的IP地址和端口。除此而外,該類還具有若干set和get方法,并且重載了比較操作,也就是==操作符和!=操作符。ACE_UNIX_AddrACE_UNIX_Addr類封裝了UNIX域地址族(AF_UNIX),它也派生自ACE_Addr。該類的功能與ACE_INET_Addr類相似。時(shí)間包裝類ACE_TIME_VALUEACE的時(shí)間包裝類,該類使用秒(sec)和微秒(usec)來描述時(shí)間。日志宏ACE_DEBUG/ACE_TRACEACE_DEBUG(與ACE_TRACE幾乎相同)和ACE_ERROR宏用于打印調(diào)試及錯(cuò)誤信息及記錄相應(yīng)的日志。它們的用法是:ACE_DEBUG((severtity,formating-args))ACE_ERROR((severtity,formating-args))severtity為嚴(yán)重級(jí)別,最常用的是LM_DEBUG,LM_ERROR。formating-args使用了ACE_TEXT宏,ACE_TEXT可以使用%d,%t等格式修飾符。就如在printf格式串中一樣,下面簡(jiǎn)單介紹幾個(gè)格式修飾符(區(qū)分大小寫)。%P當(dāng)前進(jìn)程的ID%t調(diào)用線程的ID%T當(dāng)前時(shí)間,格式為hour:min:sec.usec%s字符串ACE_ERROR內(nèi)存分配宏ACE_NEW(p,c)使用構(gòu)造器c分配內(nèi)存,并把指針賦給p。失敗時(shí),p被設(shè)置為0,并執(zhí)行returnACE_NEW_RETURN(p,c,r)使用構(gòu)造器c分配內(nèi)存,并把指針賦給p。失敗時(shí),p被設(shè)置為0,并執(zhí)行returnrACE_NEW_RETURN(p,c)使用構(gòu)造器c分配內(nèi)存,并把指針賦給p。失敗時(shí),p被設(shè)置為0,并繼續(xù)執(zhí)行下一條語(yǔ)句。Server改進(jìn)下面對(duì)我們剛才的Server進(jìn)行改進(jìn),讓它打印出一些調(diào)試信息來。1)Client連接時(shí),打印出Client端的IP地址;2)收到Client的消息時(shí),打印出消息的內(nèi)容;3)Client斷開時(shí),打印出Client斷開的信息。1.打開ServiceHandler.h進(jìn)行修改:1)為方便起見,我們創(chuàng)建了super類型定義。這樣,在我們的類中調(diào)用基類方法時(shí),可讀性將大為提高。 typedefACE_Svc_Handler<ACE_SOCK_STREAM,ACE_NULL_SYNCH>super;2)當(dāng)Client連接時(shí),打印出Client端的IP地址,應(yīng)該在open()方法里面實(shí)現(xiàn),所以我們繼承父類的open方法: intopen(void*=0);3)將Client端的IP地址保存在類里,因此增加一個(gè)屬性: private: ACE_TCHARpeer_name[MAXHOSTNAMELEN];ServiceHandler.h修改完成,下面是改進(jìn)后的ServiceHandler.h的完整代碼#ifndefSERVERHANDLER_H#defineSERVERHANDLER_H #include"ace/Svc_Handler.h"#include"ace/SOCK_Stream.h" classServerHandler:publicACE_Svc_Handler<ACE_SOCK_STREAM,ACE_NULL_SYNCH>{ typedefACE_Svc_Handler<ACE_SOCK_STREAM,ACE_NULL_SYNCH>super; public: intopen(void*=0); virtualinthandle_input(ACE_HANDLEfd=ACE_INVALID_HANDLE); private: ACE_TCHARpeer_name[MAXHOSTNAMELEN];};#endif2.修改類文件ServiceHandler.cpp。1)增加open方法,我們并不打算改變父類open的行為,所以首先調(diào)用父類的open方法。intServerHandler::open(void*p){ if(super::open(p)==-1) { return-1; } return0;}2)接下來在open方法里獲得Client的IP地址。使用底層peer的get_remote_addr方法。得到地址之后,我們ACE_DEBUG用打印出來,同時(shí)打印出時(shí)間,進(jìn)程號(hào),線程號(hào)。 ACE_INET_Addrpeer_addr; if(this->peer().get_remote_addr(peer_addr)==0 &&peer_addr.addr_to_string(peer_name,MAXHOSTNAMELEN)==0) { ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Connectionfrom%s\n"),peer_name)); }3)修改handle_input方法,把原來用printf寫的方法改成ACE_DEBUG。再把收到的消息打印出來。 if(recv_cnt<=0){ ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Connectionclosefrom%s\n"),peer_name)); return-1; } ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Receivemsgfrom%s:%s\n"),peer_name,buffer));下面是改進(jìn)后的ServiceHandler.cpp的完整代碼#include"ServerHandler.h"intServerHandler::open(void*p){ if(super::open(p)==-1) { return-1; } ACE_INET_Addrpeer_addr; if(this->peer().get_remote_addr(peer_addr)==0 &&peer_addr.addr_to_string(peer_name,MAXHOSTNAMELEN)==0) { ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Connectionfrom%s\n"),peer_name)); } return0;}intServerHandler::handle_input(ACE_HANDLE){ constintINPUT_SIZE=4096; charbuffer[INPUT_SIZE]; memset(buffer,0,INPUT_SIZE); intrecv_cnt=this->peer().recv(buffer,sizeof(buffer)); if(recv_cnt<=0){ ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Connectionclosefrom%s\n"),peer_name)); return-1; } ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Receivemsgfrom%s:%s\n"),peer_name,buffer)); this->peer().send(buffer,recv_cnt); return0;}3.這樣修改就完成了,接下來編譯測(cè)試,運(yùn)行ReactorServer,然后運(yùn)行SocketTest測(cè)試,效果類似下圖:ACEReactorClient(Demo)需求上面ReactorServer的測(cè)試的客戶端,我們使用了SocketTest這個(gè)工具。下面我們自己開發(fā)一個(gè)工具。這個(gè)工具能夠:1)建立5個(gè)與服務(wù)器端的連接;2)每個(gè)連接每隔2秒鐘發(fā)送一條測(cè)試消息給服務(wù)器,發(fā)送5次,然后斷開同服務(wù)器的鏈接。實(shí)現(xiàn)I接下來我們一步一步實(shí)現(xiàn)它(在RedHat9,使用MagicC++開發(fā),最終的代碼可以在前面指定位置獲得):1.使用MagicC++在Linux服務(wù)器上建立一個(gè)新工程ReactorClient。項(xiàng)目的設(shè)置等跟ReactorServer的設(shè)置相同2.準(zhǔn)備工作做好之后,下面我們創(chuàng)建服務(wù)處理器。創(chuàng)建新類ClientHandler,繼承自ACE_Svc_Handler。修改頭文件ClientHandler.h。1)由于我們創(chuàng)建的是Socket服務(wù)器,ACE_Svc_Handler的模板里PEER_STREAM被指定為ACE_SOCK_STREAM,同時(shí)我們不需要使用同步機(jī)制,模板里的SYNCH_STRATEGY被指定為ACE_NULL_SYNCH。classClientHandler:publicACE_Svc_Handler<ACE_SOCK_STREAM,ACE_NULL_SYNCH>2)覆蓋handle_input方法,以檢查服務(wù)器是否將發(fā)出去的消息返回來。 virtualinthandle_input(ACE_HANDLEfd=ACE_INVALID_HANDLE);下面是ClientHandler.h的完整代碼#ifndefCLIENTHANDLER_H#defineCLIENTHANDLER_H#include"ace/Svc_Handler.h"#include"ace/SOCK_Stream.h" classClientHandler:publicACE_Svc_Handler<ACE_SOCK_STREAM,ACE_NULL_SYNCH>{public: virtualinthandle_input(ACE_HANDLEfd=ACE_INVALID_HANDLE);};#endif3.下面我們來實(shí)現(xiàn)ClientHandler的handle_input方法。這個(gè)實(shí)現(xiàn)跟Server的幾乎一樣,但只負(fù)責(zé)接收消息,不再發(fā)送消息給服務(wù)器端。下面是ClientHandler.cpp的完整代碼#include"ClientHandler.h"intClientHandler::handle_input(ACE_HANDLE){ constintINPUT_SIZE=4096; charbuffer[INPUT_SIZE]; memset(buffer,0,INPUT_SIZE); intrecv_cnt=this->peer().recv(buffer,sizeof(buffer)); if(recv_cnt<=0){ ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Connectionclose\n"))); return-1; } ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Receivemsgfromserver:%s\n"),buffer)); return0;}4.最后我們實(shí)現(xiàn)main方法,增加ReactorClient.cpp文件1)在main方法,首先定義要連接的IP地址,對(duì)于我們的Client應(yīng)用來說,要連接的服務(wù)器為本機(jī)9000端口上的服務(wù)器??梢园凑障旅娴姆椒▉矶xACE_INET_Addr。 ACE_INET_Addrport_to_connect(9000,ACE_LOCALHOST);2)定義我們的Client,Connector模板類的SVC_Handler指定為我們剛剛實(shí)現(xiàn)的ClientHandler,PEER_ACCEPTOR指定為ACE_SOCK_Acceptor。 ACE_Connector<ClientHandler,ACE_SOCK_Connector>client;3)根據(jù)我們的需求,創(chuàng)建5個(gè)到服務(wù)器的連接,connect方法和Acceptor的open不同,open方法不需要制定SVC_Handler的指針,而connect方法需要。不過你可以傳個(gè)空指針進(jìn)去,connect方法會(huì)自動(dòng)創(chuàng)建一個(gè)新的SVC_Handler,并且由于connect方法的參數(shù)是SVC_Handler指針的引用,所以我們能夠得到connect方法里面創(chuàng)建的SVC_Handler的實(shí)際指針。 for(inti=0;i<5;i++) { ClientHandler*handler=NULL; if(client.connect(handler,port_to_connect)==-1) { ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Connection%dfailed.\n"),i)); return-1; } }4)接下來運(yùn)行ACE_Reactor事件循環(huán)。 ACE_Reactor::instance()->run_reactor_event_loop();下面是ReactorClient.cpp的完整代碼#include"ace/Reactor.h"#include"ace/Connector.h"#include"ace/SOCK_Connector.h" #include"ClientHandler.h"intmain(intargc,char*argv[]){ ACE_INET_Addrport_to_connect(9000,ACE_LOCALHOST); ACE_Connector<ClientHandler,ACE_SOCK_Connector>client; for(inti=0;i<5;i++) { ClientHandler*handler=NULL; if(client.connect(handler,port_to_connect)==-1) { ACE_DEBUG((LM_DEBUG,ACE_TEXT("[%T](%P|%t)Connection%dfailed.\n"),i)); return-1; } } ACE_Reactor::instance()->run_reactor_event_loop(); return0;}5.接下來編譯。如果沒有運(yùn)行ReactorServer,請(qǐng)首先運(yùn)行ReactorServer。然后再運(yùn)行ReactorClient。運(yùn)行效果如下圖:根據(jù)運(yùn)行結(jié)果,我們發(fā)現(xiàn),我們的測(cè)試程序成功的與服務(wù)器建立了5個(gè)連接,但是由于我們還沒有編寫發(fā)送消息的代碼,所以還不能每2秒發(fā)送消息。使用超時(shí)機(jī)制發(fā)送消息從ReactorServer.cpp的main方法我們看到,當(dāng)5個(gè)連接成功后,就進(jìn)入到了Reactor的事件循環(huán)中了,而沒有事件觸發(fā),是不會(huì)調(diào)用我們的服務(wù)處理器的。因此,我們的主動(dòng)發(fā)送消息的代碼也就沒有機(jī)會(huì)執(zhí)行。解決這個(gè)問題,創(chuàng)造我們主動(dòng)發(fā)送消息的機(jī)會(huì),有2個(gè)辦法:1)外

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論