久久精品国产精品国产精品污,男人扒开添女人下部免费视频,一级国产69式性姿势免费视频,夜鲁夜鲁很鲁在线视频 视频,欧美丰满少妇一区二区三区,国产偷国产偷亚洲高清人乐享,中文 在线 日韩 亚洲 欧美,熟妇人妻无乱码中文字幕真矢织江,一区二区三区人妻制服国产

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

干货 | 嵌入式系统软件架构设计

發布時間:2024/8/1 windows 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 干货 | 嵌入式系统软件架构设计 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方“大魚機器人”,選擇“置頂/星標公眾號”

福利干貨,第一時間送達!

整理 :嵌入式云IOT技術圈,作者:veryarm

1. 前言

嵌入式是軟件設計領域的一個分支,它自身的諸多特點決定了系統架構師的選擇,同時它的一些問題又具有相當的通用性,可以推廣到其他的領域。

提起嵌入式軟件設計,傳統的印象是單片機,匯編,高度依賴硬件。傳統的嵌入式軟件開發者往往只關注實現功能本身,而忽視諸如代碼復用,數據和界面分離,可測試性等因素。從而導致嵌入式軟件的質量高度依賴開發者的水平,成敗系之一身。隨著嵌入式軟硬件的飛速發展,今天的嵌入式系統在功能,規模和復雜度各方面都有了極大的提升。比如,Marvell公司的PXA3xx系列的最高主頻已經達到800Mhz,內建USB,WIFI,2D圖形加速,32位DDR內存。在硬件上,今天的嵌入式系統已經達到甚至超過了數年前的PC平臺。在軟件方面,完善的操作系統已經成熟,比如Symbian, Linux, WinCE。基于完善的操作系統,諸如字處理,圖像,視頻,音頻,游戲,網頁瀏覽等各種應用程序層出不窮,其功能性和復雜度比諸PC軟件不遑多讓。原來多選用專用硬件和專用系統的一些商業設備公司也開始轉換思路,以出色而廉價的硬件和完善的操作系統為基礎,用軟件的方式代替以前使用專有硬件實現的功能,從而實現更低的成本和更高的可變更,可維護性。

2.決定架構的因素和架構的影響

架構不是一個孤立的技術的產物,它受多方面因素的影響。同時,一個架構又對軟件開發的諸多方面造成影響。

下面舉一個具體的例子。

摩托車的發動機在出廠前必須通過一系列的測試。在流水線上,發動機被送到每個工位上,由工人進行諸如轉速,噪音,振動等方面的測試。要求實現一個嵌入式設備,具備以下基本功能:

  • 安裝在工位上,工人上班前開啟并登錄。

  • 通過傳感器自動采集測試數據,并顯示在屏幕上。

  • 記錄所有的測試結果,并提供統計功能。比如次品率。

  • 如果你是這個設備的架構師,哪些問題是在設計架構的時候應該關注的呢?

    2.1. 常見的誤解

    2.1.1. 小型的系統不需要架構

    有相當多的嵌入式系統規模都較小,一般是為了某些特定的目的而設計的。受工程師認識,客戶規模和項目進度的影響,經常不做任何架構設計,直接以實現功能為目標進行編碼。這種行為表面上看滿足了進度,成本,功能各方面的需求,但是從長遠來看,在擴展和維護上付出的成本,要遠遠高于最初節約的成本。如果系統的最初開發者繼續留在組織內并負責這個項目,那么可能一切都會正常,一旦他離開,后續者因為對系統細節的理解不足,就可能引入更多的錯誤。要注意,嵌入式系統的變更成本要遠遠高于一般的軟件系統。好的軟件架構,可以從宏觀和微觀的不同層次上描述系統,并將各個部分隔離,從而使新特性的添加和后續維護變得相對簡單。

    舉一個城鐵刷卡機的例子,這個例子在前面的課程中出現過。簡單的城鐵刷卡機只需要實現如下功能:

    一個While循環足以實現這個系統,直接就可以開始編碼調試。但是從一個架構師的角度,這里有沒有值得抽象和剝離的部分呢?

  • 計費系統。計費系統是必須抽象的,比如從單次計費到按里程計費。

  • 傳感器系統。傳感器包括磁卡感應器,投幣器等。設備可能更換。

  • 故障處理和恢復。考慮到較高的可靠性和較短的故障恢復時間,這部分有必要單獨設計。

  • 未來很可能出現的需求變更:

  • 操作界面。是否需要抽象出專門的Model來?以備將來實現View。

  • 數據統計。是否需要引入關系型數據庫?

  • 如果直接以上面的流程圖編碼,當出現變更后,有多少代碼可以復用?

    不過,也不要因此產生過度的設計。架構應當立足滿足當前需求,并適當的考慮重用和變更。

    2.1.2. 敏捷開發不需要架構

    極限編程,敏捷開發的出現使一些人誤以為軟件開發無需再做架構了。這是一個很大的誤解。敏捷開發是在傳統瀑布式開發流程出現明顯弊端后提出的解決方案,所以它必然有一個更高的起點和對開發更嚴格的要求。而不是倒退到石器時代。事實上,架構是敏捷開發的一部分,只不過在形式上,敏捷開發推薦使用更高效,簡單的方式來做設計。比如畫在白板上然后用數碼相機拍下的UML圖;用用戶故事代替用戶用例等。測試驅動的敏捷開發更是強迫工程師在寫實際代碼前設計好組件的功能和接口,而不是直接開始寫代碼。敏捷開發的一些特征:

  • 針對比傳統開發流程更大的系統

  • 承認變化,迭代架構

  • 簡潔而不混亂

  • 強調測試和重構

  • 2. 嵌入式環境下軟件設計的特點

    要談嵌入式的軟件架構,首先必須了解嵌入式軟件設計的特點。

    2.1. 和硬件密切相關

    嵌入式軟件普遍對硬件有著相當的依賴性。這體現在幾個方面:

  • 一些功能只能通過硬件實現,軟件操作硬件,驅動硬件。

  • 硬件的差異/變更會對軟件產生重大影響。

  • 沒有硬件或者硬件不完善時,軟件無法運行或無法完整運行。

  • 這些特點導致幾方面的后果:

  • 軟件工程師對硬件的理解和熟練程度會很大程度的決定軟件的性能/穩定性等非功能性指標,而這部分一向是相對復雜的,需要資深的工程師才能保證質量。

  • 軟件對硬件設計高度依賴,不能保持相對穩定,可維護性和可重用性差

  • 軟件不能離開硬件單獨測試和驗證,往往需要和硬件驗證同步進行,造成進度前松后緊,錯誤定位范圍擴大。

  • 針對這些問題,有幾方面的解決思路:

  • 用軟件實現硬件功能。選用更強大的處理器,用軟件來實現部分硬件功能,不僅可以降低對硬件的依賴,在響應變化,避免對特定型號和廠商的依賴方面都很有好處。這在一些行業里已經成為了趨勢。在PC平臺也經歷了這樣的過程,比如早期的漢卡。

  • 將對硬件的依賴獨立成硬件抽象層,盡可能使軟件的其他部分硬件無關,并可以脫離硬件運行。一方面將硬件變更甚至換件的風險控制在有限的范圍內,另一方面提高軟件部分的可測試性。

  • 2.2. 穩定性要求高

    大部分嵌入式軟件都對程序的長期穩定運行有較高的要求。比如手機經常幾個月開機,通訊設備則要求24*7正常運行,即使是通訊上的測試設備也要求至少正常運行8小時。為了穩定性的目標,有一些比較常用的設計手段:

  • 將不同的任務分布在獨立的進程中。良好的模塊化設計是關鍵

  • Watch Dog, Heart beat,重新啟動失效的進程。

  • 完善而統一的日志系統以快速定位問題。嵌入式設備一般缺乏有力的調試器,日志系統尤其重要。

  • 將錯誤孤立在最小的范圍內,避免錯誤的擴散和連鎖反應。核心代碼要經過充分的驗證,對非核心代碼,可以在監控或者沙盒中運行,避免其破壞整個系統。

  • 舉例,Symbian上的GPRS訪問受不同硬件和操作系統版本影響,功能不是非常穩定。其中有一個版本上當關閉GPRS連接時一定會崩潰,而且屬于known issue。將GPRS連接,HTTP協議處理,文件下載等操作獨立到一個進程中,雖然每次操作完畢該進程都會崩潰,對用戶卻沒有影響。

  • 雙備份這樣的手段較少采用

  • 2.3. 內存不足

    雖然當今的嵌入式系統的內存比之以K計數的時代已經有了很大的提高,但是隨著軟件規模的增長,內存不足的問題依然時時困擾著系統架構師。有一些原則,架構師在進行設計決策的時候可以參考:

    2.3.1. 虛擬內存技術

    有一些嵌入式設備需要處理巨大的數據量,而這些數據不可能全部裝入內存中。一些嵌入式操作系統不提供虛擬內存技術,比如WinCE4.2每個程序最多只能使用32M內存。對這樣的應用,架構師應該特別設計自己的虛擬內存技術。所謂的虛擬內存技術的核心是,將暫時不太可能使用的數據移出內存。這涉及到一些技術點:

  • 引用計數,正在使用的數據不能移出。

  • 使用預測,預測下一個階段某個數據的使用可能性。基于預測移出數據或者提前裝入數據。

  • 占位數據/對象。

  • 高速緩存。在復雜數據結果下緩存高頻率使用的數據,直接訪問。

  • 快速的持久化和裝載。

  • 下圖是一個全國電信機房管理系統的界面示意圖:

    每個節點下都有大量的數據需要裝載,可以使用上述技術將內存占用降到最低。

    2.3.2. 兩段式構造

    在內存有限的系統里,對象構造失敗是必須要處理的問題,失敗的原因中最常見的則是內存不足(實際上這也是對PC平臺的要求,但是在實際中往往忽略,因為內存實在便宜)。兩段式構造就是一種常用而有效的設計。舉例來說:

    CMySimpleClass: class CMySimpleClass {public:CMySimpleClass();~CMySimpleClass();...private:int SomeData; }; CMyCompoundClass: class CMyCompoundClass {public:CMyCompoundClass();~CMyCompoundClass();...private:CMySimpleClass* iSimpleClass; }; 在CMyCompoundClass的構造函數里初始化iSimpleClass對象。CMyCompoundClass::CMyCompoundClass() {iSimpleClass = new CMySimpleClass; }

    當創建CMyCompoundClass的時候會發生什么呢?

    CMyCompoundClass* myCompoundClass = new CMyCompoundClass;

  • 為CMyCompoundClass的對象分配內存

  • 調用CMyCompoundClass對象的構造函數

  • 在構造函數中創建一個CMySimpleClass的實例

  • 構造函數結束返回

  • 一切看起來都很簡單,但是如果第三步創建CMySimpleClass對象的時候發生內存不足的錯誤怎么辦呢?構造函數無法返回任何錯誤信息以提示調用者構造沒有成功。調用者于是獲得了一個指向CMyCompoundClass的指針,但是這個對象并沒有構造完整。

    如果在構造函數中拋出異常會怎么樣呢?這是個著名的噩夢,因為析構函數不會被調用,在創建CMySimpleClass對象之前如果分配了資源就會泄露。關于在構造函數中拋出異常可以單講一個小時,但是有一個建議是:盡量避免在構造函數中拋出異常。

    所以,使用兩段式構造法是一個更好的選擇。簡單的說,就是在構造函數避免任何可能產生錯誤的動作,比如分配內存,而把這些動作放在構造完成之后,調用另一個函數。比如:

    AddressBook* book = new AddressBook() If(!book->Construct()) {delete book;book = NULL; }

    這樣可以保證當Construct不成功的時候釋放已經分配的資源。

    在最重要的手機操作系統Symbian上,二段式構造法普遍使用。

    2.3.3. 內存分配器

    不同的系統有著不同的內存分配的特點。有些要求分配很多小內存,有的則需要經常增長已經分配的內存。一個好的內存分配器對嵌入式的軟件的性能有時具有重大的意義。應該在系統設計時保證整個系統使用統一的內存分配器,并且可以隨時更換。

    2.3.4. 內存泄漏

    內存泄漏對嵌入式系統有限的內存是非常嚴重的。通過使用自己的內存分配器,可以很容易的跟蹤內存的分配釋放情況,從而檢測出內存泄漏的情況。

    2.4. 處理器能力有限,性能要求高

    這里不討論實時系統,那是一塊很大的專業話題。對一般的嵌入式系統而言,由于處理器能力有限,要特別注意性能的問題。一些很好的架構設計由于不能滿足性能要求,最終導致整個項目的失敗。

    2.4.1. 抵御新技術的誘惑

    架構師必須明白,新技術常常意味著復雜和更低的性能。即使這不是絕對的,由于嵌入式系統硬件性能所限,彈性較低。一旦發現新技術有和當初設想不同之處,就更難通過修改來適應。比如GWT技術。這是Google推出的Ajax開發工具,它可以讓程序員像開發一個桌面應用程序一樣開發Web的Ajax程序。這使得在嵌入式系統上用一套代碼實現遠程和本地操作界面成為了很容易的一件事。但是在嵌入式設備上運行B-S結構的應用,性能上是一個很大的挑戰。同時,瀏覽器兼容方面的問題也很嚴重,GWT目前的版本還不夠完善。

    事實證明,嵌入式的遠程控制方案還是要采用Activex,VNC或者其他的方案。

    2.4.2. 不要有太多的層次

    分層結構有利于清晰的劃分系統職責,實現系統的解耦,但是每多一個層次,就意味著性能的一次損失。尤其是當層和層之間需要傳遞大量數據的時候。對嵌入式系統而言,在采用分層結構時要控制層次數量,并且盡量不要傳遞大量數據,尤其是在不同進程的層次之間。如果一定要傳遞數據,要避免大量的數據格式轉換,如XML到二進制,C++結構到Python結構。

    嵌入式系統能力有限,一定要將有限的能力用在系統的核心功能上。

    2.5. 存儲設備易損壞,速度較慢

    受體積和成本的限制,大部分的嵌入式設備使用諸如Compact Flash, SD, mini SD, MMC等作為存儲設備。這些設備雖然有著不擔心機械運動損壞的優點,但是其本身的使用壽命都比較短暫。比如,CF卡一般只能寫100萬次。而SD更短,只有10萬次。對于像數碼相機這樣的應用,也許是足夠的。但是對于需要頻繁擦寫磁盤的應用,比如歷史數據庫,磁盤的損壞問題會很快顯現。比如有一個應用式每天向CF卡上寫一個16M的文件,文件系統是FAT16, 每簇大小是2K,那么寫完這個16M的文件,分區表需要寫8192次,于是一個100萬次壽命的CF實際能夠工作的時間是1000000/8192 = 122天。而損壞的時候,CF卡的其他絕大部分地方的使用次數不過萬分之一。

    除了因為靜態的文件分區表等區塊被頻繁的讀寫而提前損壞,一些嵌入式設備還要面對直接斷電的挑戰,這會在存儲設備上產生不完整的數據。

    2.5.1. 損耗均衡

    損耗均衡的基本思路是平均地使用存儲器上的各個區塊。需要維護一張存儲器區塊使用情況的表,這個表包括區塊的偏移位置,當前是否可用,以及已經擦寫地次數。當有新的擦寫請求的時候,根據以下原則選擇區塊:

  • 盡量連續

  • 擦寫次數最少

  • 即使是更新已經存在的數據,也會使用以上原則分配新的區塊。同樣,這張表的存放位置也不能是固定不變的,否則這張表所占據的區塊就會最先損壞。當要更新這張表的時候,同樣要使用以上算法分配區塊。

    如果存儲器上有大量的靜態數據,那么上述算法就只能針對剩下的空間生效,這種情況下還要實現對這些靜態數據的搬運的算法。但是這種算法會降低寫操作的性能,也增加了算法的復雜度。一般都只使用動態均衡算法。

    目前比較成熟的損耗均衡的文件系統有JFFS2, 和 YAFFS。也有另一種思路就是在FAT16等傳統文件系統上實現損耗均衡,只要事先分配一塊足夠大的文件,在文件內部實現損耗均衡算法。不過必須修改FAT16的代碼,關閉對最后修改時間的更新。

    現在的CF卡和SD卡有的已經在內部實現了損耗均衡,這種情況下就不需要軟件實現了。

    2.5.2. 錯誤恢復

    如果在向存儲器寫數據的時候發生斷電或者被拔出,那么所寫的區域的數據就處于未知的狀態。在一些應用中,這會導致不完整的文件,而在另一些應用中,則會導致系統失敗。所以對這類錯誤的恢復也是嵌入式軟件設計必須考慮的。常用的思路有兩種:

  • 日志型的文件系統

  • 這種文件系統并不是直接存儲數據,而是一條條的日志,所以當發生斷電的時候,總可以恢復到之前的狀態。這類文件系統的代表如ext3。

  • 雙備份

  • 雙備份的思路更簡單,所有的數據都寫兩份。每次交替使用。文件分區表也必須是雙備份的。假設有數據塊A,A1是他的備份塊,在初始時刻和A的內容是一致的。在分區表中,F指向數據塊A,F1是他的備份塊。當修改文件時,首先修改數據塊A1的內容,如果此時斷電,A1的內容錯誤,但因為F指向的是完好的A,所以數據沒有損壞。如果A1修改成功,則修改F1的內容,如果此時斷電,因為F是完好的,所以依然沒有問題。

    現在的Flash設備,有的已經內置錯誤檢測和錯誤校正技術,可以保證在斷電時數據的完整。還有的包括自動的動態/靜態損耗均衡算法和壞塊處理,完全無須上層軟件額外對待,可以當作硬盤使用。所以,硬件越發達,軟件就會越可靠,技術不斷的進步,將讓我們可以把更多的精力投入到軟件功能的本身,這是發展的趨勢。

    2.6. 故障成本高昂

    嵌入式產品都是軟硬件一起銷售的給用戶的,所以這帶來了一個純軟件所不具備的問題,那就是當產品發生故障時,如果需要返廠才能修復,則成本就很高。嵌入式設備常見有以下的幾類故障:

    a) 數據故障。由于某些原因導致數據不能讀出或者不一致。比如斷電引起的數據庫錯誤。

    b) 軟件故障。軟件本身的缺陷,需要通過發布補丁程序或者新版本的軟件修正。

    c) 系統故障。比如用戶下載了錯誤的系統內核,導致系統無法啟動。

    d) 硬件故障。這種故障只有返廠,不屬于我們的討論范圍。

    針對前三類故障,要盡可能保證客戶自己,或者現場技術人員就可以解決。從架構的角度考慮,如下原則可以參考:

    a) 使用具備錯誤恢復能力的數據管理設計。當數據發生錯誤時,用戶可以接受的處理依次是:

    i. 錯誤被糾正,所有數據有效

    ii. 錯誤發生時的數據(可能不完整)丟失,之前的數據有效。

    iii. 所有數據丟失

    iv. 數據引擎崩潰無法繼續工作

    一般而言,滿足第二個條件即可。(日志,事務,備份,錯誤識別)

    b) 將應用程序和系統分離。應用程序應該放置在可插拔的Flash卡上,可以通過讀卡器進行文件復制升級。非必要的情況不要使用專用應用軟件來升級應用程序。

    c) 要有“安全模式”。即當主系統被損壞后,設備依然可以啟動,重新升級系統。常見的uboot可以保證這一點,在系統損壞后,可以進入uboot通過tftp重新升級。

    3. 軟件框架

    在桌面系統和網絡系統上,框架是普遍應用的,比如著名的ACE, MFC, Ruby On Rails等。而在嵌入式系統中,框架則是很少使用的。究其原因,大概是認為嵌入式系統簡單,沒有重復性,過于注重功能的實現和性能的優化。在前言中我們已經提到,現在的嵌入式發展趨勢是向著復雜化,大型化,系列化發展的。所以,在嵌入式下設計軟件框架也是很有必要,也很有價值的。

    3.1. 嵌入式軟件架構面臨的問題

    前面我們講到,嵌入式系統軟件架構所面臨的一些問題,其中很重要的一點是,對硬件的依賴和硬件相關軟件的復雜性。還包括嵌入式軟件在穩定性和內存占用等方面的苛刻要求。如果團隊中的每個人都是這些方面高手的話,也許有可能開發出高質量的軟件,但事實是一個團隊中可能只有一兩個資深人員,其他大部分都是初級工程師。人人都去和硬件打交道,都負責穩定性,性能等等指標的話,是很難保證最終產品質量的。如果組件團隊時都是精通硬件等底層技術的人才,又很難設計出在可用性,擴展性等方面出色的軟件。術業有專攻,架構師的選擇決定著團隊的組成方式。

    同時,嵌入式軟件開發雖然復雜,但是也存在大量的重用的可能性。如何重用,又如何應對將來的變更?

    所以,如何將復雜性對大多數人屏蔽,如何將關注點分離,如何保證系統的關鍵非功能指標,是嵌入式軟件架構設計師應該解決的問題。一種可能的解決方案就是軟件框架。

    3.2. 什么是框架

    框架是在一個給定的問題領域內,為了重用和應對未來需求變化而設計的軟件半成品。框架強調對特定領域的抽象,包含大量的專業領域知識,以縮短軟件的開發周期,提高軟件質量為目的。使用框架的二次開發者通過重寫子類或組裝對象的方式來實現特殊的功能。

    3.2.1. 軟件復用的層次

    復用是在我們經常談到的話題,“不要重復發明輪子”也是耳熟能詳的戒條。不過對于復用的理解實際上是有很多個層次的。

    最基礎的復用是復制粘貼。某個功能以前曾經實現過,再次需要的時候就復制過來,修改一下就可以使用。經驗豐富的程序員一般都會有自己的程序庫,這樣他們實現的時候就會比新的程序員快。復制粘貼的缺點是代碼沒有經過抽象,往往并不完全的適用,所以需要進行修改,經過多次復用后,代碼將會變得混亂,難以理解。很多公司的產品都有這個問題,一個產品的代碼從另一個產品復制而來,修改一下就用,有時候甚至類名變量名都不改。按照“只有為復用設計的代碼才能真正復用”的標準,這稱不上是復用,或者說是低水平的復用。

    更高級的復用是則是庫。這種功能需要對經常使用的功能進行抽象,提取出其中恒定不變的部分,以庫的形式提供給二次開發程序員使用。因為設計庫的時候不知道二次開發者會如何使用,所以對設計者有著很高的要求。這是使用最廣泛的一種復用,比如標準C庫,STL庫。現在非常流行的Python語言的重要優勢之一就是其庫支持非常廣泛,相反C++一直缺少一個強大統一的庫支持,成為短板。在公司內部的開發中總結常用功能并開發成庫是很有價值的,缺點是對庫的升級會影響到很多的產品,必須慎之又慎。

    框架是另一種復用。和庫一樣,框架也是對系統中不變的部分進行抽象并加以實現,由二次開發者實現其他變化的部分。典型的框架和庫的最大的區別是,庫是靜態的,由二次開發者調用的;框架是活著的,它是主控者,二次開發者的代碼必須符合框架的設計,由框架決定在何時調用。

    舉個例子,一個網絡應用總是要涉及到連接的建立,數據收發和連接的關閉。以庫的形式提供是這樣的:

    conn = connect(host,port); if(conn.isvalid()) {data = conn.recv();printf(data);conn.close(); }

    框架則是這樣的:

    class mycomm:class connect { public:host();port();onconnected();ondataarrived(unsigned char* data, int len);onclose(); };

    框架會在“適當”的時機創建mycomm對象,并查詢host和port,然后建立連接。在連接建立后,調用onconnected()接口,給二次開發者提供進行處理的機會。當數據到達的時候調用ondataarrived接口讓二次開發者處理。這是好萊塢原則,“不要來找我們,我們會去找你”。

    當然,一個完整的框架通常也要提供各種庫供二次開發者使用。比如MFC提供了很多的庫,如CString, 但本質上它是一個框架。比如實現一個對話框的OnInitDialog接口,就是由框架規定的。

    3.2.2. 針對高度特定領域的抽象

    和庫比較起來,框架是更針對特定領域的抽象。庫,比如C庫,是面向所有的應用的。而框架相對來說則要狹窄的多。比如MFC提供的框架只適合于Windows平臺的桌面應用程序開發,ACE則是針對網絡應用開發的框架,Ruby On Rails是為快速開發web站點設計的。

    越是針對特定的領域,抽象就可以做的越強,二次開發就可以越簡單,因為共性的東西越多。比如我們上面談到嵌入式系統軟件開發的諸多特點,這就是特定領域的共性,就屬于可以抽象的部分。具體到實際的嵌入式應用,又會有更多的共性可以抽象。

    框架的設計目的是總結特定領域的共性,以框架的方式實現,并規定二次開發者的實現方式,從而簡化開發。相應的,針對一個領域開發的框架就不能服務于另一個領域。對企業而言,框架是一種極好的積累知識,降低成本的技術手段。

    3.2.3. 解除耦合和應對變化

    框架設計的一個重要目的就是應對變化。應對變化的本質就是解耦。從架構師的角度看,解耦可以分為三種:

  • 邏輯解耦。邏輯解耦是將邏輯上不同的模塊抽象并分離處理。如數據和界面的解耦。這也是我們最常做的解耦。

  • 知識解耦。知識解耦是通過設計讓掌握不同知識的人僅僅通過接口工作。典型的如測試工程師所掌握的專業知識和開發工程師所掌握的程序設計和實現的知識。傳統的測試腳本通常是將這二者合二為一的。所以要求測試工程師同時具備編程的能力。通過適當的方式,可以讓測試工程師以最簡單的方式實現他的測試用例,而開發人員編寫傳統的程序代碼來執行這些用例。

  • 變與不變的解耦。這是框架的重要特征。框架通過對領域知識的分析,將共性,也就是不變的內容固定下來,而將可能發生變化的部分交給二次開發者實現。

  • 3.2.4. 框架可以實現和規定非功能性需求

    非功能性需求是指如性能,可靠性,可測試性,可移植性等。這些特性可以通過框架來實現。以下我們一一舉例。

    性能。對性能的優化最忌諱的就是普遍優化。系統的性能往往取決于一些特定的點。比如在嵌入式系統中,對存儲設備的訪問是比較慢的。如果開發者不注意這方面的問題,頻繁的讀寫存儲設備,就會造成性能下降。如果對存儲設備的讀寫由框架設計,二次開發者只作為數據的提供和處理者,那么就可以在框架中對讀寫的頻率進行調節,從而達到優化性能的目的。由于框架都是單獨開發的,完成后供廣泛使用,所以就有條件對關鍵的性能點進行充分的優化。

    可靠性。以上面的網絡通訊程序為例,由于框架負責了連接的創建和管理,也處理了各種可能的網絡錯誤,具體的實現者無須了解這方面的知識,也無須實現這方面錯誤處理的代碼,就可以保證整個系統在網絡通訊方面的可靠性。以框架的方式設計在可靠性方面的最大優勢就是:二次開發的代碼是在框架的掌控之內運行的。一方面框架可以將容易出錯的部分實現,另一方面對二次開發的代碼產生的錯誤也可以捕獲和處理。而庫則不能代替使用者處理錯誤。

    可測試性。可測試性是軟件架構需要考慮的一個重要方面。下面的章節會講到,軟件的可測試性是由優良的設計來保證的。一方面,由于框架規定了二次開發的接口,所以可以迫使二次開發者開發出便于進行單元測試的代碼。另一方面,框架也可以在系統測試的層面上提供易于實現自動化測試和回歸測試的設計,例如統一提供的TL1接口。

    可移植性。如果軟件的可移植性是軟件設計的目標,框架設計者可以在設計階段來保證這一點。一種方式是通過跨平臺的庫來屏蔽系統差異,另一種可能的方式更加極端,基于框架的二次開發可以是腳本化的。組態軟件是這方面的一個例子,在PC上組態的工程,也可以在嵌入式設備上運行。

    3.3. 一個框架設計的實例

    3.3.1. 基本架構

    3.3.2. 功能特點

    上面是一個產品系列的架構圖,其特點是硬件部分是模塊化的,可以隨時插拔。不同的硬件應用于不同的通訊測試場合。比如光通訊測試,xDSL測試,Cable Modem測試等等。針對不同的硬件,需要開發不同的固件和軟件。固件層的功能主要是通過USB接口接收來自軟件的指令,并讀寫相應的硬件接口,再進行一些計算后,將結果返回給軟件。軟件運行在WinCE平臺,除了提供一個觸摸式的圖形化界面外,還對外提供基于XML(SOAP)接口和TL1接口。為了實現自動化測試,還提供了基于Lua的腳本語言接口。整個產品系列有幾十個不同的硬件模塊,相應的需要開發幾十套軟件。這些軟件雖然服務于不同的硬件,但是彼此之間有著高度的相似性。所以,選擇先開發一個框架,再基于框架開發具體的模塊軟件成了最優的選擇。

    ### 3.3.3. 分析

    軟件部分的結構分析如下:

    系統分為軟件,固件和硬件三大塊。軟件和固件運行在兩塊獨立的板子上,有各自的處理器和操作系統。硬件則插在固件所在的板子上,是可以替換的。

    軟件和固件其實都是軟件,下面我們分別分析。

    軟件

    軟件的主要工作是提供各種用戶界面。包括本地圖形化界面,SOAP訪問界面,TL1訪問界面。

    整個軟件部分分為五大部分:

    • 通訊層

    • 協議層

    • 圖形界面

    • SOAP服務器

    • TL1服務器

    通訊層要屏蔽用戶對具體通信介質和協議的了解,無論是USB還是socket,對上層都不產生影響。通訊層負責提供可靠的通訊服務和適當的錯誤處理。通過配置文件,用戶可以改變所使用的通訊層。

    協議層的目的是將數據進行編碼和解碼。編碼的產生物是可以在通訊層發送的流,按照嵌入式軟件的特點,我們選擇二進制作為流的格式。解碼的產生物是多種的,既有供界面使用的C Struct,也可以是XML數據,還可以是Lua的數據結構(tablegt)。如果需要,還可以產生JSON,TL1,Python數據,TCL數據等等。這一層在框架中是通過機器自動生成的,我們后面會講到。

    內存數據庫,SOAP Server和TL1 Server都是協議層的用戶。圖形界面通過讀寫內存數據庫和底層通訊。

    圖形界面是框架設計的重點之一,原因是這里工作量最大,重復而無聊的工作最多。

    讓我們分析一下在圖形界面開發工作中最主要的事情是什么。

  • 收集用戶輸入的數據和命令

  • 將數據和命令發給底層

  • 接收底層反饋

  • 將數據顯示在界面上

  • 同時有一些庫用來進一步簡化開發:

    這是一個簡化的例子,但是很好的說明了框架的特點:

  • 客戶代碼必須按照規定的接口實現

  • 框架在適當的時候調用客戶實現的接口

  • 每個接口都被設計為只完成特定的單一功能

  • 將各個步驟有機的串起來是框架的事,二次開發者不知道,也無須知道。

  • 通常都要有附帶的庫。

  • 固件

    固件的主要工作是接受來自軟件的命令,驅動硬件工作;獲取硬件的狀態,進行一定的計算后返回給軟件。早期的固件是很薄的一層,因為絕大部分工作是由硬件完成的,固件只起到一個中轉通訊的作用。隨著時代發展,現在的固件開始承擔越來越多原來由硬件完成的工作。

    整個固件部分分為五大部分:

    硬件抽象層,提供對硬件的訪問接口

    互相獨立的任務群

    任務/消息派發器

    協議層

    通訊層

    針對不同的設備,工作量集中在硬件抽象層和任務群上。硬件抽象層是以庫的形式提供的,由對硬件最熟悉,經驗最豐富的工程師來實現。任務群則由一系列的任務組成,他們分別代表不同的業務應用。比如測量誤碼率。這部分由相對經驗較少的工程師來實現,他們的主要工作是實現規定的接口,按照標準化文檔定義的方式實現算法。

    任務定義了如下接口,由具體開發者來實現:

    OnInit(); OnRegisterMessage(); OnMessageArrive(); Run(); OnResultReport();

    框架的代碼流程如下:(偽代碼)

    CTask* task = new CBertTask(); task->OnInit(); task->OnRegisterMessage(); while(TRUE) {task->OnMessageArrive();task->Run();task->OnResultReport(); } delete task; task = NULL;

    這樣,具體任務的實現者所關注的最重要的事情就是實現這幾個接口。其他如硬件的初始化,消息的收發,編碼解碼,結果的上報等等事情都由框架進行了處理。避免了每個工程師都必須處理從上到下的所有方面。并且這樣的任務代碼還有很高的重用性,比如是在以太網上還是在Cable Modem上實現PING的算法都是一樣的。

    3.3.4. 實際效果

    在實際項目中,框架大大降低了開發難度。對軟件部分尤其明顯,由實習生即可完成高質量的界面開發,開發周期縮短50%以上。產品質量大大提升。對固件部分的貢獻在于降低了對精通底層硬件的工程師的需要,一般的工程師熟知測量算法即可。同時,框架的存在保證了性能,穩定和可測試性等要素。

    3.4. 框架設計中的常用模式

    3.4.1. 模板方法模式

    模板方法模式是框架中最常用的設計模式。其根本的思路是將算法由框架固定,而將算法中具體的操作交給二次開發者實現。例如一個設備初始化的邏輯,框架代碼如下:

    TBool CBaseDevice::Init() {if ( DownloadFPGA() != KErrNone ){LOG(LOG_ERROR,_L(“Download FPGA fail”));return EFalse;}if ( InitKeyPad() != KerrNone ){LOG(LOG_ERROR,_L(“Initialize keypad fail”));return EFalse;}return ETrue; }

    DownloadFPGA和InitKeyPad都是CBaseDevice定義的虛函數,二次開發者創建一個繼承于CBaseDevice的子類,具體來實現這兩個接口。框架定義了調用的次序和錯誤的處理方式,二次開發者無須關心,也無權決定。

    3.4.2. 創建型模式

    由于框架通常都涉及到各種不同子類對象的創建,創建型模式是經常使用的。例如一個繪圖軟件的框架,有一個基類定義了圖形對象的接口,基于它可以派生出橢圓,矩形,直線各種子類。當用戶繪制一個圖形時,框架就要實例化該子類。這時候可以用工廠方法,原型方法等等。

    class CDrawObj {public:virtual int DrawObjTypeID()=0;virtual Icon GetToolBarIcon()=0;virtual void Draw(Rect rect)=0;virtual CDrawObj* Clone()=0; };

    3.4.3. 消息訂閱模式

    消息訂閱模式是最常用的分離數據和界面的方式。界面開發者只需要注冊需要的數據,當數據變化時框架就會將數據“推”到界面。界面開發者可以無須關注數據的來源和內部組織形式。

    消息訂閱模式最常見的問題是同步模式下如何處理重入和超時。作為框架設計者,一定要考慮好這個問題。所謂重入,是二次開發者在消息的回調函數中執行訂閱/取消訂閱的操作,這會破壞消息訂閱的機制。所謂超時是指二次開發者的消息回調函數處理時間過長,導致其他消息無法響應。最簡單的辦法是使用異步模式,讓訂閱者和數據發布者在獨立進程/線程中運行。如果不具備此條件,則必須作為框架的重要約定,禁止二次開發者產生此類問題。

    3.4.4. 裝飾器模式

    裝飾器模式賦予了框架在后期增加功能的能力。框架定義裝飾器的抽象基類,而由具體的實現者實現,動態地添加到框架中。

    舉一個游戲中的例子,圖形繪制引擎是一個獨立的模塊,比如可以繪制人物的靜止,跑動等圖像。如果策劃決定在游戲中增加一種叫“隱身衣”的道具,要求穿著此道具的玩家在屏幕上顯示的是若有若無的半透明圖像。應該如何設計圖像引擎來適應后期的游戲升級呢?

    當隱身衣被裝備后,就向圖像引擎添加一個過濾器。這是個極度簡化的例子,實際的游戲引擎要比這個復雜。裝飾器模式還常見用于數據的前置和后置處理上。

    3.5. 框架的缺點

    一個好的框架可以大大提高產品的開發效率和質量,但也有它的缺點。

  • 框架一般都比較復雜,設計和實現一個好的框架需要相當的時間。所以,一般只有在框架可以被多次反復應用的時候適合,這時候,前提投入的成本會得到豐厚的回報。

  • 框架規定了一系列的接口和規則,這雖然簡化了二次開發工作,但同時也要求二次開發者必須記住很多規定,如果違反了這些規定,就不能正常工作。但是由于框架屏蔽了大量的領域細節,相對而言,其學習成本還是大大降低了的。

  • 框架的升級對已有產品可能會造成嚴重的影響,導致需要完整的回歸測試。對這個問題有兩個辦法。第一是對框架本身進行嚴格的測試,有必要建立完善的單元測試庫,同時開發示例項目,用來測試框架的所有功能。第二則是使用靜態鏈接,讓已有產品不輕易跟隨升級。當然,如果已有產品有較好的回歸測試手段,就更好。

  • 性能損失。由于框架對系統進行了抽象,增加了系統的復雜性。諸如多態這樣的手段使用也會普遍的降低系統的性能。但是從整體上來看,框架可以保證系統的性能處于一個較高的水平。

  • 4. 自動代碼生成

    4.1. 機器能做的事就不要讓人來做

    懶惰是程序員的美德,更是架構師的美德。軟件開發的過程就是人告訴機器如何做事的過程。如果一件事情機器自己就可以做,那就不要讓人來做。因為機器不僅不知疲倦,而且絕不會犯錯。我們的工作是讓客戶的工作自動化,多想一點,就能讓我們自己的工作也部分自動化。極有耐心的程序員是好的,也是不好的。

    經過良好設計的系統,往往會出現很多高度類似而且具有很強規律的代碼。未經良好設計的系統則可能對同一類功能產生很多不同的實現。前面關于框架設計的部分已經證明了這一點。有時候,我們更進一步,分析出這些相似代碼之中的規律,用格式化的數據來描述這些功能,而由機器來產生代碼。

    4.2. 舉例

    4.2.1. 消息的編碼和解碼

    上面關于框架的實例中,可以看到消息編解碼的部分已經被獨立出來,和其他部分沒有耦合。加上他本身的特點,非常適合進一步將其“規則化”,用機器產生代碼。

    編碼,就是把數據結構流化;解碼反之。以編碼為例,代碼無非是這樣的:(二進制協議)

    stream << a.i; stream << a.j; stream << a.object;

    (為了簡化,這里假設已經設計了一個流對象,可以流化各種數據類型,并且已經處理了諸如字節序轉換等問題。)

    最后我們得到一個stream。大家是否已經習慣了寫這種代碼?但是這樣的代碼不能體現工程師任何的創造性,因為我們早已經知道有i, 有j, 還有一個object,為什么還要自己敲入這些代碼呢?如果我們分析一下a的定義,是不是就可以自動產生這樣的代碼呢?

    struct dataA {int i;int j;struct dataB object; };

    只需要一個簡單的語義分析器解析這段代碼,得到一棵關于數據類型的樹,就可以輕易的產生流化的代碼。這樣的分析器用Python等字符串處理能力強的語言不過兩百行左右。關于數據類型的樹類似下圖:

    只要遍歷這棵樹,就可以生成所有數據結構的流化代碼。

    在上一個框架所舉例的項目中,為一個硬件模塊自動產生的消息編碼解碼器代碼量高達三萬行,幾乎相當于一個小軟件。由于是自動產生,沒有任何錯誤,為上層提供了高可靠性。

    還可以用XML或者其他的格式定義數據結構,從而產生自動代碼。根據需要,C++/Java/Python,任何類型的都可以。如果希望提供強檢查,可以使用XSD來定義數據結構。有一個商業化的產品,xBinder,很貴,很難用,還不如自己開發。(為什么難用?因為它太通用)。除了編碼為二進制格式,還可以編碼為任何你需要的格式。我們知道二進制格式雖然效率很高,但是太難調試(當然有些人看內存里的十六進制還是很快的),所以我們可以在編碼成二進制的同時,還生成編碼為其他可閱讀的格式的代碼,比如XML。這樣,通訊使用二進制,而調試使用XML,兩全其美。產生二進制的代碼大概是這樣的:

    Xmlbuilder.addelement(“i”,a.i); Xmlbuilder.addelement(“j”,a.j); Xmlbuilder.addelement(“object”,a.object);

    同樣也很適合機器產生。同樣的思路可以用來讓軟件內嵌腳本支持。這里不多說了。(內嵌腳本支持最大的問題是在C/C++和腳本之間交換數據,也是針對數據類型的大量相似代碼。)

    最近Google 發布了它的protocol buffer,就是這樣的思路。目前支持C++/Python,估計很快會支持更多的語言,大家可以關注。以后就不要再手寫編碼解碼器了。

    4.2.2. GUI代碼

    上面的框架設計部分,我們說到框架對界面數據收集和界面更新無能為力,只能抽象出接口,由程序員具體實現。但是讓我們看看這些界面程序員做的事情吧。(代碼經過簡化,可以看作偽代碼)。

    void onDataArrive(CDataBinder& data) {m_biterror.setText(“%d”,data.biterror);m_signallevel.setText(“%d”,data.signallevel”);m_latency.setText(“%d”,data.latency”); }Void onCollectData(CDataBinder& data) {data.biterror = atoi(m_biterror.getText());data. signallevel = atoi(m_ signallevel.getText());data. latency = atoi(m_ latency.getText()); }

    這樣的代碼很有趣嗎?想想我們可以怎么做?(XML描述界面,問題是對于復雜邏輯很難)

    4.2.3. 小結

    由此可見,在軟件架構的過程中,首先要遵循一般性的原則,盡量將系統各個功能部分獨立出來,實現高內聚低耦合,進而發現系統存在的高度重復,規律性很強的代碼,進一步將他們規則化,形式化,最后用機器來產生這些代碼。目前這方面最成功的應用就是消息的編解碼。對界面代碼的自動化生成有一定局限,但也可以應用。大家在自己的工作中要擅于發現這樣的可能,減少工作量,提高工作效率。

    4.2.4. Google Protocol Buffer

    Google剛剛發布的Protocol Buffer是使用代碼自動生成的一個典范。

    Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. You can even update your data structure without breaking deployed programs that are compiled against the "old" format.

    你要做的首先是定義消息的格式,Google指定了它的格式:

    message Person {required string name = 1;required int32 id = 2;optional string email = 3;enum PhoneType {MOBILE = 0;HOME = 1;WORK = 2; } message PhoneNumber {required string number = 1;optional PhoneType type = 2 [default = HOME]; }repeated PhoneNumber phone = 4; }

    Once you've defined your messages, you run the protocol buffer compiler for your application's language on your .proto file to generate data access classes. These provide simple accessors for each field (like query() and set_query()) as well as methods to serialize/parse the whole structure to/from raw bytes – so, for instance, if your chosen language is C++, running the compiler on the above example will generate a class called Person. You can then use this class in your application to populate, serialize, and retrieve Person protocol buffer messages. You might then write some code like this:

    Person person; person.set_name("John Doe"); person.set_id(1234); person.set_email("jdoe@example.com"); fstream output("myfile", ios::out | ios::binary); person.SerializeToOstream(&output); Then, later on, you could read your message back in: fstream input("myfile", ios::in | ios::binary); Person person; person.ParseFromIstream(&input); cout << "Name: " << person.name() << endl; cout << "E-mail: " << person.email() << endl;

    Protocol Buffer的編碼格式是二進制的,同時也提供可讀的文本格式。效率高,體積小,上下兼容。目前支持Java,Python和C++,很快會支持更多的語言。

    5. 面向語言編程(LOP)

    5.1. 從自動化代碼生成更進一步

    面向語言編程的通俗定義是:將特定領域的知識融合到一種專用的計算機語言當中,從而提高人與計算機交流的效率。

    自動化代碼生成其實就是面向語言編程。語言不等于是編程語言,可以是圖,也可以是表,任何可以建立人和機器之間交流渠道的都是計算機語言。軟件開發歷史上的一次生產率的飛躍是高級語言的發明。它讓我們以更簡潔的方式實現更復雜的功能。但是高級語言也有它的缺點,那就是從問題領域到程序指令的過程很復雜。因為高級語言是為通用目的而設計的,所以離問題領域很遠。舉例來說,要做一個圖形界面,我可以跟另一個工程師說:這里放一個按鈕,那邊放一個輸入框,當按下按鈕的時候,就在輸入框里顯示Hello World。我甚至可以隨手給他畫出來。

    對于我和他直接的交流而言,這已經足夠了,5分鐘。但是要讓轉變為計算機能夠理解的語言,需要多久?

    如果是匯編語言?(告訴計算機如何操作寄存器和內存)

    如果是C++? (告訴計算機如何在屏幕上繪圖,如果響應鼠標鍵盤消息)

    如果有一個不錯的圖形界面庫?(告訴計算機創建Button,Label對象,管理這些對象,放置這些對象,處理消息)

    如果有一個不錯的開發框架+IDE? (用WYSIWYG工具繪制,設計類,類的成員變量,編寫消息響應函數)

    如果有一門專門做圖形界面開發的語言?

    可以是這樣的:

    Label l {Text=””} Button b{Text=”ok”,action=l.Text=”hello world”}

    通用的計算機語言是基于變量,類,分支,循環,鏈表,消息這些概念的。這些概念離問題本身有著遙遠的距離,而且表達能力非常有限。自然語言表達能力很強,但是歧義和冗余太多,無法格式化標準化。傳統的思想告訴我們:計算機語言就是一條條的指令,編程就是寫下這些指令。而面向語言編程的思想是,用盡量貼近問題,貼近人的思維的辦法來描述問題,從而降低從人的思想到計算機軟件轉換的難度。

    舉一個游戲開發的例子。現在的網絡游戲普遍的采用了C++或者C開發游戲引擎。而具體的游戲內容,則是由一系列二次開發工具和語言完成的。地圖編輯器就是一種面向游戲的語言。Lua或者類似的腳本則被嵌入到游戲內部,用來編寫武器,技能,任務等等。Lua本身不具備獨立開發應用程序的能力,然而游戲引擎的設計者通過給Lua提供一系列的,各種層次上的接口,將領域知識密集的賦予了腳本,從而大大提高了游戲二次開發的效率。網絡游戲的鼻祖MUD則是設計了LPC來作為游戲的開發語言。MUD的引擎MudOS和LPC之間的關系如圖:

    用LPC創建一個NPC的代碼類似如下:

    inherit NPC; void create() {set_name("菜花蛇", ({ "caihua she", "she" }) );set("race", "野獸");set("age", 1);set("long", "一只青幽幽的菜花蛇,頭部呈橢圓形。n");set("attitude", "peaceful");set("str", 15);set("cor", 16);set("limbs", ({ "頭部", "身體", "七寸", "尾巴" }) );set("verbs", ({ "bite" }) );set("combat_exp", 100+random(50));set_temp("apply/attack", 7);set_temp("apply/damage", 4);set_temp("apply/defence",6);set_temp("apply/armor",5);setup(); } void die() {object ob;message_vision("$N抽搐兩下,$N死了。n", this_object());ob = new(__DIR__"obj/sherou");ob->move(environment(this_object()));destruct(this_object()); }

    LPC培養了一大批業余游戲開發者,甚至成為很多人進入IT行業的起點。原因就是它簡單,易理解,100%為游戲開發設計。這就是LOP的魅力。

    5.2. 優勢和劣勢

    LOP最重要的優點是將領域知識固化到語言中,從而:

  • 提高開發效率。

  • 優化團隊結構,降低交流成本,領域專家和程序員可以更好的合作。

  • 降低耦合,易于維護。

  • 其次,由于LOP不是通用語言,所涉及的范圍就狹窄很多,所以:

  • 更容易得到穩定的系統

  • 更容易移植

  • 相應的,LOP也有它的劣勢:

  • LOP對領域知識抽象的要求比框架更高。

  • 開發一門新的語言本身的成本。幸好現在設計一門新的語言不算太難,還有Lua這樣的“專用二次開發”語言的支持。

  • 性能損失。不過相比開發成本的節約,在非性能核心部分使用LOP還是很值得的。

  • 5.3. 在嵌入式系統中的應用

    舉例,嵌入式設備的Web服務器。很多設備都提供Web服務用于配置,比如路由器,ADSL貓等等。這種設備所提供的web服務的典型用例是用戶填寫一些參數,提交給Web服務器,Web 服務器將這些參數寫入硬件,并將操作結果或者其他信息生成頁面返回給瀏覽器。由于典型的Apache,Mysql,PHP組合體積太大且不容易移植,通常嵌入式系統的Web服務都是用C/C++直接寫就的。從socket管理,http協議到具體操作硬件,生成頁面,都一體負責。然而對于功能復雜,Web界面要求較高的情況,用C來寫頁面效率就太低了。

    shttpd是一個小巧的web服務器,小巧到只有一個.c文件,4000余行代碼。雖然體積很小,卻具備了最基本的功能,比如CGI。它既可以獨立運行,也可以嵌入到其他的應用程序當中。shttpd在大多數平臺上都可以順利編譯、運行。lua是一個小巧的腳本語言,專用于嵌入和擴展。它和C/C++代碼有著良好的交互能力。

    將Lua引擎嵌入到shttpd中,再使用C編寫一個(一些)驅動硬件的擴展,注冊成為Lua的函數,形成的系統結構如下圖:

    這樣的應用在嵌入式系統中是有一定代表性的,即,以C實現底層核心功能,而把系統的易變部分以腳本實現。大家可以思考在自己的開發過程中是否可以使用這種技術。這是LOP的一種具體應用模式。(沒有創造一種全新的語言,而是使用Lua)

    6. 測試

    6.1. 可測試性是軟件質量的一個度量指標

    好的軟件是設計出來的,好的軟件也一定是便于測試的。一個難于測試的軟件的質量是難以得到保障的。在今天軟件規模越來越大的趨勢下,以下問題是普遍存在的:

  • 測試只能手工進行,回歸測試代價極大,實際只能執行點測,質量無法保證

  • 各個模塊只有集成到一起后才能測試

  • 代碼不經過任何單元測試就集成

  • 這些問題的根源都在于缺乏一個良好的軟件設計。一個好的軟件設計應該使得單元測試,模塊測試和回歸測試都變得容易,從而保證測試的廣度和深度,最終產生高質量的軟件。除了功能,非功能性需求也必須是可測試的。所以,可測試性是軟件設計中一個重要的指標,是系統架構師需要認真考慮的問題。

    6.2. 測試驅動的軟件架構

    這里談的是測試驅動的軟件架構,而不是測試驅動的開發。TDD(Test Driven Development) 是一種開發方式,是一種編碼實踐。而測試驅動的架構強調的是,從提高可測試性的角度進行架構設計。軟件的測試分為多個層次:

    6.3. 系統測試

    系統測試是指由測試人員執行的,驗證軟件是否完整正確的實現了需求的測試。這種測試中,測試人員作為用戶的角色,通過程序界面進行測試。在大部分情況下這些工作是手工完成的。在規范的流程中,這個過程通常要占到整個軟件開發時間的1/3以上。而當有新版本發布的時候,盡管只涉及了軟件的一部分,測試部門依然需要完整的測試整個軟件。這是由代碼“副作用”特點決定的。有時候修改一個bug可以引發更多的bug,破壞原來工作正常的代碼。這在測試中叫回歸測試(Regression test)。對于規模較大的軟件,回歸測試需要很長的時間,在版本新增功能和錯誤修正不多的情況下,回歸測試可以占到整個軟件開發過程了一半以上,嚴重影響了軟件的交付,也使軟件測試部門成為軟件開發流程中的瓶頸。測試過程自動化,是部分解決這個問題的辦法。

    作為架構師,有必要考慮如何實現軟件的可自動化測試性。

    6.3.1. 界面自動化測試

    在沒有圖形化界面以前,字符方式的界面是比較容易進行自動化測試的。一個編寫良好的腳本就可以實現輸入和對輸出的檢查。但是對于圖形化的界面,人的參與似乎變得不可缺少。有一些界面自動化的測試工具,如WinRunner, 這些工具可以記錄下測試人員的操作成為腳本,然后通過回放這些腳本,就可以實現操作的自動化。針對嵌入式設備,有Test Quest可以使用,通過在設備中運行一個類似遠程桌面的Agent,PC端的測試工具可以用圖像識別的方法識別出不同的組件,并發送相應用戶的輸入。此類工具的基本工作原理如圖:

    但是這個過程在實際中存在三個問題:

  • 可靠性差,經常中斷運行。要寫一個可靠的腳本甚至比開發軟件還要困難。比如,按下一個按鈕,有時候一個對話框立刻就出現,有時候可能要好幾秒,有時候甚至不出現,操作錄制工具不能自動實現這些判斷,而需要手動修改。

  • 對操作結果的判斷很困難,尤其是非標準的控件。

  • 當界面修改后,原有代碼很容易失效

  • 要應用基于圖形界面的自動化測試工具,架構師在架構的時候應該考慮:

  • 界面風格如何保持一致。應當由架構,而非程序員決定架構的風格。包括布局,控件大小,相對位置,文字,對操作的響應方式,超時時長,等等。

  • 如何在最合適測試工具的界面和用戶喜歡的界面之中折中。比如,Test Quest是基于圖像識別的,那么黑白兩色的界面是最有利的,而用戶喜歡的漸進色就非常不利。也許讓界面具備自動的切換能力最好。

  • 對于已經完成的產品,如果架構沒有為自動化測試做過考慮,所能應用的范圍就非常有限,不過還是有一些思路可以供參考:

  • 實現小規模的自動化腳本。針對一個具體的操作流程進行測試,而不是試圖用一個腳本測試整個軟件。一系列的小測試腳本組成了一個集合,覆蓋系統的一部分功能。這些測試腳本可以都以軟件啟動時的狀態作為基準,所以在狀態處理上會比較簡單

  • ”猴子測試”有一定的價值。所謂猴子測試,就是隨機操作鼠標和鍵盤。這種測試完全不理解軟件的功能,可以發現一些正常測試無法發現的錯誤。據微軟內部的資料,微軟的一些產品15%的錯誤是由“猴子測試”發現的。

  • 總的來講,基于界面的自動化測試是不成熟的。對架構師而言一定要避免功能只能通過界面才能訪問。要讓界面僅僅是界面,而軟件大部分的功能是獨立于界面并可以通過其他方式訪問的。上面框架的例子中的設計就體現了這一點。

    思考:如何讓界面具有自我測試功能?

    6.3.2. 基于消息的自動化測試

    如果軟件對外提供基于消息的接口,自動化測試就會變得簡單的多。上面已經提到了固件的TL1接口。對于界面部分,則應該在設計的時候,將純粹的“界面”獨立出來,讓它盡可能的薄,而其他部分依然可以基于消息提供服務。

    在消息的基礎上,用腳本語言包裝成函數的形式,可以很容易的調用,并覆蓋消息的各種參數組合,從而提高測試的覆蓋率。關于如何將消息包裝為腳本,可以參考SOAP的實現。如果使用的不是XML,也可以自己實現類似的自動代碼生成。

    這些測試腳本應該由開發人員撰寫,每當實現了一個新的接口(也就是一條新的消息),就應該撰寫相應的測試腳本,并作為項目的一部分保存在代碼庫中。當需要執行回歸測試的時候,只要運行一遍測試腳本即可,大大提高了回歸測試的效率。

    所以,為了實現軟件的自動化測試,提供基于消息的接口是一個很好的辦法,這讓我們可以在軟件之外獨立的編寫測試腳本。在設計的時候可以考慮這個因素,適當的增加軟件消息的支持。當然,TL1只是一個例子,根據項目的需要,可以選擇任何適合的協議,如SOAP。

    6.3.3. 自動化測試框架

    在編寫自動化測試腳本的時候,有很多的工作是重復的,比如建立socket連接,日志,錯誤處理,報表生成等。同時,對于測試人員來說,這些工作可能是比較困難的。因此,設計一個框架,實現并隱藏這些重復和復雜的技術,讓測試腳本的編寫者將注意力集中在具體的測試邏輯上。

    這樣一個框架應該實現以下功能:

  • 完成連接的初始化等基礎工作。

  • 捕獲所有的錯誤,保證Test Case中的錯誤不會打斷后續的Test Case執行。

  • 自動檢測和執行Test Case。新增的Test Case是獨立的腳本文件,無須修改框架的代碼或者配置。

  • 消息編解碼,并以函數的方式提供給Test Case編寫者調用。

  • 方便的工具,如報表,日志等。

  • 自動統計Test Case的運行結果并生成報告。

  • 自動化測試框架的思路和一般的軟件框架是一致的,就是避免重復勞動,降低開發難度。

    下圖是一個自動化測試框架的結構圖:

    每個Test Case都必須定義一個規定的Run函數,框架將依次調用,并提供相應的庫函數供Test Case用來發送命令和獲得結果。這樣,測試用例的編寫者就只需要將注意力集中在測試本身。舉例:

    def run():open_laser()assert(get_laser_state() == ON)insert_error(BIT_ERROR)assert(get_error_bit() == BIT_ERROR)

    測試用例的編寫者擁有的知識是“必須先打開激光器然后才能向線路上插入錯誤”。而架構師能提供的是消息收發,編解碼,錯誤處理,報表生成等,并將這些為測試用例編寫者隔離。

    問題: open_laser, get_laser_state這些函數是誰寫的?

    問題:如何進一步實現知識的解耦?能否有更方便的語言來編寫TestCase?

    6.3.4. 回歸測試

    有了自動化的測試腳本和框架,回歸測試就變得很簡單了。每當有新版本發布時,只需運行一遍現有的Test Case,分析測試報告,如果有測試失敗的Case則回歸測試失敗,需要重新修改,直到所有的Case完全通過。完整的回歸測試是軟件質量的重要保證。

    6.4. 集成測試

    集成測試要驗證的是系統各個組成模塊的接口是否工作正常。這是比系統測試更低層的測試,通常由開發人員和測試人員共同完成。

    例如在一個典型的嵌入式系統中,FPGA,固件和界面是常見的三個模塊。模塊本身還可以劃分為更小的模塊,從而降低復雜度。嵌入式軟件模塊測試的常見問題是硬件沒有固件則無法工作,固件沒有界面就無法驅動;反過來,界面沒有固件不能完整運行,固件沒有硬件甚至無法運行。于是沒有經過測試的模塊直到集成的時候才能完整運行,發現問題后需要考慮所有模塊的問題,定位和解決的代價都很大。假設有模塊A和B,各有十個bug。如果都沒有經過模塊測試直接集成,可以認為排錯的工作量相當于10*10等于100。

    所以,在設計一個模塊的時候,首先要考慮,這個模塊如何單獨測試?比如,如果界面和固件之間是通過SOCKET通信的,那么就可以開發一個模擬固件,在同樣的端口上提供服務。這個模擬固件不執行實際的操作,但是會響應界面的請求并返回模擬的結果。并且返回的結果可以覆蓋到各種典型的情況,包括錯誤的情況。使用這樣的技術,界面部分幾乎可以得到100%的驗證,在集成階段遇到錯誤的大大減少。

    對固件而言,因為處于系統的中間,所以問題復雜一些。一方面,要讓固件可以通過GUI以外的途徑被調用;另一方面則要模擬硬件的功能。對于第一點,在設計的時候,要讓接口和實現分離。接口可以隨意的更換,比如和GUI的接口也許是JSON,同時還可以提供telnet的TL1接口,但是實現是完全一樣的。這樣,在和GUI集成之前,就可以通過TL1進行完全的測試固件。對于第二點,則應該在設計的時候提取出硬件抽象層,讓固件的主要實現和寄存器,內存地址等因素隔離開來。在沒有硬件或者硬件設計未定的時候實現一個硬件模擬層,來保證固件可以完整運行并測試。

    6.5. 單元測試

    單元測試是軟件測試的最基本單位,是由開發人員執行以保證其所開發代碼正確的過程。開發人員應該提交經過測試的代碼。未經單元測試的代碼在進入軟件后,不僅發現問題后很難定位,而且通過系統測試是很難做到對代碼分支的完全覆蓋的。TDD就是基于這個層次的開發模式。

    單元測試的粒度一般是函數或者類,例如下面這個常用函數:

    int atoi(const char *nptr);

    這是一個功能非常單一的函數,所以單元測試對它非常有效。可以通過單元測試驗證下列情況:

  • 一般正常調用,如”9”,”1000”,”-1”等

  • 空的nptr指針

  • 非數字字符串,”abc”,”@#!123”,”123abc”

  • 帶小數點的字符串, “1.1”,”0.111”,”.123”

  • 超長字符串

  • 超大數字,”999999999999999999999999999”

  • 超過一個的-號和位置錯誤的-號,”—1”,”-1-“,”-1-2”

  • 如果atoi通過了以上測試,我們就可以放心的將它集成到軟件中去了。由它再引發問題的概率就很小了(不是完全沒有,因為我們不能遍歷所有可能,只是挑選有代表性的異常情況進行測試)。

    以上的例子可以說是單元測試的典范,但實際中卻常常不是這么回事。我們常常發現寫好的函數很難做單元測試,不僅工作量很大,效果也不見得好。其根本的原因是,函數沒有遵循好一些原則:

  • 單一功能

  • 低耦合

  • 反觀atoi的例子,功能單一明確,和其他函數幾乎沒有任何耦合(我上面并沒有寫atoi的代碼實現,大家可以自己實現,希望是0耦合)。

    下面我舉一個實際中的例子。

    這是一個簡單的TL1命令發送和解析軟件,功能需求描述如下:

    ü 通過telnet與TL1服務器通訊

    ü 發送TL1命令給TL1服務器

    ü 解析TL1服務器的響應

    TL1是通訊行業廣泛使用的一種協議,為了給不熟悉TL1的朋友簡化問題,我定義了一個簡化的格式:

    CMD:CTAG:PAYLOAD;CMD - 命令的名字,可以是任意字母開頭,由字母和下劃線組成的字符串CTAG - 一個數字,用于標志命令的序號PAYLOAD - 可以是任意格式的內容; - 結束符相應的,TL1服務器的回應也有格式:DATECTAG COMPLDPAYLOAD;DATE – 日期和時間CTAG – 一個數字,和TL1 命令所攜帶的CTAG一樣COMPLD – 表明命令執行成功PAYLOAD - 返回的結果,可以是任何格式的內容; - 結束符

    舉例:

    命令:GET-IP-CONFIG:1:;

    結果:

    2008-7-19 11:00:00 1 COMPLD ip address: 192.168.1.200 gate way: 192.168.1.1 dns: 192.168.1.3 ;

    命令:SET-IP-CONFIG:2:172.31.2.100,172.31.2.1,172.31.2.3;

    結果:

    2008-7-19 11:00:05 2 COMPLD ;

    軟件的最上層可能是這樣的:

    Dict* ipconf = GET_IP_CONFIG(); ipconf->set(“ipaddr”,”172.31.2.100) ipconf->set(“gateway”,”172.3.2.1”) ipconf->set(“dns”,”172.31.2.1”) SET_IP_CONFIG(ipconf);

    以GET_IP_CONFIG為例,這個函數應該完成的功能包括:

    ü 建立telnet連接,如果連接尚未建立

    ü 構造TL1命令字符串

    ü 發送

    ü 接收反饋

    ü 解析反饋,并給IP_CONF結構復制

    ü 返回

    我們當然不希望每個這樣的函數都重復實現這些功能,所以我們定義了幾個模塊:

  • Telnet 連接管理

  • TL1命令構造

  • TL1 結果解析

  • 這里我們來分析TL1結果解析,假設設計為一個函數,函數的原型如下:

    Dict* TL1Parse(const char* tl1response)

    這個函數的功能是接受一個字符串,如果它是一個合法且已知的TL1回應,則將其中的結果提取出來,放入一個字典對象中。

    這本來會是一個很便于進行單元測試的例子:輸入各種字符串,檢查返回結果是否正確即可。但是在這個軟件中,有一個很特殊的問題:

    TL1Parse在解析一個字符串時,它必須要知道當前要處理的是哪條命令的回應。但是請注意,在TL1的回應中,是不包括命令的名字的。唯一的辦法是使用CTAG,這個命令和回應一一對應的數字。Tl1Parse首先提取出CTAG來,然后查找使用這個CTAG的是什么命令。這里產生了一個對外調用,也就是耦合。

    有一個對象維護了一個CTAG和命令名字對應關系的表,通過CTAG,可以查詢到對應的命令名,從而知道如何解析這個TL1 response.

    如此一來,TL1Parse就無法進行單元測試了,至少不能輕易的進行。通常的樁函數的辦法都不好用了。

    怎么辦?

    重新設計,消除耦合。

    將TL1Parse拆分為兩個函數:

    Tl1_header TL1_get_header(const char* tl1response) Dict* TL1_parse_payload(const char* tl1name ,const char* tl1payload)

    這兩個函數都可以單獨進行完整的單元測試。而這兩個函數的代碼基本就是TL1Parse切分了一下,但是其可測試性得到了很大的提高,得到一個可靠的解析器的可能性自然也大大提升了。

    這個例子演示了如何通過設計來提高代碼的可測試性—這里是單元測試。一個隨意設計,隨意實現的軟件要進行單元測試將會是一場噩夢,只有在設計的時候就考慮到單元測試的需要,才能真正的進行單元測試。

    6.5.1. 圈復雜度測量

    模塊的復雜度直接影響了單元測試的覆蓋率。最著名的度量代碼復雜度的方法是圈復雜度測量。

    計算公式:V(F)=e-n+2。其中e是流程圖中的邊的數量,n是節點數量。簡單的算法是統計如 if、while、do和switch 中的 case 語句數加1。適合于單元測試的代碼的復雜度一般認為不應該超過10。

    6.5.2. 扇入扇出測量

    扇入是指一個模塊被其他模塊所引用。扇出是指一個模塊引用其他模塊。我們都知道好的設計應該是高內聚低耦合的,也就是高扇入低扇出。一個扇出超過7的模塊一般認為是設計欠佳的。扇出過大的模塊進行單元測試不論從樁設置還是覆蓋率上都是困難的。將系統的傳出耦合和傳入耦合的數量結合起來,形成另一個度量:不穩定性。

    不穩定性 = 扇出 / (扇入 + 扇出)

    這個值的范圍從0到1。值越接近1,它就越不穩定。在設計和實現架構時,應當盡量依賴穩定的包,因為這些包不太可能更改。相反的,依賴一個不穩定的包,發生更改時間接受到傷害的可能性就更大。

    6.5.3. 框架對單元測試的意義

    框架的應用在很大程度上可以幫助進行單元測試。因為二次開發者被限定實現特定的接口,而這些接口勢必都是功能明確,簡單,低耦合的。之前的框架示例代碼也演示了這一點。這再次說明了,由高水平的工程師設計出的框架,可以強制初級工程師產生高質量的代碼。

    7. 維護架構的一致性

    在實際的開發中,代碼偏離精心設計的架構是很常見的事情,比如下圖示例了一個嵌入式設備中設計的MVC模式:

    View依賴于Controller和Model, Controller依賴于Model,Model作為底層服務提供者,不依賴View或者Controller. 這是一個適用的架構,可以在相當程度上分離業務,數據和界面。但是,某個程序員在實現時,使用了一個從Model到View的調用,破壞了架構。

    這種現象通常發生在產品的維護階段,有時也發生在架構的實現階段。為了增加一個功能或者修正一個錯誤,程序員由于不理解原有架構的思路,或者只是單純的偷懶,走了“捷徑”。如果這樣的實現不能及時發現并糾正,設計良好的架構就會被漸漸破壞,也就是我們常說的“架構”腐爛了。通常一個有一定年齡的軟件產品的架構都有這個問題。如何監視并防止這種問題,有技術上的和管理上的手段。

    技術上,借助工具,可以對系統組件的依賴進行分析,架構的外在表現最重要的就是各個部分的耦合關系。有一些工具可以統計軟件組件的扇入和扇出。可以用這種工具編寫測試代碼,對組件的扇出進行檢測,一旦發現測試失敗,就說明架構遭到了破壞。這種檢查可以集成在一些IDE中, 在編譯時同步進行,或者在check in的時候進行。更高級的工具可以對代碼進行反向工程生成UML,可以提供更進一步的信息。但通常對扇入扇出做檢查就可以了。

    通過設置代碼檢視的開發流程,對程序員check in的代碼進行評審,也可以防止此類問題。代碼檢視是開發中非常重要的一環,它屬于開發后期階段用來防止壞的代碼進入系統的重要手段。代碼檢視通常要關注以下問題:

  • 是否正確完整的完成了需求

  • 是否遵循了系統的架構

  • 代碼的可測試性

  • 錯誤處理是否完備

  • 代碼規范

  • 代碼檢視通常以會議的形式進行,時間點設置在項目階段性完成,需要check in代碼時。對于迭代式開發,則可以在一個迭代周期結束前組織。參與人員包括架構師,項目經理,項目成員,其他項目的資深工程師等。一般時間不要太長,以不超過2個小時為宜。會議前2天左右發出會議通知和相關文檔代碼,與會者必須先了解會議內容,進行準備。會議中,由代碼的作者首先講解代碼需要實現的功能,自己的實現思路。然后展示代碼。與會者根據自己的經驗提出各種問題和改進意見。這種會議最忌諱的是讓作者感到被指責或者輕視,所以,會議組織者要首先定義會議的基調:會議成功與否的標準不是作者的代碼質量如何,而是與會者是否提供了有益的建議。會后由作者給與會者打分,而不是反之。

    8. 一個實際嵌入式系統架構的演化

    上世紀九十年代,互聯網的極速發展讓通訊測試設備也得到了極大的發展。那個年代,能夠實現某種測量的硬件是競爭的核心,軟件的目的僅僅是驅動硬件運行起來,再提供一個簡單的界面。所以,最初的產品的軟件結構非常簡單,類似前面的城鐵門禁系統。

    優點:程序簡單明了的實現了用戶的需求,一個程序員就可以全部搞定。

    缺點:完全沒有劃分模塊,底層上層耦合嚴重。

    8.1. 數據處理

    用戶要求能將測量結果保存下來,并可以重新打開。數據存儲模塊和界面被獨立出來。

    依然保持上面的主邏輯,但是界面部分不僅可以顯示實時的數據,也可以從ResultManager中讀取數據來顯示。

    優點:數據和界面分離的雛形初步顯現

    缺點:ResultManager只是作為一個工具存在,負責保存和裝載歷史數據。界面和數據的來源依然耦合的很緊。不同的界面需要的不同數據都是通過硬編碼判斷的。

    8.2. 窗口管理

    隨著功能不斷復雜,界面窗口越來越多,原來靠一個類來繪制各種界面的方式已經不能承受。于是窗口的概念被引入。每個界面都被視為一個窗口,窗口中的元素為控件。窗口的打開,關閉,隱藏則由窗口管理器負責。

    優點:界面功能以窗口的單位分離,不再是一個超大的集合。

    缺點:雖然有了窗口管理器,但是界面依然是直接和底層耦合的,依然是大循環結構。

    8.3. MVC模式

    隨著規模進一步擴大,最初的大循環結構終于無法滿足日益復雜的需求了。標準的MVC模式被引入,經歷了一次大的重構。

    數據中心作為Model被獨立出來,保存著當前最新的數據。View被放在了獨立的任務中執行,定期從DataCenter輪詢數據。用戶的操作通過View發送給Controller,進一步調用硬件驅動執行。硬件執行的結果從驅動到Controller更新到DataCenter中。界面,數據,命令三者基本解耦。ResultManager成為DataCenter的一個組件,View不再直接與其通訊。

    MVC模式的引入,第一次讓這個產品了有真正意義上職責明晰,功能獨立的架構。

    8.4. 大量類似模塊,低效的復用

    到上一步,作為一個單獨的嵌入式設備,其架構基本可以滿足需求。但是隨著市場的擴展,越來越多的設備被設計出來。這些設備雖然執行的具體測量任務不同,但是他們都有著同樣的操作方式,類似的界面,更主要的是,它們面臨的問題領域是相同的。長期以來,復制和粘貼是唯一的復用方式,甚至類名變量名都來不及改。一個錯誤在一個設備上被修正,同樣一段代碼的錯誤在其他設備上卻來不及修改。而隨著團隊規模的擴大,甚至MVC的基本架構在一些新設備上都沒能遵守。

    最終框架被引入了這個系列的產品。框架確定了如下內容:

  • MVC模式的基本架構

  • 窗口管理器和組件布局算法

  • 多國語言方案(字符串管理器)

  • 日志系統

  • 內存分配器和內存泄露檢測

  • 8.5. 遠程控制

    客戶希望將設備固定安放在網絡的某個位置,作為“探針”使用,在辦公室通過遠程控制來訪問這個設備。這對于原本是作為純手持設備設計的系統又是一個挑戰。幸運的是,MVC架構具有相當的彈性,早期的投入獲得了回報。

    TL1 Server 對外提供基于Telnet的遠程控制接口。在系統內部,它的位置相當于View,只和原有的Controller和DataCenter通訊。

    8.6. 自動化的TL1解釋器

    由于TL1命令相當多,而TL1又往往不是客戶的第一需求,很多設備的TL1命令開始不完整。究其原因,還是手寫TL1命令的解釋器太累。后來通過引入Bison和Flex,這個問題有所改善,但還是不足。自動化代碼生成在這個階段被引入。通過以如下的格式定義TL1,工具可以自動生成TL1的編碼和解碼器代碼。

    CMD_NAME {cmd = “SET-TIME-CONFIG::<ctag>::<year>,<month>,<day>,<hour>,<minute>,[<second>]”year = 1970..2100month = 1..12day = 1..31hour = 0..23minute = 0..59second = 0..59 }

    8.7. 測試的難題

    經過數十年的積累,產品已經成為一個系列,幾十種設備。大部分設備進入了維護期,經常有客戶提一些小的改進,或者要求修正一下缺陷。繁重的手工回歸測試成為了噩夢。

    基于TL1的自動化測試極大的解放了測試人員。通過在PC上運行的測試腳本,回歸測試變得簡單而可靠。唯一不足的是界面部分無法驗證。

    基于Test Quest的自動化工具需要在設備運行的pSOS系統上開發一個類似遠程桌面的軟件,而這在pSOS上并非易事。不過好消息是,由于框架固定了界面的風格和布局算法,基于Test Quest的自動化工具會有很高的識別效率。

    8.8. 小結

    從這個實際的嵌入式產品重構的歷程可以看出,第三步引入MVC模式和第四步的框架化是非常關鍵的。成熟的MVC模式保證了后續一系列的可擴充性,而框架則保證了這個架構的在所有產品中的準確重用。

    9. 總結

    本文是針對嵌入式軟件開發的特點,討論架構設計的思路和方法。試圖給大家提供一種思想,啟發大家的思維。框架,自動化代碼生成和測試驅動的架構是核心內容,其中框架又是貫穿始終的要素。有人問我,什么是架構師,怎么樣才能成為架構師?我回答說:編碼,編碼,再編碼;改錯,改錯,再改錯。當你覺得厭煩的時候,停下來想想,怎么才能更快更好的完成這些工作?架構師就是在實踐中產生的,架構師來自于那些勤于思考,懶于重復的人。

    -END-

    往期好文合集

    號稱最好的國產操作系統在 Windows 10 面前能否一戰?

    入行嵌入式研發10多年,一位工程師悟出這些道理

    嵌入式大佬 | 嵌入式C語言知識點萬字總結

    ??最 后??

    ?

    若覺得文章不錯,轉發分享,也是我們繼續更新的動力。

    5T資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,PCB、FPGA、DSP、labview、單片機、等等

    在公眾號內回復「更多資源」,即可免費獲取,期待你的關注~

    長按識別圖中二維碼關注

    總結

    以上是生活随笔為你收集整理的干货 | 嵌入式系统软件架构设计的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    欧美黑人巨大xxxxx | 亚洲区欧美区综合区自拍区 | 精品亚洲韩国一区二区三区 | 国产精品久久国产精品99 | 偷窥日本少妇撒尿chinese | 波多野结衣av一区二区全免费观看 | 狠狠色噜噜狠狠狠狠7777米奇 | 久久久久成人精品免费播放动漫 | 国产欧美亚洲精品a | 在线成人www免费观看视频 | 一本色道婷婷久久欧美 | 久久97精品久久久久久久不卡 | 国产明星裸体无码xxxx视频 | 久久久婷婷五月亚洲97号色 | 中国女人内谢69xxxx | av无码电影一区二区三区 | 小sao货水好多真紧h无码视频 | 青草视频在线播放 | 无码精品人妻一区二区三区av | 国语自产偷拍精品视频偷 | 欧美精品国产综合久久 | 免费观看黄网站 | 美女张开腿让人桶 | 日韩亚洲欧美中文高清在线 | 正在播放老肥熟妇露脸 | 露脸叫床粗话东北少妇 | 国产精品国产三级国产专播 | 亚洲一区二区三区国产精华液 | 特黄特色大片免费播放器图片 | 久久午夜无码鲁丝片 | 在线观看国产午夜福利片 | 国产真实乱对白精彩久久 | 欧美人与牲动交xxxx | 国产成人精品久久亚洲高清不卡 | 国产区女主播在线观看 | 亚洲一区二区三区四区 | 全球成人中文在线 | 丝袜美腿亚洲一区二区 | 久久久久国色av免费观看性色 | 少妇一晚三次一区二区三区 | 理论片87福利理论电影 | 午夜熟女插插xx免费视频 | 免费观看又污又黄的网站 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 亚洲欧美国产精品专区久久 | 国产国语老龄妇女a片 | 东京热无码av男人的天堂 | 在线亚洲高清揄拍自拍一品区 | 欧美性猛交内射兽交老熟妇 | 3d动漫精品啪啪一区二区中 | 性啪啪chinese东北女人 | 人妻无码久久精品人妻 | 成熟妇人a片免费看网站 | 亚洲gv猛男gv无码男同 | 久久亚洲日韩精品一区二区三区 | 久久亚洲中文字幕精品一区 | 少妇性俱乐部纵欲狂欢电影 | 国产综合久久久久鬼色 | 给我免费的视频在线观看 | √天堂资源地址中文在线 | aⅴ亚洲 日韩 色 图网站 播放 | 激情五月综合色婷婷一区二区 | 无码人中文字幕 | 国产精品丝袜黑色高跟鞋 | 综合网日日天干夜夜久久 | 亚洲色欲久久久综合网东京热 | 国产又粗又硬又大爽黄老大爷视 | 国产精品99爱免费视频 | 国产欧美亚洲精品a | 国产精品理论片在线观看 | 日本护士xxxxhd少妇 | 鲁鲁鲁爽爽爽在线视频观看 | 成人欧美一区二区三区黑人 | 久久精品国产亚洲精品 | 高清国产亚洲精品自在久久 | 亚洲欧美色中文字幕在线 | 国产乱子伦视频在线播放 | av人摸人人人澡人人超碰下载 | 一个人看的www免费视频在线观看 | 久久午夜夜伦鲁鲁片无码免费 | 欧美日韩综合一区二区三区 | 欧美激情内射喷水高潮 | 久久婷婷五月综合色国产香蕉 | 美女黄网站人色视频免费国产 | 亚洲午夜福利在线观看 | 131美女爱做视频 | 久久综合香蕉国产蜜臀av | 日本www一道久久久免费榴莲 | 久久久久人妻一区精品色欧美 | 激情人妻另类人妻伦 | 成人免费视频在线观看 | 女人被爽到呻吟gif动态图视看 | 国内精品一区二区三区不卡 | 精品人妻av区 | 国产亚洲欧美日韩亚洲中文色 | 成人aaa片一区国产精品 | 久久久久免费精品国产 | 亚洲精品久久久久久一区二区 | 国产精品亚洲一区二区三区喷水 | 在线观看欧美一区二区三区 | 成年女人永久免费看片 | 九九久久精品国产免费看小说 | 国产精品久久久久7777 | 日本欧美一区二区三区乱码 | 国产偷自视频区视频 | 久久国产自偷自偷免费一区调 | 久久综合九色综合97网 | 四虎国产精品一区二区 | 久久久www成人免费毛片 | 精品 日韩 国产 欧美 视频 | 欧美 日韩 人妻 高清 中文 | 色欲综合久久中文字幕网 | 熟女体下毛毛黑森林 | 色情久久久av熟女人妻网站 | 亚洲 激情 小说 另类 欧美 | 精品无码国产自产拍在线观看蜜 | 丝袜人妻一区二区三区 | 国产va免费精品观看 | 少妇性l交大片欧洲热妇乱xxx | 国内精品久久毛片一区二区 | 波多野42部无码喷潮在线 | 网友自拍区视频精品 | 无码帝国www无码专区色综合 | 一本色道久久综合亚洲精品不卡 | 日韩av无码中文无码电影 | 四虎永久在线精品免费网址 | 亚洲国产av精品一区二区蜜芽 | 未满成年国产在线观看 | 丰满妇女强制高潮18xxxx | 无码国产色欲xxxxx视频 | 狠狠综合久久久久综合网 | 乱人伦中文视频在线观看 | 人人澡人人透人人爽 | 99久久精品无码一区二区毛片 | 国产精品久久久 | 亚洲最大成人网站 | 成在人线av无码免观看麻豆 | 亚洲乱码日产精品bd | 97se亚洲精品一区 | 丰满少妇熟乱xxxxx视频 | 色噜噜亚洲男人的天堂 | av无码电影一区二区三区 | 日韩在线不卡免费视频一区 | 美女毛片一区二区三区四区 | 青草青草久热国产精品 | 国产人妻久久精品二区三区老狼 | 97夜夜澡人人双人人人喊 | 乱中年女人伦av三区 | 未满成年国产在线观看 | 日本护士xxxxhd少妇 | 无码毛片视频一区二区本码 | 天天拍夜夜添久久精品大 | 亚洲人成无码网www | 午夜时刻免费入口 | 欧美性猛交内射兽交老熟妇 | 成年美女黄网站色大免费视频 | 色婷婷综合激情综在线播放 | 中文字幕乱码中文乱码51精品 | 西西人体www44rt大胆高清 | 在线看片无码永久免费视频 | 日本精品人妻无码77777 天堂一区人妻无码 | 1000部啪啪未满十八勿入下载 | www一区二区www免费 | 丰满人妻一区二区三区免费视频 | 台湾无码一区二区 | 欧美人与禽zoz0性伦交 | 日韩av无码一区二区三区不卡 | 少妇厨房愉情理9仑片视频 | 国产在线aaa片一区二区99 | 少女韩国电视剧在线观看完整 | 日日碰狠狠丁香久燥 | 麻豆国产丝袜白领秘书在线观看 | www国产亚洲精品久久网站 | 国产国语老龄妇女a片 | 97精品人妻一区二区三区香蕉 | 色综合天天综合狠狠爱 | 熟女俱乐部五十路六十路av | 亚洲日本va中文字幕 | 女人色极品影院 | 亚洲日韩中文字幕在线播放 | 老熟女重囗味hdxx69 | 亚洲色大成网站www | 日日摸日日碰夜夜爽av | 51国偷自产一区二区三区 | 日韩精品成人一区二区三区 | 欧美阿v高清资源不卡在线播放 | 少妇人妻大乳在线视频 | 亚洲中文字幕av在天堂 | 麻豆果冻传媒2021精品传媒一区下载 | 国产熟妇另类久久久久 | 国产免费无码一区二区视频 | 亚洲中文字幕av在天堂 | 又大又硬又爽免费视频 | 国产网红无码精品视频 | 麻豆国产人妻欲求不满 | 中文字幕亚洲情99在线 | 亚洲熟妇色xxxxx亚洲 | 男女作爱免费网站 | 小sao货水好多真紧h无码视频 | 国模大胆一区二区三区 | 国产精品免费大片 | 国产精品亚洲а∨无码播放麻豆 | 美女扒开屁股让男人桶 | 久久综合九色综合欧美狠狠 | 久久久久久九九精品久 | 国产亚洲精品久久久久久久久动漫 | 日韩欧美群交p片內射中文 | 国色天香社区在线视频 | 免费播放一区二区三区 | 一区二区三区乱码在线 | 欧洲 | 少妇厨房愉情理9仑片视频 | 人人爽人人澡人人人妻 | 67194成是人免费无码 | 亚洲精品一区二区三区在线观看 | 7777奇米四色成人眼影 | 国产成人一区二区三区在线观看 | 国产绳艺sm调教室论坛 | 国产亚洲人成在线播放 | 国产精品久久久久影院嫩草 | 正在播放老肥熟妇露脸 | 又湿又紧又大又爽a视频国产 | 日本一区二区三区免费高清 | 亚洲综合另类小说色区 | 搡女人真爽免费视频大全 | 美女扒开屁股让男人桶 | 亚洲日韩乱码中文无码蜜桃臀网站 | 国产精品多人p群无码 | 国产av无码专区亚洲a∨毛片 | 免费网站看v片在线18禁无码 | 在线 国产 欧美 亚洲 天堂 | 欧美日韩色另类综合 | 免费乱码人妻系列无码专区 | 好男人www社区 | 国产日产欧产精品精品app | 欧美三级不卡在线观看 | 日本va欧美va欧美va精品 | 亚洲中文字幕va福利 | 免费无码av一区二区 | 国产熟妇另类久久久久 | 欧美日韩一区二区三区自拍 | 午夜福利一区二区三区在线观看 | 亚洲熟悉妇女xxx妇女av | 狠狠噜狠狠狠狠丁香五月 | 国产手机在线αⅴ片无码观看 | av无码不卡在线观看免费 | 国色天香社区在线视频 | 亚洲色欲色欲欲www在线 | 国语自产偷拍精品视频偷 | 强开小婷嫩苞又嫩又紧视频 | 国产婷婷色一区二区三区在线 | 中文字幕人妻无码一区二区三区 | 男人和女人高潮免费网站 | 曰韩少妇内射免费播放 | 亚洲性无码av中文字幕 | 国产精品亚洲综合色区韩国 | 亚洲成av人片天堂网无码】 | 无码国内精品人妻少妇 | 色诱久久久久综合网ywww | 日韩人妻无码中文字幕视频 | 好男人www社区 | 久久精品视频在线看15 | 无码国内精品人妻少妇 | 久久婷婷五月综合色国产香蕉 | 免费男性肉肉影院 | 欧美成人免费全部网站 | 美女扒开屁股让男人桶 | 无码国产色欲xxxxx视频 | 中文字幕无码热在线视频 | 国产乱人无码伦av在线a | 少妇性l交大片欧洲热妇乱xxx | 欧美黑人巨大xxxxx | 无码国产激情在线观看 | 久久伊人色av天堂九九小黄鸭 | 亚洲七七久久桃花影院 | 宝宝好涨水快流出来免费视频 | 色欲av亚洲一区无码少妇 | 国产成人无码区免费内射一片色欲 | 亚洲а∨天堂久久精品2021 | 秋霞成人午夜鲁丝一区二区三区 | 人妻中文无码久热丝袜 | 久久久中文久久久无码 | 97久久超碰中文字幕 | 久久久久久久久888 | 久久99精品国产麻豆蜜芽 | 日韩精品无码一区二区中文字幕 | 久久精品女人天堂av免费观看 | 一二三四在线观看免费视频 | 精品国产aⅴ无码一区二区 | 日产精品高潮呻吟av久久 | 97夜夜澡人人爽人人喊中国片 | 久久成人a毛片免费观看网站 | 亚洲成色在线综合网站 | 国产莉萝无码av在线播放 | 精品亚洲韩国一区二区三区 | 天天做天天爱天天爽综合网 | 捆绑白丝粉色jk震动捧喷白浆 | 草草网站影院白丝内射 | 国产xxx69麻豆国语对白 | 丰满护士巨好爽好大乳 | 欧美日本日韩 | 99久久精品无码一区二区毛片 | 性生交大片免费看女人按摩摩 | 亚洲性无码av中文字幕 | 人妻少妇精品无码专区动漫 | 久久国产精品偷任你爽任你 | а天堂中文在线官网 | 欧美日韩久久久精品a片 | 国内揄拍国内精品人妻 | 亚洲精品一区三区三区在线观看 | www国产精品内射老师 | 欧洲欧美人成视频在线 | 国产精品永久免费视频 | 一本加勒比波多野结衣 | 成 人影片 免费观看 | 亚洲成av人片在线观看无码不卡 | 一本久道久久综合婷婷五月 | 亚洲精品欧美二区三区中文字幕 | 人人妻人人澡人人爽欧美一区九九 | 久久久久久a亚洲欧洲av冫 | 午夜丰满少妇性开放视频 | 欧美熟妇另类久久久久久不卡 | 在线看片无码永久免费视频 | www国产精品内射老师 | 嫩b人妻精品一区二区三区 | 国产一区二区三区四区五区加勒比 | 欧美日韩人成综合在线播放 | 免费无码午夜福利片69 | 久久人人爽人人爽人人片ⅴ | 18无码粉嫩小泬无套在线观看 | 亚洲狠狠色丁香婷婷综合 | 无码人妻精品一区二区三区下载 | 欧美亚洲国产一区二区三区 | 日本一区二区三区免费高清 | 一本大道伊人av久久综合 | 狠狠噜狠狠狠狠丁香五月 | 狠狠色噜噜狠狠狠7777奇米 | 国产激情无码一区二区app | 中文字幕无码热在线视频 | 99国产欧美久久久精品 | 精品国产一区二区三区av 性色 | 久久久成人毛片无码 | 色一情一乱一伦一视频免费看 | 国产办公室秘书无码精品99 | 5858s亚洲色大成网站www | 老头边吃奶边弄进去呻吟 | 精品一二三区久久aaa片 | 18无码粉嫩小泬无套在线观看 | 亚洲成av人片天堂网无码】 | 丰满少妇熟乱xxxxx视频 | 波多野结衣高清一区二区三区 | 日韩精品a片一区二区三区妖精 | 丁香啪啪综合成人亚洲 | 国产色xx群视频射精 | 清纯唯美经典一区二区 | 亚洲人成网站在线播放942 | 一本大道伊人av久久综合 | 欧美日韩视频无码一区二区三 | 日韩av无码一区二区三区不卡 | 国产精品久久国产三级国 | 伊人色综合久久天天小片 | 精品国产一区二区三区四区 | 亚洲国产精品一区二区美利坚 | 亚洲乱码中文字幕在线 | 老熟女重囗味hdxx69 | 成人片黄网站色大片免费观看 | 中文字幕无码av激情不卡 | 蜜桃av抽搐高潮一区二区 | 夜先锋av资源网站 | 日本高清一区免费中文视频 | 亚洲成av人影院在线观看 | 欧美阿v高清资源不卡在线播放 | 欧美日韩精品 | 国内少妇偷人精品视频 | aⅴ亚洲 日韩 色 图网站 播放 | 久久无码中文字幕免费影院蜜桃 | 国产精品理论片在线观看 | 久久亚洲中文字幕精品一区 | 欧美第一黄网免费网站 | 精品国产一区二区三区四区在线看 | 色综合久久88色综合天天 | 国产亚av手机在线观看 | 狂野欧美性猛xxxx乱大交 | 夜夜躁日日躁狠狠久久av | 一区二区传媒有限公司 | 国产精品18久久久久久麻辣 | 蜜臀aⅴ国产精品久久久国产老师 | 女人和拘做爰正片视频 | 国产精品内射视频免费 | 牛和人交xxxx欧美 | 影音先锋中文字幕无码 | 国产 精品 自在自线 | 精品无码av一区二区三区 | 亚洲欧美色中文字幕在线 | 小泽玛莉亚一区二区视频在线 | 伊人久久大香线焦av综合影院 | 老司机亚洲精品影院 | 日韩精品一区二区av在线 | 中文字幕中文有码在线 | 成人精品视频一区二区三区尤物 | 熟女俱乐部五十路六十路av | 无遮挡国产高潮视频免费观看 | 日本一卡二卡不卡视频查询 | 亚洲人成影院在线无码按摩店 | 任你躁国产自任一区二区三区 | 日本大香伊一区二区三区 | 日韩av无码中文无码电影 | 十八禁真人啪啪免费网站 | 亚洲国产成人av在线观看 | 国色天香社区在线视频 | 激情内射亚州一区二区三区爱妻 | 国产一区二区三区日韩精品 | 国产办公室秘书无码精品99 | 真人与拘做受免费视频一 | 人人妻人人澡人人爽人人精品浪潮 | 精品国精品国产自在久国产87 | 蜜臀aⅴ国产精品久久久国产老师 | 国产情侣作爱视频免费观看 | 日日麻批免费40分钟无码 | 久久婷婷五月综合色国产香蕉 | 人妻互换免费中文字幕 | 99久久久国产精品无码免费 | 国产精品视频免费播放 | 乱码av麻豆丝袜熟女系列 | 少妇性荡欲午夜性开放视频剧场 | 国产麻豆精品一区二区三区v视界 | 国产三级精品三级男人的天堂 | 国产疯狂伦交大片 | 欧美人与善在线com | 宝宝好涨水快流出来免费视频 | 久久无码中文字幕免费影院蜜桃 | 国内揄拍国内精品少妇国语 | 日产精品高潮呻吟av久久 | 99视频精品全部免费免费观看 | 欧美一区二区三区视频在线观看 | 亚洲中文字幕无码一久久区 | 精品 日韩 国产 欧美 视频 | 国内精品一区二区三区不卡 | 国产网红无码精品视频 | 国产精品a成v人在线播放 | 亚洲精品中文字幕 | 无码国产激情在线观看 | 麻豆md0077饥渴少妇 | 亚洲人亚洲人成电影网站色 | 亚洲中文字幕av在天堂 | 狠狠躁日日躁夜夜躁2020 | 夜精品a片一区二区三区无码白浆 | 久久久久免费精品国产 | 男人的天堂av网站 | 亚洲欧美日韩综合久久久 | 99久久精品午夜一区二区 | 色婷婷av一区二区三区之红樱桃 | 狠狠综合久久久久综合网 | 在线欧美精品一区二区三区 | 欧洲熟妇色 欧美 | 亚洲伊人久久精品影院 | 人妻少妇被猛烈进入中文字幕 | 亚洲综合在线一区二区三区 | 人人妻人人澡人人爽人人精品浪潮 | 久久精品国产99精品亚洲 | 丰满少妇熟乱xxxxx视频 | 人人妻人人澡人人爽精品欧美 | 成人免费视频视频在线观看 免费 | 亚洲国产av美女网站 | 亚洲精品中文字幕久久久久 | 人人妻人人澡人人爽精品欧美 | 日本一卡二卡不卡视频查询 | 亚洲精品一区二区三区在线观看 | 亚洲中文字幕无码中文字在线 | 国产乱人偷精品人妻a片 | 丝袜美腿亚洲一区二区 | 国产精品高潮呻吟av久久4虎 | 久久伊人色av天堂九九小黄鸭 | 日本精品人妻无码免费大全 | 国产成人综合在线女婷五月99播放 | 曰韩无码二三区中文字幕 | 日韩精品无码一区二区中文字幕 | 国产偷自视频区视频 | 熟妇人妻激情偷爽文 | 久青草影院在线观看国产 | 亚洲国产精品成人久久蜜臀 | 日本免费一区二区三区最新 | 日本一区二区更新不卡 | 国产美女精品一区二区三区 | 图片小说视频一区二区 | 亚洲 日韩 欧美 成人 在线观看 | 国产后入清纯学生妹 | 欧美三级a做爰在线观看 | 国产成人精品久久亚洲高清不卡 | 国产精品-区区久久久狼 | 中文字幕无码免费久久9一区9 | 樱花草在线播放免费中文 | 亚洲中文字幕av在天堂 | 2020久久香蕉国产线看观看 | 老司机亚洲精品影院 | 国产精品久久国产精品99 | 亚洲精品午夜国产va久久成人 | 亚洲精品综合五月久久小说 | 色婷婷久久一区二区三区麻豆 | 欧美精品国产综合久久 | 装睡被陌生人摸出水好爽 | 国产在线精品一区二区三区直播 | 欧美精品免费观看二区 | 国产精品久久久久久无码 | 无码成人精品区在线观看 | 伊人久久婷婷五月综合97色 | 性欧美疯狂xxxxbbbb | 国产av一区二区三区最新精品 | 人人妻人人藻人人爽欧美一区 | 300部国产真实乱 | 蜜桃臀无码内射一区二区三区 | 强奷人妻日本中文字幕 | 男人和女人高潮免费网站 | 亚洲爆乳精品无码一区二区三区 | 熟女少妇在线视频播放 | 国产无av码在线观看 | 久久久久成人片免费观看蜜芽 | 人妻少妇精品久久 | √天堂资源地址中文在线 | www一区二区www免费 | 蜜臀av在线播放 久久综合激激的五月天 | 日日麻批免费40分钟无码 | 欧美午夜特黄aaaaaa片 | 毛片内射-百度 | 久久国产自偷自偷免费一区调 | 国产精品丝袜黑色高跟鞋 | 一个人免费观看的www视频 | 成 人 免费观看网站 | 欧美性生交活xxxxxdddd | 国产亚洲日韩欧美另类第八页 | 国产乱人伦av在线无码 | 亚欧洲精品在线视频免费观看 | 熟女体下毛毛黑森林 | 亚洲高清偷拍一区二区三区 | 中文字幕精品av一区二区五区 | 亚洲国产av美女网站 | 中文字幕亚洲情99在线 | 亚洲精品国产品国语在线观看 | 亚洲成a人一区二区三区 | 日日夜夜撸啊撸 | 激情五月综合色婷婷一区二区 | 亚洲乱码中文字幕在线 | 成人aaa片一区国产精品 | 99久久亚洲精品无码毛片 | 久久99精品久久久久婷婷 | 澳门永久av免费网站 | 久久五月精品中文字幕 | 性欧美熟妇videofreesex | 色欲综合久久中文字幕网 | 大乳丰满人妻中文字幕日本 | 久久成人a毛片免费观看网站 | 亚洲の无码国产の无码步美 | 狠狠色噜噜狠狠狠狠7777米奇 | 欧洲美熟女乱又伦 | 十八禁真人啪啪免费网站 | 亚洲色偷偷男人的天堂 | 精品久久久久久人妻无码中文字幕 | 麻豆成人精品国产免费 | 99久久久国产精品无码免费 | 无码精品人妻一区二区三区av | 沈阳熟女露脸对白视频 | 少女韩国电视剧在线观看完整 | 偷窥日本少妇撒尿chinese | 精品国产青草久久久久福利 | 亚洲午夜福利在线观看 | 精品厕所偷拍各类美女tp嘘嘘 | 久久久久国色av免费观看性色 | 日本成熟视频免费视频 | 97无码免费人妻超级碰碰夜夜 | 我要看www免费看插插视频 | 一本久久a久久精品亚洲 | 日韩av无码一区二区三区 | 国产精品久久久久久亚洲影视内衣 | 日日摸夜夜摸狠狠摸婷婷 | 377p欧洲日本亚洲大胆 | 男女猛烈xx00免费视频试看 | 国产口爆吞精在线视频 | 欧美国产日韩亚洲中文 | 成人免费无码大片a毛片 | 青青久在线视频免费观看 | 亚洲精品一区二区三区大桥未久 | 日本护士毛茸茸高潮 | 老子影院午夜伦不卡 | 国产电影无码午夜在线播放 | 久久99精品国产.久久久久 | aⅴ在线视频男人的天堂 | 亚洲乱码日产精品bd | 蜜臀av在线观看 在线欧美精品一区二区三区 | 亚洲区小说区激情区图片区 | 波多野结衣aⅴ在线 | 国产精品美女久久久久av爽李琼 | 天堂无码人妻精品一区二区三区 | 未满小14洗澡无码视频网站 | 久久精品国产一区二区三区 | 狠狠色噜噜狠狠狠7777奇米 | 中文字幕人妻无码一区二区三区 | 国产国产精品人在线视 | 天天摸天天碰天天添 | 少妇无码一区二区二三区 | 亚洲va欧美va天堂v国产综合 | 国产午夜无码精品免费看 | 99久久精品日本一区二区免费 | 人人爽人人澡人人高潮 | 国产精品第一区揄拍无码 | 99久久久无码国产精品免费 | 漂亮人妻洗澡被公强 日日躁 | 西西人体www44rt大胆高清 | 日韩精品乱码av一区二区 | 中文字幕色婷婷在线视频 | 无码av岛国片在线播放 | 国产精品永久免费视频 | 欧美日韩一区二区综合 | 亚洲成av人影院在线观看 | 日日麻批免费40分钟无码 | 精品人妻av区 | 丰满岳乱妇在线观看中字无码 | 一本色道久久综合狠狠躁 | 国产成人一区二区三区在线观看 | 在线精品国产一区二区三区 | 国产精品内射视频免费 | 人妻熟女一区 | 性生交大片免费看l | 国产精品久久国产三级国 | www国产精品内射老师 | 欧美黑人性暴力猛交喷水 | a在线观看免费网站大全 | av无码久久久久不卡免费网站 | 天天拍夜夜添久久精品大 | 亚洲第一无码av无码专区 | 日产国产精品亚洲系列 | 久久99久久99精品中文字幕 | 乱码午夜-极国产极内射 | 一本无码人妻在中文字幕免费 | 国产在线一区二区三区四区五区 | 亚洲欧美国产精品久久 | 亚洲欧洲日本综合aⅴ在线 | 7777奇米四色成人眼影 | 一二三四在线观看免费视频 | 狠狠色噜噜狠狠狠狠7777米奇 | 色欲久久久天天天综合网精品 | 国语精品一区二区三区 | 中文字幕乱妇无码av在线 | 5858s亚洲色大成网站www | 午夜无码区在线观看 | 亚洲色欲久久久综合网东京热 | 熟妇女人妻丰满少妇中文字幕 | 中文字幕人妻无码一夲道 | 野外少妇愉情中文字幕 | 国产情侣作爱视频免费观看 | 色综合久久久久综合一本到桃花网 | 蜜桃av抽搐高潮一区二区 | 亚洲色偷偷偷综合网 | 十八禁视频网站在线观看 | 欧美成人免费全部网站 | 宝宝好涨水快流出来免费视频 | 亚洲无人区一区二区三区 | 国产精品视频免费播放 | 久久综合九色综合97网 | 国产精品视频免费播放 | 国产成人精品久久亚洲高清不卡 | 国产小呦泬泬99精品 | 强奷人妻日本中文字幕 | 国产色在线 | 国产 | 97精品人妻一区二区三区香蕉 | 水蜜桃av无码 | 日产精品高潮呻吟av久久 | 一本色道久久综合狠狠躁 | 丰满少妇熟乱xxxxx视频 | 嫩b人妻精品一区二区三区 | 四虎永久在线精品免费网址 | 亚洲一区二区三区香蕉 | 一本加勒比波多野结衣 | 白嫩日本少妇做爰 | 丰满肥臀大屁股熟妇激情视频 | 精品久久久无码中文字幕 | 国产偷抇久久精品a片69 | 波多野结衣一区二区三区av免费 | 国产成人精品优优av | 76少妇精品导航 | 久久精品中文字幕大胸 | 日本熟妇乱子伦xxxx | 午夜精品久久久久久久 | 欧美高清在线精品一区 | 久久亚洲精品中文字幕无男同 | 免费观看的无遮挡av | 内射爽无广熟女亚洲 | 免费国产成人高清在线观看网站 | 国产人妻大战黑人第1集 | 久久久久亚洲精品男人的天堂 | 亚洲国产综合无码一区 | 国产免费久久久久久无码 | 少妇无套内谢久久久久 | 亚洲精品一区二区三区四区五区 | 日韩视频 中文字幕 视频一区 | 免费无码av一区二区 | 久久婷婷五月综合色国产香蕉 | 亚洲成av人综合在线观看 | 亚洲国产欧美在线成人 | 欧洲精品码一区二区三区免费看 | 300部国产真实乱 | 成人性做爰aaa片免费看不忠 | 亚洲精品午夜国产va久久成人 | 国产激情无码一区二区 | 蜜桃av抽搐高潮一区二区 | 一本久道高清无码视频 | 玩弄中年熟妇正在播放 | 在线播放无码字幕亚洲 | 女人高潮内射99精品 | 全黄性性激高免费视频 | 亚洲の无码国产の无码影院 | 午夜精品久久久久久久 | 99久久精品无码一区二区毛片 | 高清不卡一区二区三区 | 玩弄少妇高潮ⅹxxxyw | 正在播放老肥熟妇露脸 | 特级做a爰片毛片免费69 | 图片小说视频一区二区 | 久久久国产精品无码免费专区 | 无码成人精品区在线观看 | 人妻体内射精一区二区三四 | 在线亚洲高清揄拍自拍一品区 | 久久综合香蕉国产蜜臀av | 强伦人妻一区二区三区视频18 | 国产午夜无码视频在线观看 | 麻豆果冻传媒2021精品传媒一区下载 | 久久精品丝袜高跟鞋 | 亚洲s码欧洲m码国产av | 性色欲情网站iwww九文堂 | 亚洲 欧美 激情 小说 另类 | 国产精品亚洲专区无码不卡 | 老子影院午夜精品无码 | 中文字幕精品av一区二区五区 | 婷婷丁香五月天综合东京热 | 5858s亚洲色大成网站www | 曰韩少妇内射免费播放 | 对白脏话肉麻粗话av | 97无码免费人妻超级碰碰夜夜 | 久久久精品成人免费观看 | 久久人人97超碰a片精品 | 无码国产乱人伦偷精品视频 | 内射老妇bbwx0c0ck | 伊在人天堂亚洲香蕉精品区 | 搡女人真爽免费视频大全 | 一本色道久久综合亚洲精品不卡 | 老熟妇仑乱视频一区二区 | 丰满少妇女裸体bbw | 日本精品高清一区二区 | 亚洲一区二区三区 | 亚洲一区二区三区国产精华液 | 人人爽人人爽人人片av亚洲 | 日韩成人一区二区三区在线观看 | 日欧一片内射va在线影院 | 伊人久久婷婷五月综合97色 | 日韩精品无码免费一区二区三区 | 丰满护士巨好爽好大乳 | 丰满少妇弄高潮了www | 特黄特色大片免费播放器图片 | 亚洲天堂2017无码中文 | 国内揄拍国内精品人妻 | 亚洲热妇无码av在线播放 | 国产深夜福利视频在线 | 免费网站看v片在线18禁无码 | 99久久久无码国产精品免费 | 人人妻人人澡人人爽欧美精品 | 粗大的内捧猛烈进出视频 | 欧美精品一区二区精品久久 | 午夜精品久久久内射近拍高清 | 国产亚洲精品精品国产亚洲综合 | 好屌草这里只有精品 | 国产精品欧美成人 | 久久天天躁狠狠躁夜夜免费观看 | 人人超人人超碰超国产 | 日日摸夜夜摸狠狠摸婷婷 | 精品国偷自产在线视频 | 18禁止看的免费污网站 | 国产成人人人97超碰超爽8 | 国产xxx69麻豆国语对白 | 高潮毛片无遮挡高清免费视频 | 久久久久成人片免费观看蜜芽 | 精品无码国产自产拍在线观看蜜 | 色综合久久久久综合一本到桃花网 | 欧美人与牲动交xxxx | 国产午夜亚洲精品不卡下载 | 在线а√天堂中文官网 | 国产精品久久久午夜夜伦鲁鲁 | 免费视频欧美无人区码 | 在线观看国产一区二区三区 | 宝宝好涨水快流出来免费视频 | 亚洲成熟女人毛毛耸耸多 | 国产一区二区不卡老阿姨 | 成人三级无码视频在线观看 | 男女猛烈xx00免费视频试看 | 国产成人无码a区在线观看视频app | 亚洲伊人久久精品影院 | 老子影院午夜伦不卡 | 久久精品国产99久久6动漫 | 国产亚洲精品精品国产亚洲综合 | 亚洲第一无码av无码专区 | 男女性色大片免费网站 | www国产亚洲精品久久久日本 | 欧美阿v高清资源不卡在线播放 | 麻豆国产人妻欲求不满 | 国产亚洲人成在线播放 | 国内揄拍国内精品少妇国语 | 荡女精品导航 | 国产午夜亚洲精品不卡下载 | 狠狠亚洲超碰狼人久久 | 亚洲自偷精品视频自拍 | 一本无码人妻在中文字幕免费 | 女高中生第一次破苞av | 久久伊人色av天堂九九小黄鸭 | 一本精品99久久精品77 | 免费视频欧美无人区码 | 亚欧洲精品在线视频免费观看 | 少妇一晚三次一区二区三区 | 99视频精品全部免费免费观看 | 撕开奶罩揉吮奶头视频 | 国产精品欧美成人 | 天堂亚洲2017在线观看 | 色偷偷人人澡人人爽人人模 | 一本无码人妻在中文字幕免费 | 亚洲自偷精品视频自拍 | 无码乱肉视频免费大全合集 | 午夜福利一区二区三区在线观看 | 亚洲国产一区二区三区在线观看 | 久久久国产精品无码免费专区 | 亚洲娇小与黑人巨大交 | 99久久精品无码一区二区毛片 | 亚洲色在线无码国产精品不卡 | 香港三级日本三级妇三级 | 精品国产一区二区三区四区在线看 | 亚洲国产欧美日韩精品一区二区三区 | 亚洲国产欧美国产综合一区 | 欧美三级a做爰在线观看 | 两性色午夜视频免费播放 | 午夜丰满少妇性开放视频 | 18禁黄网站男男禁片免费观看 | 亚洲色偷偷男人的天堂 | 国产亚洲人成在线播放 | 黑森林福利视频导航 | 18无码粉嫩小泬无套在线观看 | a国产一区二区免费入口 | 2020久久香蕉国产线看观看 | 国产成人无码专区 | 精品一区二区不卡无码av | 天堂亚洲2017在线观看 | 性啪啪chinese东北女人 | 国产国语老龄妇女a片 | 性生交大片免费看l | 亚洲国产精品无码一区二区三区 | 久久www免费人成人片 | 成人精品视频一区二区三区尤物 | 午夜精品一区二区三区在线观看 | 天天综合网天天综合色 | 三级4级全黄60分钟 | 精品欧美一区二区三区久久久 | 久久精品中文字幕一区 | 伊人色综合久久天天小片 | www一区二区www免费 | 最新国产麻豆aⅴ精品无码 | 最新国产麻豆aⅴ精品无码 | 领导边摸边吃奶边做爽在线观看 | 亚洲精品一区二区三区大桥未久 | 成人一在线视频日韩国产 | 激情爆乳一区二区三区 | 狂野欧美激情性xxxx | 亚洲色大成网站www | 国产乱人无码伦av在线a | 日本爽爽爽爽爽爽在线观看免 | 国产9 9在线 | 中文 | 亚洲国产一区二区三区在线观看 | 亚洲国产av精品一区二区蜜芽 | 久久综合给久久狠狠97色 | 成人无码视频在线观看网站 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产在热线精品视频 | 国产成人综合在线女婷五月99播放 | 无码纯肉视频在线观看 | 亚洲成a人一区二区三区 | 377p欧洲日本亚洲大胆 | 精品午夜福利在线观看 | 国产午夜精品一区二区三区嫩草 | 夜夜高潮次次欢爽av女 | 亚洲小说图区综合在线 | 国产黄在线观看免费观看不卡 | 野外少妇愉情中文字幕 | 六月丁香婷婷色狠狠久久 | 亚洲爆乳精品无码一区二区三区 | 娇妻被黑人粗大高潮白浆 | 两性色午夜视频免费播放 | 国产三级久久久精品麻豆三级 | 一个人看的www免费视频在线观看 | 狠狠色色综合网站 | 国语自产偷拍精品视频偷 | 国产激情精品一区二区三区 | 日日碰狠狠躁久久躁蜜桃 | 欧美性生交活xxxxxdddd | 国产亚洲视频中文字幕97精品 | 极品嫩模高潮叫床 | 国产精品久久久久7777 | 国产明星裸体无码xxxx视频 | 国产极品视觉盛宴 | av人摸人人人澡人人超碰下载 | 99久久久无码国产精品免费 | 性色av无码免费一区二区三区 | 亚洲男人av天堂午夜在 | 国产后入清纯学生妹 | 三级4级全黄60分钟 | 久久国产精品二国产精品 | 久久www免费人成人片 | 国产内射爽爽大片视频社区在线 | 国产黄在线观看免费观看不卡 | 久久综合给久久狠狠97色 | 亚洲中文字幕久久无码 | 久久国产36精品色熟妇 | 97se亚洲精品一区 | 在线播放免费人成毛片乱码 | 小sao货水好多真紧h无码视频 | 国产无套内射久久久国产 | 狠狠色色综合网站 | 在线 国产 欧美 亚洲 天堂 | 欧美三级a做爰在线观看 | 荫蒂添的好舒服视频囗交 | 人妻少妇精品视频专区 | 亚洲人成网站免费播放 | 亚洲欧洲无卡二区视頻 | 午夜精品久久久内射近拍高清 | 黄网在线观看免费网站 | 亚洲另类伦春色综合小说 | 日本熟妇大屁股人妻 | 国产两女互慰高潮视频在线观看 | 亚洲精品一区国产 | 丰满人妻被黑人猛烈进入 | 亚洲中文字幕在线无码一区二区 | 久久天天躁夜夜躁狠狠 | 在线观看免费人成视频 | 老子影院午夜精品无码 | 成人一区二区免费视频 | 国产精品a成v人在线播放 | 青青草原综合久久大伊人精品 | 久久久精品456亚洲影院 | 国产av人人夜夜澡人人爽麻豆 | 亚洲午夜无码久久 | 亚洲熟妇自偷自拍另类 | 老司机亚洲精品影院 | 亚洲中文字幕无码中文字在线 | 十八禁真人啪啪免费网站 | 成熟女人特级毛片www免费 | 国产精品无码一区二区桃花视频 | 一本久久a久久精品亚洲 | 青青草原综合久久大伊人精品 | 99久久亚洲精品无码毛片 | 四虎4hu永久免费 | 性欧美牲交在线视频 | 国产精品第一区揄拍无码 | 国产乱人伦偷精品视频 | 日本www一道久久久免费榴莲 | 亚洲综合精品香蕉久久网 | 国产激情艳情在线看视频 | 在线a亚洲视频播放在线观看 | 亚洲无人区午夜福利码高清完整版 | 亚洲第一无码av无码专区 | 国产成人无码a区在线观看视频app | 亚洲va欧美va天堂v国产综合 | 亚洲国产精品毛片av不卡在线 | 无遮挡啪啪摇乳动态图 | 亚洲欧洲中文日韩av乱码 | 精品熟女少妇av免费观看 | 国产真实乱对白精彩久久 | 成熟人妻av无码专区 | 色综合久久久久综合一本到桃花网 | 午夜精品久久久久久久久 | 久久久久99精品成人片 | 精品无码国产自产拍在线观看蜜 | 精品国产福利一区二区 | 久久精品国产亚洲精品 | 国产av一区二区精品久久凹凸 | 国产精品嫩草久久久久 | 亚洲一区二区观看播放 | 巨爆乳无码视频在线观看 | 无码福利日韩神码福利片 | 久久久久久av无码免费看大片 | 国产亚洲日韩欧美另类第八页 | 国产偷国产偷精品高清尤物 | 熟妇女人妻丰满少妇中文字幕 | 日本肉体xxxx裸交 | 色婷婷综合激情综在线播放 | 欧美日韩在线亚洲综合国产人 | 精品无码av一区二区三区 | 人妻插b视频一区二区三区 | 欧美老熟妇乱xxxxx | 少妇一晚三次一区二区三区 | 特黄特色大片免费播放器图片 | 一个人免费观看的www视频 | aⅴ亚洲 日韩 色 图网站 播放 | 日产精品高潮呻吟av久久 | 精品乱子伦一区二区三区 | 正在播放老肥熟妇露脸 | 在线播放免费人成毛片乱码 | www成人国产高清内射 | 国产真人无遮挡作爱免费视频 | 一区二区三区高清视频一 | 久久久久成人精品免费播放动漫 | 丝袜足控一区二区三区 | 国产精品国产自线拍免费软件 | 久久久国产精品无码免费专区 | 婷婷色婷婷开心五月四房播播 | 国产亚洲tv在线观看 | 亚洲七七久久桃花影院 | 亚拍精品一区二区三区探花 | 国产精品对白交换视频 | 久久久久成人精品免费播放动漫 | 丰满少妇熟乱xxxxx视频 | 九月婷婷人人澡人人添人人爽 | 欧美熟妇另类久久久久久不卡 | 国产亚洲日韩欧美另类第八页 | 国产精品亚洲一区二区三区喷水 | 天下第一社区视频www日本 | 蜜臀aⅴ国产精品久久久国产老师 | 熟女体下毛毛黑森林 | v一区无码内射国产 | 爆乳一区二区三区无码 | 精品 日韩 国产 欧美 视频 | 久久99精品久久久久久动态图 | 国产又爽又猛又粗的视频a片 | 成人综合网亚洲伊人 | 欧美成人家庭影院 | 亚洲色偷偷偷综合网 | 亚洲爆乳精品无码一区二区三区 | 老太婆性杂交欧美肥老太 | 亚洲综合色区中文字幕 | 国产精品.xx视频.xxtv | 久久亚洲中文字幕无码 | 日本精品少妇一区二区三区 | 岛国片人妻三上悠亚 | 国产成人一区二区三区在线观看 | 中文字幕中文有码在线 | 红桃av一区二区三区在线无码av | 成人欧美一区二区三区 | 毛片内射-百度 | 人妻天天爽夜夜爽一区二区 | 在线看片无码永久免费视频 | 国产成人无码av一区二区 | 狂野欧美性猛交免费视频 | 亚洲精品中文字幕 | 亚洲国产精品久久久天堂 | 丁香花在线影院观看在线播放 | 无码午夜成人1000部免费视频 | 日日摸夜夜摸狠狠摸婷婷 | 国产精品无码成人午夜电影 | 99精品视频在线观看免费 | 国产香蕉97碰碰久久人人 | 免费乱码人妻系列无码专区 | 欧美人与禽zoz0性伦交 | 成人无码视频免费播放 | 真人与拘做受免费视频一 | 国产亚洲美女精品久久久2020 | 激情综合激情五月俺也去 | 日本va欧美va欧美va精品 | 欧美xxxx黑人又粗又长 | 国产香蕉尹人视频在线 | 成人免费视频一区二区 | 久久www免费人成人片 | 国产熟妇高潮叫床视频播放 | 国产色精品久久人妻 | 一本久久a久久精品亚洲 | 久久精品女人天堂av免费观看 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 狠狠躁日日躁夜夜躁2020 | 亚洲人亚洲人成电影网站色 | 日韩无套无码精品 | 男女下面进入的视频免费午夜 | 国内少妇偷人精品视频免费 | 欧美精品无码一区二区三区 | 女人和拘做爰正片视频 | 国产口爆吞精在线视频 | av无码电影一区二区三区 | 自拍偷自拍亚洲精品被多人伦好爽 | 亚洲一区二区三区 | 日韩视频 中文字幕 视频一区 | 免费观看又污又黄的网站 | 欧美性黑人极品hd | 永久免费观看国产裸体美女 | 精品国产av色一区二区深夜久久 | 精品成人av一区二区三区 | 亚无码乱人伦一区二区 | 六月丁香婷婷色狠狠久久 | 亚洲精品午夜国产va久久成人 | 国产成人久久精品流白浆 | 国产热a欧美热a在线视频 | 国产午夜福利亚洲第一 | 又紧又大又爽精品一区二区 | 老子影院午夜伦不卡 | 国产综合色产在线精品 | 日韩亚洲欧美精品综合 | 天堂无码人妻精品一区二区三区 | 亚洲精品久久久久久一区二区 | 亚洲毛片av日韩av无码 | 欧美日韩综合一区二区三区 | 久久午夜无码鲁丝片午夜精品 | 亚洲爆乳大丰满无码专区 | 国产一区二区三区日韩精品 | 久久精品中文字幕一区 | 99久久99久久免费精品蜜桃 | 5858s亚洲色大成网站www | 国产精品人人爽人人做我的可爱 | 2020最新国产自产精品 | 在线观看欧美一区二区三区 | 中文字幕无码热在线视频 | 亚洲精品一区二区三区四区五区 | 婷婷综合久久中文字幕蜜桃三电影 | 国产精品资源一区二区 | 国产无遮挡又黄又爽免费视频 | 亚洲熟妇色xxxxx欧美老妇 | 日日碰狠狠躁久久躁蜜桃 | 久久 国产 尿 小便 嘘嘘 | 中文字幕亚洲情99在线 | 久久国产精品精品国产色婷婷 | 漂亮人妻洗澡被公强 日日躁 | 国产亚洲人成a在线v网站 | 撕开奶罩揉吮奶头视频 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | 色综合久久88色综合天天 | 奇米影视7777久久精品 | 国内少妇偷人精品视频免费 | 人妻少妇精品无码专区二区 | 未满小14洗澡无码视频网站 | 欧美日本精品一区二区三区 | 国产美女极度色诱视频www | 男女爱爱好爽视频免费看 | 亚洲国产av精品一区二区蜜芽 | 亚洲一区二区三区在线观看网站 | 国产97人人超碰caoprom | 国产精品国产自线拍免费软件 | 熟女俱乐部五十路六十路av | 熟妇人妻无码xxx视频 | 呦交小u女精品视频 | 牛和人交xxxx欧美 | 亚洲色欲色欲欲www在线 | 精品一二三区久久aaa片 | 偷窥日本少妇撒尿chinese | 欧美性色19p | 人人澡人人妻人人爽人人蜜桃 | 久久综合色之久久综合 | 丁香花在线影院观看在线播放 | 乱人伦人妻中文字幕无码久久网 | 亚洲国产精品毛片av不卡在线 | aⅴ亚洲 日韩 色 图网站 播放 | 人妻互换免费中文字幕 | 亚洲精品成人av在线 | 激情综合激情五月俺也去 | 亚洲性无码av中文字幕 | 久久人人爽人人人人片 | а天堂中文在线官网 | 亚洲欧洲中文日韩av乱码 | 亚洲色成人中文字幕网站 | 漂亮人妻洗澡被公强 日日躁 | 精品人妻人人做人人爽 | 老司机亚洲精品影院无码 | 日本成熟视频免费视频 | 人人澡人人妻人人爽人人蜜桃 | 粗大的内捧猛烈进出视频 | 亚洲国产精品久久久天堂 | 国产日产欧产精品精品app | 少妇激情av一区二区 | 成在人线av无码免观看麻豆 | 亚洲欧美中文字幕5发布 | 午夜精品一区二区三区在线观看 | 无码一区二区三区在线观看 | 亚洲天堂2017无码 | 国产精品久久久av久久久 | 97色伦图片97综合影院 | 国产精品久久久久久亚洲毛片 | 久久综合九色综合欧美狠狠 | 国产精品久久国产三级国 | 成人试看120秒体验区 | 国内少妇偷人精品视频免费 | 国模大胆一区二区三区 | 国产人妻精品一区二区三区不卡 | 婷婷五月综合缴情在线视频 | 丰满护士巨好爽好大乳 | 国产国产精品人在线视 | 久久精品人妻少妇一区二区三区 | 男女猛烈xx00免费视频试看 | 久久久婷婷五月亚洲97号色 | 日本一卡2卡3卡4卡无卡免费网站 国产一区二区三区影院 | 国色天香社区在线视频 | 学生妹亚洲一区二区 | 成人无码视频在线观看网站 | 99久久人妻精品免费二区 | 无码人妻精品一区二区三区下载 | 四十如虎的丰满熟妇啪啪 | 国产激情无码一区二区app | 精品久久8x国产免费观看 | 丰满人妻精品国产99aⅴ | 日韩 欧美 动漫 国产 制服 | 国产av剧情md精品麻豆 | 无码国模国产在线观看 | 国产精品久久精品三级 | 色噜噜亚洲男人的天堂 | 熟女体下毛毛黑森林 | 中文字幕日韩精品一区二区三区 | 亚洲欧美国产精品专区久久 | 久久久久国色av免费观看性色 | 无码国产色欲xxxxx视频 | 少女韩国电视剧在线观看完整 | 国产97在线 | 亚洲 | 国产精品久久久午夜夜伦鲁鲁 | 国产精品美女久久久网av | 亚洲色欲色欲欲www在线 | 美女扒开屁股让男人桶 | 欧美xxxx黑人又粗又长 | 成人亚洲精品久久久久软件 | 色综合久久88色综合天天 | 国产特级毛片aaaaaa高潮流水 | 天下第一社区视频www日本 | 99riav国产精品视频 | 久久伊人色av天堂九九小黄鸭 | 少妇高潮喷潮久久久影院 | 国产精品人妻一区二区三区四 | 99久久精品国产一区二区蜜芽 | 国产黄在线观看免费观看不卡 | 国产成人精品无码播放 | 国产精品成人av在线观看 | 人妻有码中文字幕在线 | 成人性做爰aaa片免费看不忠 | 一区二区三区乱码在线 | 欧洲 | 无套内谢的新婚少妇国语播放 | 久久久久成人精品免费播放动漫 | 久久综合狠狠综合久久综合88 | 欧美成人午夜精品久久久 | 色一情一乱一伦一区二区三欧美 | 国色天香社区在线视频 | 99久久精品日本一区二区免费 | 久热国产vs视频在线观看 | 国产亚洲精品久久久久久大师 | 红桃av一区二区三区在线无码av | 中文字幕日韩精品一区二区三区 | 荡女精品导航 | 丰满少妇弄高潮了www | 人人妻人人澡人人爽欧美一区九九 | 婷婷五月综合缴情在线视频 | 97久久精品无码一区二区 | 久久久久免费看成人影片 | 亚洲精品国产品国语在线观看 | 四虎永久在线精品免费网址 | 欧美人与物videos另类 | 麻豆国产人妻欲求不满 | 久久综合给久久狠狠97色 | 国产亚洲美女精品久久久2020 | 国产综合在线观看 | 精品偷自拍另类在线观看 | 国产亚洲欧美日韩亚洲中文色 | 免费看少妇作爱视频 | 88国产精品欧美一区二区三区 | 久青草影院在线观看国产 | 麻豆国产人妻欲求不满 | 国产无套内射久久久国产 | 免费男性肉肉影院 | 蜜桃av抽搐高潮一区二区 | 国产亚洲欧美在线专区 | 无码精品人妻一区二区三区av | 国产午夜福利亚洲第一 | 性生交大片免费看女人按摩摩 | 亚洲人成影院在线无码按摩店 | аⅴ资源天堂资源库在线 | 天天燥日日燥 | 丰满肥臀大屁股熟妇激情视频 | 国产精品久久久久久无码 | 国产精品国产自线拍免费软件 | 国产精品丝袜黑色高跟鞋 | 国产精品丝袜黑色高跟鞋 | 波多野结衣 黑人 | 国产办公室秘书无码精品99 | av无码不卡在线观看免费 | 亚洲人交乣女bbw | 黄网在线观看免费网站 | 久久国产自偷自偷免费一区调 | 成人无码影片精品久久久 | 免费人成网站视频在线观看 | 任你躁国产自任一区二区三区 | 久久综合色之久久综合 | 内射巨臀欧美在线视频 | 国产亚洲精品久久久闺蜜 | 丰满少妇人妻久久久久久 | 亚洲aⅴ无码成人网站国产app | 思思久久99热只有频精品66 | 免费视频欧美无人区码 | 桃花色综合影院 | 成人女人看片免费视频放人 | 国产精品亚洲综合色区韩国 | 乱人伦中文视频在线观看 | 无码任你躁久久久久久久 | 亚洲 a v无 码免 费 成 人 a v | 色一情一乱一伦一视频免费看 | 国产成人无码专区 | 国产人妻人伦精品 | 国产卡一卡二卡三 | 国产av一区二区精品久久凹凸 | 国产高清av在线播放 | а√天堂www在线天堂小说 | 国产明星裸体无码xxxx视频 | 亚洲小说图区综合在线 | 性色av无码免费一区二区三区 | 麻花豆传媒剧国产免费mv在线 | 日韩视频 中文字幕 视频一区 | 九九热爱视频精品 | 国产熟妇另类久久久久 | 久久综合九色综合欧美狠狠 | 精品国精品国产自在久国产87 | 一区二区三区乱码在线 | 欧洲 | 我要看www免费看插插视频 | 日本高清一区免费中文视频 | 亚洲呦女专区 | 人妻夜夜爽天天爽三区 | 国产精品亚洲lv粉色 | 久久久久久久久888 | 中文无码成人免费视频在线观看 | 乱人伦人妻中文字幕无码 | 亚洲精品国偷拍自产在线观看蜜桃 | 亚洲精品一区二区三区大桥未久 | 免费观看黄网站 | 无码国模国产在线观看 | 国产精品无套呻吟在线 | aⅴ在线视频男人的天堂 | 在线成人www免费观看视频 | 国产69精品久久久久app下载 | 天天做天天爱天天爽综合网 | 极品嫩模高潮叫床 | 久久99热只有频精品8 | 国产内射老熟女aaaa | 蜜桃av抽搐高潮一区二区 | 丰满少妇弄高潮了www | 亚洲欧美日韩综合久久久 | 中文字幕av无码一区二区三区电影 | 国产亚洲人成在线播放 | 丰满少妇弄高潮了www | 久久婷婷五月综合色国产香蕉 | 亚洲乱码中文字幕在线 | 国产色视频一区二区三区 | 乱码午夜-极国产极内射 | 一本大道伊人av久久综合 | 久久亚洲日韩精品一区二区三区 | 亚洲欧美日韩综合久久久 | 任你躁国产自任一区二区三区 | 国产精品久久久久影院嫩草 | 无码毛片视频一区二区本码 | 人妻有码中文字幕在线 | 国产精品.xx视频.xxtv | 国产精品久免费的黄网站 | 欧美人与物videos另类 | 欧美国产日韩久久mv | 中文精品久久久久人妻不卡 | av无码不卡在线观看免费 | 激情亚洲一区国产精品 | 国产后入清纯学生妹 | 国产超碰人人爽人人做人人添 | 欧美老熟妇乱xxxxx | 欧美 日韩 人妻 高清 中文 | 国产午夜福利亚洲第一 | 亚洲精品一区二区三区大桥未久 | 国产精品久久久 | 亚洲精品美女久久久久久久 | 欧美真人作爱免费视频 | 蜜臀av在线播放 久久综合激激的五月天 | 高中生自慰www网站 | 国産精品久久久久久久 | 亚洲国产成人a精品不卡在线 | 日日天干夜夜狠狠爱 | 国产色在线 | 国产 | 婷婷五月综合激情中文字幕 | 久久综合给久久狠狠97色 | 在线亚洲高清揄拍自拍一品区 | 日本va欧美va欧美va精品 | 秋霞特色aa大片 | 无码成人精品区在线观看 | 色偷偷av老熟女 久久精品人妻少妇一区二区三区 | 欧美成人免费全部网站 | 老头边吃奶边弄进去呻吟 | 日韩精品久久久肉伦网站 | 国内揄拍国内精品人妻 | 中文字幕无码免费久久99 | 久久人人爽人人爽人人片av高清 | 熟女俱乐部五十路六十路av | 55夜色66夜色国产精品视频 | 久久亚洲精品中文字幕无男同 | 国产做国产爱免费视频 | 综合激情五月综合激情五月激情1 | 纯爱无遮挡h肉动漫在线播放 | 台湾无码一区二区 | av小次郎收藏 | 成人三级无码视频在线观看 | 天干天干啦夜天干天2017 | 亚洲精品国产精品乱码视色 | 曰本女人与公拘交酡免费视频 | 巨爆乳无码视频在线观看 | 日韩精品无码一区二区中文字幕 | 国产内射爽爽大片视频社区在线 | 精品人妻av区 | 性色av无码免费一区二区三区 | 日韩精品久久久肉伦网站 | 波多野42部无码喷潮在线 | 少妇无码吹潮 | 国产成人无码av在线影院 | 中文字幕人妻无码一区二区三区 | 99精品视频在线观看免费 | 丰满人妻一区二区三区免费视频 | 日本熟妇人妻xxxxx人hd | 无码av中文字幕免费放 | 欧美日韩视频无码一区二区三 | 精品乱码久久久久久久 | 在线欧美精品一区二区三区 | 国产成人无码午夜视频在线观看 | 亚洲啪av永久无码精品放毛片 | 人人澡人人妻人人爽人人蜜桃 | 婷婷丁香六月激情综合啪 | 欧美丰满老熟妇xxxxx性 | 久久精品国产一区二区三区 | 自拍偷自拍亚洲精品10p | 377p欧洲日本亚洲大胆 | 亚洲男女内射在线播放 | 国产熟妇高潮叫床视频播放 | 日本护士毛茸茸高潮 | 免费无码一区二区三区蜜桃大 | 在线播放亚洲第一字幕 | 亚洲精品中文字幕乱码 | 亚洲性无码av中文字幕 | 国产精品理论片在线观看 | 成人片黄网站色大片免费观看 | 一本大道伊人av久久综合 | 无码国产激情在线观看 | 国产舌乚八伦偷品w中 | 国产成人精品三级麻豆 | 波多野42部无码喷潮在线 | 久久99精品久久久久婷婷 | 麻豆蜜桃av蜜臀av色欲av | 精品日本一区二区三区在线观看 | 鲁大师影院在线观看 | 樱花草在线社区www | 日产国产精品亚洲系列 | 久久久国产精品无码免费专区 | 无码精品国产va在线观看dvd | 欧美色就是色 | 亚洲 日韩 欧美 成人 在线观看 | 亚洲伊人久久精品影院 | 亚洲区小说区激情区图片区 | 色诱久久久久综合网ywww | 中文字幕色婷婷在线视频 | 欧美丰满老熟妇xxxxx性 | 国产农村妇女aaaaa视频 撕开奶罩揉吮奶头视频 | | 领导边摸边吃奶边做爽在线观看 | 亚洲日韩精品欧美一区二区 | 熟妇激情内射com | 人人妻人人澡人人爽精品欧美 | 在线a亚洲视频播放在线观看 | 中文精品久久久久人妻不卡 | 亚洲精品中文字幕 | 欧美日本精品一区二区三区 | 久久久久久九九精品久 | 无遮挡国产高潮视频免费观看 | 色五月五月丁香亚洲综合网 | 色欲综合久久中文字幕网 | 夜夜高潮次次欢爽av女 | 国产乱码精品一品二品 | 成人无码视频在线观看网站 | 国产熟妇高潮叫床视频播放 | 无码一区二区三区在线 | 俺去俺来也在线www色官网 | 久久人人爽人人爽人人片ⅴ | 丰满岳乱妇在线观看中字无码 | 国产香蕉97碰碰久久人人 | 无套内谢老熟女 | 国产超碰人人爽人人做人人添 | 一本久久伊人热热精品中文字幕 | 3d动漫精品啪啪一区二区中 | 亚洲成a人片在线观看无码 | 国产成人综合在线女婷五月99播放 | 亚洲 高清 成人 动漫 | 99精品视频在线观看免费 | 欧美喷潮久久久xxxxx | 在线观看国产一区二区三区 | 日韩av无码一区二区三区 | 国产激情一区二区三区 | 亚洲 欧美 激情 小说 另类 | 宝宝好涨水快流出来免费视频 | 亚洲欧美日韩成人高清在线一区 | 久久久久久亚洲精品a片成人 | 丰满少妇熟乱xxxxx视频 | 亚洲国产精品无码一区二区三区 | 亚洲人成影院在线观看 | 一个人看的www免费视频在线观看 | 熟妇激情内射com | 老熟女乱子伦 | 熟女少妇人妻中文字幕 | 18无码粉嫩小泬无套在线观看 | 国产在线一区二区三区四区五区 | 亚洲码国产精品高潮在线 | 亚洲色大成网站www国产 | 欧美性生交活xxxxxdddd | 亚洲欧美精品伊人久久 | 荫蒂被男人添的好舒服爽免费视频 | 在线观看国产一区二区三区 | 国内综合精品午夜久久资源 | 色诱久久久久综合网ywww | 日韩欧美成人免费观看 | 国产无套粉嫩白浆在线 | 色综合视频一区二区三区 | 国产尤物精品视频 | 成人无码影片精品久久久 | 亚洲熟妇自偷自拍另类 | 在线精品国产一区二区三区 | 色婷婷香蕉在线一区二区 | 国产熟女一区二区三区四区五区 | 亚洲七七久久桃花影院 | 97人妻精品一区二区三区 | 色五月五月丁香亚洲综合网 | 久9re热视频这里只有精品 | 亚洲熟妇色xxxxx欧美老妇 | 荫蒂被男人添的好舒服爽免费视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 欧美午夜特黄aaaaaa片 | 亚洲小说春色综合另类 | 动漫av网站免费观看 | 色婷婷香蕉在线一区二区 | 日韩av无码一区二区三区不卡 | 一本久道久久综合婷婷五月 | 无套内射视频囯产 | ass日本丰满熟妇pics | 久久精品国产亚洲精品 | 成人性做爰aaa片免费看不忠 | 人妻人人添人妻人人爱 | 欧美一区二区三区 | 成人一区二区免费视频 | 在线亚洲高清揄拍自拍一品区 | 亚洲成色www久久网站 | 偷窥村妇洗澡毛毛多 | 亚欧洲精品在线视频免费观看 | 欧美成人午夜精品久久久 | 人妻天天爽夜夜爽一区二区 | 精品无码av一区二区三区 | 久久综合香蕉国产蜜臀av | 性啪啪chinese东北女人 | 天堂一区人妻无码 | 亚洲の无码国产の无码影院 | 熟女俱乐部五十路六十路av | 久久精品人人做人人综合 | 国产精品爱久久久久久久 | 成人动漫在线观看 | 国产精品久久福利网站 | 国产亚洲精品久久久闺蜜 | 乱码av麻豆丝袜熟女系列 | 国产农村妇女高潮大叫 | 无码国产色欲xxxxx视频 | 国产精品亚洲综合色区韩国 | 精品久久久无码人妻字幂 | 99精品国产综合久久久久五月天 | 动漫av网站免费观看 | www一区二区www免费 | 亚洲色偷偷偷综合网 | 日本成熟视频免费视频 | 无码免费一区二区三区 | 午夜熟女插插xx免费视频 | 国产在线精品一区二区三区直播 | 7777奇米四色成人眼影 | 久久精品国产一区二区三区肥胖 | 一本久久伊人热热精品中文字幕 | 一本色道久久综合亚洲精品不卡 | 又色又爽又黄的美女裸体网站 | 久久久精品国产sm最大网站 | 欧美激情一区二区三区成人 | 黄网在线观看免费网站 | 99精品久久毛片a片 | 国产精品人人爽人人做我的可爱 | 日本欧美一区二区三区乱码 | 日韩精品成人一区二区三区 | 久久午夜无码鲁丝片午夜精品 | 内射欧美老妇wbb | 婷婷五月综合缴情在线视频 | 国产两女互慰高潮视频在线观看 | 亚洲一区二区三区播放 | 麻花豆传媒剧国产免费mv在线 | 丰满岳乱妇在线观看中字无码 | 国语精品一区二区三区 | 一个人免费观看的www视频 | 少妇厨房愉情理9仑片视频 | 波多野结衣高清一区二区三区 | 狠狠色噜噜狠狠狠狠7777米奇 | 亚洲熟妇色xxxxx欧美老妇 | 六十路熟妇乱子伦 | 无码人妻av免费一区二区三区 | 日日碰狠狠躁久久躁蜜桃 | 美女毛片一区二区三区四区 | 高清无码午夜福利视频 | 欧美人与禽zoz0性伦交 | 色婷婷香蕉在线一区二区 | 国产精品va在线播放 | 久久久久成人片免费观看蜜芽 | 欧美freesex黑人又粗又大 | 熟女体下毛毛黑森林 | 日欧一片内射va在线影院 | 国产精品人人妻人人爽 | 日本高清一区免费中文视频 | 亚无码乱人伦一区二区 | 欧美性生交xxxxx久久久 | 国内精品人妻无码久久久影院蜜桃 | 宝宝好涨水快流出来免费视频 | 77777熟女视频在线观看 а天堂中文在线官网 | 高清国产亚洲精品自在久久 | 精品一区二区三区无码免费视频 | 狠狠色丁香久久婷婷综合五月 | 一本久道高清无码视频 | 99久久精品无码一区二区毛片 | 亚洲精品成人av在线 | 丰满人妻精品国产99aⅴ | 亚洲精品一区三区三区在线观看 | 夜夜高潮次次欢爽av女 | 亚洲熟熟妇xxxx | 免费人成在线视频无码 | 狠狠噜狠狠狠狠丁香五月 | 国产亚洲精品久久久久久大师 | 国产午夜手机精彩视频 | 狠狠色噜噜狠狠狠狠7777米奇 | 中文字幕av无码一区二区三区电影 | 男女作爱免费网站 | 精品人妻人人做人人爽 | 欧美日韩一区二区免费视频 | 亚洲综合另类小说色区 | 国产亚洲精品久久久久久久久动漫 | 丰满少妇熟乱xxxxx视频 | 日日摸日日碰夜夜爽av | 奇米影视888欧美在线观看 | 国产小呦泬泬99精品 | 午夜丰满少妇性开放视频 | 亚洲 激情 小说 另类 欧美 | 久久精品人妻少妇一区二区三区 | 无码人妻精品一区二区三区下载 | 在线播放无码字幕亚洲 | 精品国产国产综合精品 | 国产明星裸体无码xxxx视频 | 麻豆国产人妻欲求不满 | 亚洲色www成人永久网址 | 精品久久久久香蕉网 | 国产做国产爱免费视频 | 精品亚洲韩国一区二区三区 | 欧美日本精品一区二区三区 | 奇米影视7777久久精品人人爽 | 国产精品99久久精品爆乳 | 国产综合在线观看 | 欧美肥老太牲交大战 | 精品国产av色一区二区深夜久久 | 丰满少妇熟乱xxxxx视频 | 日日摸日日碰夜夜爽av | 亚洲色偷偷偷综合网 | 国产亚洲美女精品久久久2020 | 色欲久久久天天天综合网精品 | 婷婷色婷婷开心五月四房播播 | 人人爽人人澡人人人妻 | 色老头在线一区二区三区 | 99精品无人区乱码1区2区3区 | 激情人妻另类人妻伦 | 一区二区传媒有限公司 | 国产精品va在线观看无码 | 三上悠亚人妻中文字幕在线 | 日日天日日夜日日摸 | 国产在线aaa片一区二区99 | 奇米综合四色77777久久 东京无码熟妇人妻av在线网址 | 色欲人妻aaaaaaa无码 | 国产精品美女久久久网av | 久久久成人毛片无码 | 青青青爽视频在线观看 | 人妻aⅴ无码一区二区三区 | 鲁鲁鲁爽爽爽在线视频观看 | 国产国语老龄妇女a片 | 小sao货水好多真紧h无码视频 | 国产人成高清在线视频99最全资源 | 丝袜足控一区二区三区 |