Asp.net管道模型(管線模型)
前言
為什么我會起這樣的一個標題,其實我原本只想了解asp.net的管道模型而已,但在查看資料的時候遇到不明白的地方又橫向地查閱了其他相關的資料,而收獲比當初預想的大了很多。
有本篇作基礎,下面兩篇就更好理解了:
目錄
一般不寫目錄,感覺這次要寫的東西有些多就寫一個清晰一下吧。
1.Asp.net管道模型;
2.進程的子進程與進程的線程;
參考:ASP.NET使用管道模型(PipleLines)處理HTTP請求
管道模型中包含以下對象:
流程圖:
Http Request傳到工作進程(IIS5.x為aspnet_wp.exe,IIS6.x和IIS7.x為w3wp.exe)后,工作進程實例中通過ISAPIRuntime(主要作用是調用一些非托管代碼生成HttpWorkerRequest對象,HttpWorkerRequest對象包含當前請求的所有信息,然后傳遞給HttpRuntime)傳遞HttpWorkerRequest對象給HttpRuntime並調用HttpRuntime的ProcessRequest方法,HttpRuntime為管道模型的入口此時正式進入管道模型。
HttpRuntime根據HttpWorkerRequest對象生成HttpContext,HttpContext包含request、response等屬性, 再調用HttpApplicationFactory的GetApplicationInstance方法生成HttpApplication, HttpApplication對象包含多個HttpModule對象(當一個HTTP請求到達HttpModule時,整個ASP.NET Framework系統還並沒有對這個HTTP請求做任何處理,也就是說此時對於HTTP請求來講,HttpModule是一個HTTP請求的“必經之路”,所以可以在這個HTTP請求傳遞到真正的請求處理中心(HttpHandler)之前附加一些需要的信息在這個HTTP請求信息之上,或者針對截獲的這個HTTP請求信息作一些額外的工作,或者在某些情況下干脆終止滿足一些條件的HTTP請求,從而可以起到一個Filter過濾器的作用),並調用各個HttpModule對象的Init方法初始化HttpModule,在Init方法中可以訂閱HttpApplication的事件從而作出相應的處理。當HttpApplication執行到Application_ResolveRequestCache時暫時將控制權交給HttpHandler並根據HttpHandler中是否啟用SessionState來確定是否生成會話跟蹤功能(.aspx中用enablesessionstate設置,.ashx中用是否繼承IRequiresSessionState接口來設置),然后HttpApplication繼續執行自身的事件直到執行完PreRequestHandlerExecute事件就根據URL請求的后綴名獲取HttpHandlerFactory對象(默認情況下.aspx調用System.Web.UI.PageHandlerFactory,.ashx調用System.Web.UI.SimpleHandlerFactory),調用HttpHandlerFactory的GetHandler方法生成具體的HttpHandler對象或調用ReleaseHandler方法使工廠可以重用現有的處理程序實例來處理http請求並返回http響應,再經過HttpApplication對象的一系列事件(具體事件請參考HttpModule的認識(轉載))最終返回到客戶端,當然http響應所經過的HttpApplication的一系列事件都可以被HttpModule對象所訂閱。
參考:百度問答
我拿Windows舉例子吧, 因為Linux的內核好像是沒有線程概念的.進程和線程的區別在於粒度不同, 進程之間的變量(或者說是內存)是不能直接互相訪問的, 而線程可以, 線程一定會依附在某一個進程上執行.我舉個例子, 你在Windows下開一個IE瀏覽器, 這個IE瀏覽器是一個進程. 你用瀏覽器去打開一個pdf, IE就去調用Acrobat去打開, 這時Acrobat是一個獨立的進程, 就是IE的子進程.而IE自己本身同時用同一個進程開了2個網頁, 並且同時在跑兩個網頁上的腳本, 這兩個網頁的執行就是IE自己通過兩個線程實現的.值得注意的是, 線程仍然是IE的內容, 而子進程Acrobat嚴格來說就不屬於IE了, 是另外一個程序.之所以是IE的子進程, 只是受IE調用而啟動的而已.
追問:那我可不可以這樣理解,父進程創建了一個子進程,只要給這個子進程分配一定的任務,他們從此就沒有關系了 。。。。
回答:也不能這么說從此就沒關系了, 父進程還是可以通過和子進程通信來獲得一些信息的. 拿上面的例子來說,
IE可以通過一些進程間通信的接口來知道Acrobat是否順利的把pdf打開了之類的信息. 但有一點我覺得你的理解基本正確,
就是父進程和子進程是獨立的. 假如IE開了一個病毒子進程, 子進程不聽話, 父進程也沒什么特別的辦法, 除了向系統申請去關閉它之外.
區分子進程和線程很簡單: 一個獨立程序的運行稱為一個進程, 在進程里並發執行的不同部分稱為線程. 由這個進程引發的另外的獨立程序運行為這個進程的子進程.(基本上就是這樣, 更加嚴格的定義建議參考操作系統的教科書)
參考:.NET簡談組件程序設計之(AppDomain應用程序域)
參考:http://blog.csdn.net/zhoufoxcn/article/details/2425420中周公的回答
進程:屬於操作系統上的概念,一個進程占有一個內存地址,是應用程序與應用程序之間的邊界,進程之間不能共享代碼和數據空間(也就是不能直接交互),但可以通過IPC(remoting、named pipe、webservice等)進行數據交互。一個進程出現錯誤甚至崩潰不會影響其他進程的執行。
子進程:由另一個進程啟動,子進程與父進程沒有從屬關系,兩進程可以通過IPC進行數據交互。
線程:屬於操作系統上的概念,是代碼執行堆棧和執行上下文的邊界,同一進程的多個線程共享代碼和數據空間,但只負責執行代碼而沒有攜帶數據的功能。獨立或多個線程協同負責執行進程中的任務。
題外:對於線程其實還有很多方面可以深入,更多請參考《深入線程》
應用程序域(AppDomain)
參考:理解AppDomain
AppDomain是.net framework獨有的概念,是邏輯宿主,其功能就像進程那樣是程序運行的獨立空間(從進程中分配獨立的內存空間,AppDomain間不能共享代碼和數據空間),當一個AppDomain中的程序出現異常甚至崩潰時不會影響到其他AppDomain中運行的程序。但AppDomain不是進程,一個進程可以擁有一個或多個AppDomain,其中必須有一個默認的AppDomain。
也許這里您會有這樣的疑問:AppDomain是線程嗎?如果不是那么與線程的關系是什么呢?在.net framework中存在進程、應用程序域(AppDomain)、線程三個獨立又有聯系的概念,一個進程含一個或多個AppDomain(必須存在一個默認AppDomain);一個進程含一個或多個線程(通常含一個線程池,里面有多個可重用的線程);AppDomain與線程是多對多關系,但某一個時刻一個線程只能處理一個AppDomain,而AppDomain可以由多個線程同時處理(並發)。
從運行程序時的過程是這樣的:系統首先分配一段內存地址空間然后把控制權交給了CLR生成默認AppDomain,然后將程序集加載到默認AppDomain中,程序正式運行(系統在托管堆中沒有AppDomain的概念,AppDomain不是操作系統的概念,由CLR管理)。默認AppDomain隨CLR而生而亡,無法以編碼方式刪除或者卸載其中的程序集。
下面以圖的形式描述進程、線程、AppDomain的位置關系。
AppDomain之間不能直接交互,可通過代理的方式進行數據交互(如果是進程就使用IPC)。(具體實現以后探討!)
上圖左邊為IIS5.X WEB SERVER,右邊為Asp.net Application的工作進程(worker process),Asp.net是以作為IIS組件的形式擴展IIS的。
當一個http request發送到IIS5.X時,IIS先把虛擬目錄轉變為物理目錄,然后根據文件后綴名檢查iis中的metabase文件檢查文件擴展名與可執行代碼(擴展程序)映射記錄(如.aspx、.ashx等對應aspnet_isapi.dll),如果metabase文件中沒有就再檢查是否為不受服務器端保護的文件(受服務器端保護:App_Code文件夾下的文件;不受服務器端保護:css、js文件),如果都不存在則直接返回404HTTP狀態碼給客戶端;(該查找循序可通過《理解並自定HttpHandler》)存在則iis的inetinfo.exe實例會調用相應的可執行代碼(這里是aspnet_isapi.dll),aspnet_isapi.dll會通過一個命名管道(named pipe,一種簡單的IPC——進程通信機制,具體內容請參考:《命名管道及延伸進程通信學習》)把從inetinfo.exe獲取的request異步轉發到Asp.net工作進程實例:aspnet_wp.exe,然后就進入管道模型。同時aspnet_isapi.dll通過named pipe監測工作進程的運行狀況,如果工作進程性能低於某個值aspnet_isapi.exe就會殺死工作進程,當下一個請求傳遞過來時重新啟動一個工作進程處理請求。而工作進程通過named pipe同步請求web server的信息(如調用Server對象獲取服務器信息)。
圖依然秉承着我很丑但很有用的原則,嘻嘻!!
aspnet_wp.exe的工作進程中含有一個線程池和一個默認AppDomain,當一個Request發送到工作進程后,工作進程會根據請求的虛擬目錄的文件(一個虛擬目錄對應一個Application)由默認AppDomain創建AppDomain並將該虛擬目錄的程序集加載到AppDomain中(虛擬目錄中可能不止一個程序集,而默認AppDomain會將整個虛擬目錄下的所有程序集加載到AppDomain上),如果該虛擬目錄的AppDomain已存在就直接使用該AppDomain,如果虛擬目錄的程序集發生變化(包括web.config變化),就會新建一個AppDomain再將以變化的程序集加載到新的AppDomain中;這時從線程池獲取空閑線程執行程序集(寫一個網站發布成兩個虛擬目錄進行測試,可以看到執行http請求處理的線程不斷地變化,兩個虛擬目錄會出現使用相同線程的情況)。程序集中的變量和狀態均保存在所屬的AppDomain的內存中,如HttpContext.Current.Items、Application等(Application對象其實就是一張HashTable,可以被多個線程(iis5.X)或多個Application實例(iis6.x)訪問),AppDomain之間不能直接訪問對方的變量和狀態。Session狀態變量有三種模式InProc、StateServer和SQLServer,其中默認為InProc表示Session狀態保存在Asp.net進程中,如果虛擬目錄的程序集發生變化后在新AppDomain中調用之前所設置的Session狀態變量就會發現Session丟失了(客戶端的Cookie中保存的SessionID依舊,如果存在應該是可以讀取的),表明Session模式為InProc時Session狀態變量保存在對應的AppDomain中。
題外話:如果session模式設置為StateServer表示使用狀態服務器保存Session狀態,就是使用另外一個本地或遠程進程來保存Session狀態,本地開啟狀態服務器步驟(系統為Windows server類型):1.開始->所有程序->管理工具->服務->開啟 Asp.net狀態服務,然后配置一下網站的web.config為<sessionState mode="StateServer" stateConnectionString="tcpip=localhost:4242"/>
IIS5.x、IIS6.x和IIS7.x的區別
參考:各版本IIS下ASP.net請求處理過程區別
IIS5.x設計為一個服務器只啟用一個工作進程來處理所有請求/響應,為保證各個Application(以虛擬目錄為單位)獨立運行且不干擾其他Application(一個Application崩潰不導致整個進程崩潰),引入了AppDomain。但AppDomain效果差強人意,於是IIS6.x開始使用應用程序池(Application Pool)。在非Web Garden模式下一個Application對應一個應用程序池,對應一個工作進程,6.x開始工作進程從Aspnet_wp改為w3wp;在Web Garden模式下一個Application對應一個應用程序池,對應多個工作進程,Application可以在任意一個工作進程上執行,一旦其中一個工作進程崩潰也能及時處理該Application的請求,但在Web Garden模式下SessionState不能使用InProc模式,因為該模式會將SessionState保存在工作進程的AppDomain中。
IIS5.x中識別請求屬於哪個Application是在工作進程中在用戶模式下實現的,而IIS6.x是由Web Server的http.sys在核心模式實現的(IIS5.x的是Aspnet_isapi.dll,而IIS6.x開始使用了新組件http.sys)。注:為了避免用戶應用程序訪問或者修改關鍵的操作系統數據,windows提供了兩種處理器訪問模式:用戶模式(User Mode)和內核模式(Kernel Mode)。一般地,用戶程序運行在User mode下,而操作系統代碼運行在Kernel Mode下。Kernel Mode的代碼允許訪問所有系統內存和所有CPU指令。
IIS5.x和IIS6.x的ASP.NET都是以IIS ISAPI extension的方式外加到IIS,而IIS7.x開始把Asp.net繼承到IIS當中,並且IIS7.x工作模式有經典模式和集成模式兩種,具體請看參考。
本篇是出處哦!http://www.cnblogs.com/fsjohnhuang/archive/2012/07/12/2587658.html