聶永的博客

          記錄工作/學(xué)習(xí)的點(diǎn)點(diǎn)滴滴。

          MQTT-SN協(xié)議亂翻之功能描述

          前言

          緊接上文,這是第三篇,主要是對(duì)MQTT-SN 1.2協(xié)議進(jìn)行總體性功能描述。

          嗯,這一部分可以結(jié)合著MQTT協(xié)議對(duì)比著來看。

          網(wǎng)關(guān)的廣播和發(fā)現(xiàn)

          網(wǎng)關(guān)只能在成功連接到MQTT Server之后,才能夠周期性的在無線個(gè)人區(qū)域網(wǎng)WPNs內(nèi)對(duì)所有客戶端廣播ADVERTISE消息,便于客戶端被動(dòng)知道網(wǎng)關(guān)的存在。

          在同一網(wǎng)絡(luò)下,多個(gè)擁有不同Id的網(wǎng)關(guān)可有同時(shí)運(yùn)行中,但會(huì)由客戶端根據(jù)信號(hào)強(qiáng)弱決定連接具體網(wǎng)關(guān),無論何時(shí)只能連接一個(gè)網(wǎng)關(guān)。

          客戶端可維護(hù)一份可用網(wǎng)關(guān)列表(包含網(wǎng)關(guān)地址),在接收到包含有新的網(wǎng)關(guān)id的ADVERTISE和GWINFO消息后,其列表需要添加新的網(wǎng)關(guān)元素進(jìn)去。

          ADVERTISE廣播消息包含的下一次廣播間隔時(shí)長(zhǎng)Duration屬性,單位秒,設(shè)為變量T_ADV,應(yīng)該盡可能大與15分鐘(900秒),頻率降低是為了避免低速個(gè)人區(qū)域網(wǎng)絡(luò)的擁塞。

          針對(duì)接收ADVERTISE消息頻率,處理能力較強(qiáng)客戶端可以用于監(jiān)督網(wǎng)關(guān)是否可用。eg:客戶端連續(xù)N_ADV次接收不到某個(gè)網(wǎng)關(guān)ADVERTISE廣播消息,可認(rèn)為此網(wǎng)關(guān)經(jīng)死掉不可用并且從已維護(hù)的網(wǎng)關(guān)列表中移除。同樣的,作為備用的網(wǎng)關(guān)認(rèn)為主網(wǎng)關(guān)已掛掉,此時(shí)可處于激活狀態(tài),正常發(fā)揮作用。

          網(wǎng)關(guān)發(fā)送廣播消息ADVERTISE的時(shí)間間隔很長(zhǎng),這對(duì)導(dǎo)致新加入的客戶端不利,但客戶端可以直接發(fā)送SEARCHGW廣播消息進(jìn)行查詢網(wǎng)關(guān)。大量的新入設(shè)備會(huì)造成廣播風(fēng)暴造成網(wǎng)絡(luò)擁擠,每一個(gè)新加入的客戶端在發(fā)送SEARCHGW廣播消息之前都需要獲取一個(gè)隨機(jī)的延遲發(fā)送值(0-Tsearchgw),在延遲等待發(fā)送期間若接收到其它客戶端發(fā)送的SEARCHGW廣播消息,會(huì)取消掉自己的SEARCHGW廣播消息發(fā)送,等待網(wǎng)關(guān)GWINFO消息通知。

          SEARCHGW消息屬性radius廣播半徑,記為變量Rb,1跳(1 hop)在一般密集部署下的MQTT-SN客戶端基本可用。

          網(wǎng)關(guān)接收到SEARCHGW會(huì)即刻回復(fù)包含自身id的GWINFO消息??蛻舳耸盏絊EARCHGW后,若有需要延遲發(fā)送的SEARCHGW會(huì)取消掉,若自身維護(hù)一份多個(gè)可用網(wǎng)關(guān)列表,在等待T_GWINFO時(shí)間內(nèi)沒有收到GWINFO消息,會(huì)從列表中取出一條網(wǎng)關(guān)信息組裝成GWINFO消息并廣播出去。這就要求客戶端已運(yùn)行多時(shí),并且維護(hù)多個(gè)可用網(wǎng)關(guān)列表。

          GWINFO和SEARCHGW所包含半徑radius屬性值一致,這就要求底層網(wǎng)絡(luò)在傳輸時(shí)進(jìn)行決定是否需要傳輸?shù)狡渌愋途W(wǎng)絡(luò)中。

          若沒有接收到響應(yīng),SEARCHGW消息可能被重新傳輸。兩個(gè)連續(xù)的SEARCHGW消息重傳間隔應(yīng)該呈指數(shù)形式增加,避免太密集傳輸。

          客戶端的連接建立

          無論是基于哪一種傳輸協(xié)議,TCP or UDP,客戶端都需要建立連接,并且保持心跳,邏輯上和服務(wù)器端保持一條不斷線的雙向通道。下面一張圖,演示了客戶端建立連接的過程,并且設(shè)定客戶端在CONNECT消息中標(biāo)志位字段中遺囑WILL屬性為true,然后就有了遺囑主題/消息的請(qǐng)求過程。

          很多情況下,連接CONNECT是不需要遺囑支持的,網(wǎng)關(guān)會(huì)直接返回CONNACK消息,但網(wǎng)關(guān)會(huì)因?yàn)閾砣虿恢С忠恍〤ONNET特性,CONNACK所包含返回代碼字段ReturnCode中包含拒絕代碼,要求客戶端檢查是否連接成功,區(qū)別對(duì)待。比如:

           CONNACK消息返回狀態(tài)碼為0x01(Rejected: congestion,因擁塞被拒絕),客戶端需要在T_WAIT時(shí)間間隔后進(jìn)行重試。
          

          回話清理

          已經(jīng)連接的客戶端斷線后,若之前在CONNECT中沒有設(shè)置過會(huì)話清理(Clean Session)標(biāo)識(shí),那么之前的訂閱等信息在網(wǎng)關(guān)處將會(huì)持久存在。相比MQTT,MQTT-SN中的“Clean Session”標(biāo)識(shí)被擴(kuò)展到遺囑特性中。在CONNECT消息中,CleanSession和Will組合將會(huì)產(chǎn)生以下效果:

          • CleanSession=true, Will=true: 網(wǎng)關(guān)將會(huì)刪除之前對(duì)應(yīng)的所有訂閱和遺囑,新的遺囑主題/消息稍后即將重新處理
          • CleanSession=true, Will=false: 網(wǎng)關(guān)將會(huì)刪除之前對(duì)應(yīng)的所有訂閱和遺囑,返回CONNACK消息
          • CleanSession=false, Will=true: 網(wǎng)關(guān)將繼續(xù)持有之前對(duì)應(yīng)的所有訂閱,新的遺囑主題/消息稍后即將重新處理
          • CleanSession=false, Will=false: 網(wǎng)關(guān)將會(huì)繼續(xù)持有之前對(duì)應(yīng)的所有訂閱和遺囑等數(shù)據(jù),并返回CONNACK消息

          更新遺囑流程

          • CONNEECTION中標(biāo)志位Will中設(shè)置是否需要更新遺囑主題/消息
          • 空WILLTOPIC(兩個(gè)字節(jié))消息將會(huì)促使網(wǎng)關(guān)刪除對(duì)應(yīng)遺囑數(shù)據(jù)
          • WILLTOPICUPD/WILLMSGUPD可以更新/修改遺囑主題、遺囑消息
          • 空白WILLTOPICUPD(兩個(gè)字節(jié))消息意味著請(qǐng)求網(wǎng)清空對(duì)應(yīng)已有的遺囑數(shù)據(jù)

          主題注冊(cè)流程

          受限于無線傳感器網(wǎng)絡(luò)的有限帶寬和微小消息負(fù)載,PUBLISH消息中不能夠包含完整的主題名稱topic name。這就需要客戶端和網(wǎng)關(guān)之間通過注冊(cè)流程,獲取主題名稱對(duì)應(yīng)的(16位的自然數(shù))topic id,然后塞入PUBLISH消息的topicId屬性中。

          客戶端發(fā)送REGISTER消息,網(wǎng)關(guān)返回REGACK消息,其所包含的ReturenCode屬性決定注冊(cè)成功與否:

          • ReturnCode = “accepted”,topicId可以很愉快的使用在稍后的PUBLISH消息中
          • ReturnCode = “rejected: congestion”,客戶端需要稍等一段時(shí)間(T_WAIT表示,大于5分鐘)再次重新注冊(cè)
          • ReturnCode = “rejected: invalid topic ID/not supported”,客戶端需要稍作調(diào)整,再次重新注冊(cè)

          任意時(shí)間,只能執(zhí)行一個(gè)REGISTER消息,有沒有完成注冊(cè)流程,需要等待。

          網(wǎng)關(guān)->客戶端方向,網(wǎng)關(guān)發(fā)送REGISTER消息給通知客戶端指定topicId對(duì)應(yīng)某個(gè)主題,以便后面發(fā)送PUBLISH消息使用。若客戶端在訂閱SUBSCRIBE消息時(shí)使用了通配符(#/+),那么與之相匹配的topic name也將被一一通知到。因此不建議使用通配符,較為低效。

          客戶端發(fā)布流程

          客戶端一旦獲取到topic name對(duì)應(yīng)topic id,就可以直接發(fā)送PUBLISH消息了。這和MQTT協(xié)議相比,PUBLISH消息中Topic Name被替換成Topic Id,除此之外,還要注意ReturnCode:

          • ReturnCode = “rejected: congestion”,客戶端需要稍等一段時(shí)間(>5分鐘)后再次重試
          • ReturnCode = “rejected: invalid topic ID”,客戶端需要重新注冊(cè)topic name獲取topic id,然后再次重新發(fā)布

          QoS 1和 QoS 2在任一時(shí)間,都必須等待已有PUBLISH消息完成,才能進(jìn)行下面的PUBLISH消息發(fā)布流程。

          預(yù)定義topic id和兩個(gè)字符的topic name

          預(yù)定義的topic id已提前指派好對(duì)應(yīng)的topic name,需要客戶端和網(wǎng)關(guān)在代碼層級(jí)支持,省略了中間注冊(cè)流程,在連接建立之后可以馬上進(jìn)行PUBLISH消息,但這需要在PUBLISH標(biāo)志Flags字段中設(shè)置TopicIdType值為0b01(0b10表示兩個(gè)字節(jié)長(zhǎng)度的短topic name)。雖然可以快速發(fā)送PUBLISH消息,但客戶端想訂閱預(yù)定義的topic id,接收對(duì)應(yīng)的PUBLISH消息,一樣需要發(fā)送SUBSCRIBLE消息請(qǐng)求進(jìn)行訂閱。若亂指定預(yù)定義topic id,會(huì)收到ReturnCode=“Rejection: invalid topic Id”的異常。

          預(yù)定義的短topic name只有兩個(gè)字符長(zhǎng)度的字符串(也是兩個(gè)字節(jié)),topic id為兩個(gè)字節(jié)表示的一個(gè)自然數(shù)(0-65535),兩者使用場(chǎng)景一致,都需要在標(biāo)志位Flags設(shè)置TopicIdType具體值,0b01表示預(yù)定義topic id,0b10表示兩個(gè)字節(jié)長(zhǎng)度的短topic name,需要分清。

          PUBLISH對(duì)應(yīng)QoS -1值

          這對(duì)僅僅支持PUBLISH QoS -1的非常簡(jiǎn)單的客戶端實(shí)現(xiàn)而言,除此之外不支持任何特性。它不關(guān)心連接是否建立,也沒有注冊(cè)、訂閱這一說,按照已經(jīng)固化到代碼中的網(wǎng)關(guān)地址直接發(fā)送PUBLISH消息,不關(guān)心網(wǎng)關(guān)地址是否正確、網(wǎng)關(guān)是否存活、消息是否發(fā)送成功。

          下面的PUBLISH屬性值依賴于QoS -1的情況:

          • QoS標(biāo)志,被置為0b11
          • TopicIdType標(biāo)志,可能是(預(yù)定義topic id)0b01也可能是(短topic name)0b10
          • TopicId字段,預(yù)定義topic id或短topic name
          • Data字段,需要發(fā)送的數(shù)據(jù),沒啥變化

          客戶端的訂閱和退訂

          客戶端對(duì)某個(gè)主題感興趣,可以發(fā)起SUBSCRIBLE流程,攜帶上感興趣的主題名(topic id),服務(wù)器一般會(huì)返回包含有指定主題Id(topic id)的SUBACK消息。訂閱失敗,可以從PUBACK的ReturnCode中獲知:

          • ReturnCode = “rejected: congestion”,客戶端需要稍等一段時(shí)間T_WAIT(>5分鐘)后再次重試

          有一種情況是SUBSCRIBLE訂閱主題包含通配符,網(wǎng)關(guān)的處理就很簡(jiǎn)單,在SUBACK中返回的topic id為0x0000。稍后,網(wǎng)關(guān)向客戶端發(fā)送REGISTER消息走注冊(cè)流程,通知通配符匹配到的主題對(duì)應(yīng)的topic id值。

          來自客戶端的SUBSCRIBLE消息一樣支持預(yù)定義topic id,以及短topic name,這和PUBLISH消息差不多。

          退訂就很簡(jiǎn)單,客戶端發(fā)送UNSUBSCRIBLE消息,網(wǎng)關(guān)返回UNSUBACK消息。

          但同一時(shí)刻,客戶端只允許處理訂閱SUBSCRIBLE或取消訂閱UNSUBSCRIBLE按照串行化順序,下一個(gè)操作依賴于上一個(gè)操作完全成功。

          網(wǎng)關(guān)發(fā)布流程

          服務(wù)器發(fā)布流程和客戶端類似,在發(fā)布之前需要檢測(cè)其主題是否已經(jīng)向客戶端提前注冊(cè)過,若無需要把主題和指定的topic id放入REGISTER消息中發(fā)送給客戶端進(jìn)行注冊(cè)流程,然后等待客戶端處理結(jié)果REGACK。注冊(cè)通過,然后才能正常發(fā)送PUBLISH消息。

          網(wǎng)關(guān)需要確保REGISTER的主題以及PUBLISH消息的內(nèi)容負(fù)載都不能太長(zhǎng)超過當(dāng)前網(wǎng)絡(luò)負(fù)載上限(比如在ZigBee環(huán)境下不能超過60個(gè)字節(jié)),取消注冊(cè)/發(fā)布流程就好了。

          網(wǎng)關(guān)發(fā)布PUBLISH消息時(shí),客戶端檢測(cè)到未知的topic id,把拒絕理由封裝到PUBACK后,網(wǎng)關(guān)遇到ReturnCode=“Rejected: invalid Topic ID”非法topic id,需要考慮刪除或重新注冊(cè)。

          客戶端或許會(huì)拒絕其注冊(cè),或許會(huì)不允許PUBLISH消息,網(wǎng)關(guān)如上靜默處理就好了,失敗就失敗了,不需要告知?jiǎng)e人。

          客戶端發(fā)布流程于此類似,需要在發(fā)布之前進(jìn)行主題注冊(cè)以獲取指定的topic id,提交PUBLISH消息后,同樣需要檢查PUBACK所包含的ReturnCode字段是接受還是拒絕,因網(wǎng)絡(luò)擁塞而產(chǎn)生的拒絕,客戶端需要在T_WAIT時(shí)間后再次重試。

          客戶端的發(fā)布必須是串行方式,下一個(gè)需要發(fā)送到PUBLISH消息需要等待上一個(gè)發(fā)送成功被網(wǎng)關(guān)接受之后才能進(jìn)行處理。

          心跳保活流程

          一般是客戶端->網(wǎng)關(guān),網(wǎng)關(guān)->客戶端也沒有問題。但要求PINGREQ -> PINGRESP 一定要單個(gè)時(shí)針循環(huán),PINGREQ發(fā)送者不能也是PINGRESP的發(fā)送者,那樣不但亂了流程,也浪費(fèi)了網(wǎng)絡(luò)資源。嗯,不允許雙向互發(fā)。

          客戶端可基于心跳機(jī)制監(jiān)測(cè)已連接網(wǎng)關(guān)健康與否,連續(xù)多次接收不到來自網(wǎng)關(guān)的PINGRESP消息后,客戶端連接下一個(gè)可替換的網(wǎng)關(guān)。因?yàn)榭蛻舳说倪B接和心跳和其它客戶端狀態(tài)屬性不同步,但這可能會(huì)帶來一個(gè)問題,同一時(shí)間若有大量的客戶端洪水般同時(shí)連接一個(gè)網(wǎng)關(guān),網(wǎng)關(guān)可能毫無征兆的會(huì)被沖垮掉。這就要求網(wǎng)關(guān)要有批量的連接處理能力,并發(fā)特性增強(qiáng)才行。

          客戶端斷線流程

          客戶端主動(dòng)發(fā)送DISCONNECT消息告知網(wǎng)關(guān)需要斷線之后,若有交換信息的需要可以重新發(fā)起一個(gè)新的會(huì)話連接。DISCONNECT消息之后,網(wǎng)關(guān)不會(huì)清理掉已有訂閱和遺囑數(shù)據(jù),除非在之前的CONNECT消息中已硬性設(shè)置了CleanSession會(huì)話清理標(biāo)識(shí)為true。網(wǎng)關(guān)接收到DISCONNECT消息之后會(huì)返回一個(gè)DISCONNECT消息作為響應(yīng)。

          有一種情況是客戶端會(huì)突然接收到來自網(wǎng)關(guān)的DISCONNECT消息,這也許是網(wǎng)關(guān)自身發(fā)生了異常錯(cuò)誤,或網(wǎng)關(guān)無法定位客戶端的消息歸屬(客戶端的消息和客戶端無法關(guān)聯(lián)到一起),此時(shí)客戶端需要發(fā)送CONNECT消息重建與網(wǎng)關(guān)的會(huì)話連接。

          客戶端重傳流程

          客戶端->網(wǎng)關(guān)的消息都是單路傳播的,這依賴于客戶端所持有的已連接網(wǎng)關(guān)的單播地址。

          客戶端發(fā)送一個(gè)消息之后,需要啟動(dòng)一個(gè)重試定時(shí)器Tretry和一個(gè)重試計(jì)數(shù)器Nretry用以監(jiān)督網(wǎng)關(guān)消息響應(yīng)。定時(shí)器會(huì)被客戶端在指定時(shí)間內(nèi)接收到來自網(wǎng)關(guān)的消息后取消掉,若沒有準(zhǔn)時(shí)接收到則會(huì)觸發(fā)定時(shí)器執(zhí)行消息重發(fā)流程,連續(xù)Nretry次重發(fā)后,客戶端會(huì)直接取消掉當(dāng)前流程,判斷當(dāng)前網(wǎng)關(guān)已經(jīng)斷線,需要連接到另外一個(gè)可用的網(wǎng)關(guān)。假如另外的網(wǎng)關(guān)也是連接失敗,會(huì)嘗試重連之前的網(wǎng)關(guān)。

          若在休眠狀態(tài)下,一旦超過重試計(jì)數(shù)器值,客戶端直接進(jìn)入休眠狀態(tài)。

          客戶端休眠支持策略

          這里所說的客戶端指的是依賴電池驅(qū)動(dòng)的電子設(shè)備,你要明白一個(gè)事實(shí),節(jié)省電池資源是多麼的重要,省電就是關(guān)鍵,沒電了就沒得玩了嘛。當(dāng)不處于激活狀態(tài)時(shí)為了省電就得需要進(jìn)入睡眠/休眠狀態(tài),當(dāng)有數(shù)據(jù)需要接收或發(fā)送時(shí)就可以醒過來。網(wǎng)關(guān)嘛需要追蹤設(shè)備的休眠狀態(tài)并且支持緩存需要發(fā)送給休眠設(shè)備的消息,在設(shè)備喚醒時(shí)一一發(fā)送。

          下面是客戶端的狀態(tài)轉(zhuǎn)換圖,很清晰描述了各種狀態(tài)之間的交互:

          客戶端具有五種狀態(tài):激活(active),休眠(asleep),喚醒(awake),斷線(disconnected),丟失(lost),每次只能是其中一種。

          網(wǎng)關(guān)需要監(jiān)督客戶端的狀態(tài),開始于CONNECT消息中存活時(shí)長(zhǎng)字段(keep alive),在大于存活時(shí)長(zhǎng)時(shí)間內(nèi)網(wǎng)關(guān)接收不到來自客戶端消息,網(wǎng)關(guān)認(rèn)為客戶端已經(jīng)處于丟失狀態(tài)(lost),會(huì)激活對(duì)應(yīng)的遺囑特性若存在的話。

          客戶端發(fā)送DISCONNECT消息但沒有duration休眠時(shí)長(zhǎng)字段,網(wǎng)關(guān)這將處于沒有時(shí)間監(jiān)督的斷線狀態(tài)。一旦包含duration休眠時(shí)長(zhǎng)字段,表示客戶端需要休眠一段時(shí)間,網(wǎng)關(guān)這客戶端被轉(zhuǎn)換為休眠狀態(tài),休眠時(shí)長(zhǎng)為duration所定義在值。超過此休眠時(shí)長(zhǎng)的一段時(shí)間內(nèi),網(wǎng)關(guān)若接收不到客戶端發(fā)送過來的任何消息,那么客戶端會(huì)被轉(zhuǎn)化為丟失狀態(tài),若已設(shè)置遺囑特性,此時(shí)遺囑特性會(huì)生效。客戶端休眠期間需要被發(fā)送的消息都會(huì)被網(wǎng)關(guān)緩存。

          睡眠狀態(tài)下流程圖會(huì)更形象的說明流程:

          毫無疑問,網(wǎng)關(guān)可使用一個(gè)休眠定時(shí)器維護(hù)客戶端的休眠狀態(tài)等,休眠定時(shí)器會(huì)被停掉當(dāng)網(wǎng)關(guān)接收到客戶端發(fā)送過的PINGREQ消息,網(wǎng)關(guān)從PINGREQ消息所包含的Client Id檢索是否存在已緩存的PUBLISH消息,若有會(huì)一一按照順序發(fā)送到客戶端。所有對(duì)應(yīng)已緩存消息發(fā)送完畢后,會(huì)隨之發(fā)送一個(gè)PINGRESP消息。若沒有緩存消息,網(wǎng)關(guān)直接返回一個(gè)PINGRESP消息。網(wǎng)關(guān)會(huì)重新啟動(dòng)休眠定時(shí)器,網(wǎng)關(guān)維護(hù)的客戶端狀態(tài)被轉(zhuǎn)換為休眠狀態(tài),客戶端在接收到PINGRESP消息之后,將直接轉(zhuǎn)向休眠狀態(tài),節(jié)省用電。

          客戶端在喚醒狀態(tài)下處理消息,遵守“客戶端重傳流程”行為,一旦達(dá)到重試計(jì)數(shù)器限制,將進(jìn)入睡眠狀態(tài)。

          客戶端從休眠狀態(tài)轉(zhuǎn)向喚醒狀態(tài)用于檢查網(wǎng)關(guān)是否為其緩存消息時(shí),需要發(fā)送一個(gè)PINGREQ消息到網(wǎng)關(guān);從休眠/喚醒狀態(tài)轉(zhuǎn)換為激活狀態(tài),需要發(fā)送一個(gè)CONNECT消息告知網(wǎng)關(guān);轉(zhuǎn)換為斷線狀態(tài)時(shí)需要發(fā)送兩個(gè)字節(jié)的DISCONNECT(沒有休眠時(shí)長(zhǎng)字段duration)消息;需要重新定義的休眠時(shí)長(zhǎng),發(fā)送一個(gè)DISCONNECT消息(包含新的duration時(shí)長(zhǎng)值)通知網(wǎng)關(guān)即可。

          小結(jié)

          功能性描述介紹完了,基本上MQTT-SN協(xié)議介紹已接近尾聲,最后面的篇章就是短短的實(shí)現(xiàn)描述了。

          posted on 2015-01-09 17:32 nieyong 閱讀(6982) 評(píng)論(1)  編輯  收藏 所屬分類: MQTT

          評(píng)論

          # re: MQTT-SN協(xié)議亂翻之功能描述 2015-03-05 14:49 皮脂分泌和細(xì)菌導(dǎo)致青春痘長(zhǎng)起

          好文章,要多關(guān)注  回復(fù)  更多評(píng)論   

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請(qǐng)標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2015年1月>
          28293031123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          統(tǒng)計(jì)

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個(gè)人收藏

          最新隨筆

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 田东县| 吴川市| 原平市| 行唐县| 博白县| 垦利县| 孝义市| 治县。| 广灵县| 夏邑县| 江口县| 乐平市| 旬邑县| 尼勒克县| 新平| 嘉黎县| 武清区| 台北县| 同心县| 互助| 榕江县| 千阳县| 井冈山市| 平阳县| 武邑县| 林芝县| 惠来县| 吴桥县| 泾源县| 尉氏县| 疏勒县| 建水县| 大石桥市| 沿河| 旌德县| 东平县| 微博| 南安市| 筠连县| 金溪县| 普安县|