發表文章

目前顯示的是 2018的文章

[Program Note] MQTT QoS(Quality of Service)說明

圖片
MQTT的全名為Message Queuing Telemetry Transport,為IBM和Eurotech共同製定的通訊協定,MQTT是為物聯網所設計的M2M通訊協定,網路頻寬與硬體需求非常少,是極為輕便的通訊協定。MQTT通訊協定是基於TCP/IP連線,並提供自有的不同QoS(Quality of Service)層級的訊息傳遞,適用於網路連線不佳的環境、CPU較弱的嵌入式裝置。 MQTT的封包分為三個部分,分別為Fix Header, Variable Header, Payload,在PUBLISH與SUBSCRIBE封包中,QoS會在Fix Header中定義;對於MQTT封包的詳細內容可以參考MQTT官方文件第二章:MQTT Control Packet format。 QoS定義訊息傳送的品質,確保發布的訊息有被確實接收,MQTT定義的QoS分為0、1、2三個等級,在程式撰寫時會在Publisher發送訊息與Subscriber發起訂閱時指定各自的QoS等級: 0:At most once 訊息最多傳送一次,不會確認訊息傳送的結果,不會儲存訊息;如果Subscriber已中斷連線,或如果Broker故障,則該訊息就會會遺失。 在下圖中,Publisher並不能確認Broker是否有收到訊息,同樣的Broker也不能確定Subscriber是否有收到訊息。 1:At least once 一律會傳送訊息至少一次,如果傳送端未接收到確認通知,則會再次傳送訊息並設定DUP(duplicate)旗標,直到接收到確認通知為止。 如下圖,Publisher會在封包Header中加入packet identifier識別碼,訊息發送給Broker之後,Broker會回傳PUBACK(publish acknowledgment) 封包給Publisher,其中也有相同的packet identifier識別碼,讓Publisher確認訊息已經確實送達;同樣的方式也作用在Broker與Subscriber之間。 接收端在處理訊息之後,會從接收端中刪除訊息。如果接收端是Broker,則會將訊息發佈至其Subscriber。如果接收端是Subscriber,則會將訊息遞送至其應用程式。刪除訊息之後,接收端會傳送確認通知至傳送端。 ...

[Program Note] Asynchronous Programing與Callback Function

圖片
Asynchronous Programing 一開始要先清楚何謂同步與非同步,同步比較簡單,就像是我們去銀行辦事情,你填好單子交給行員,之後你必須在行員的櫃台一直等他完成作業,無論是開戶、領款、或者存款,這樣就是同步作業;你的程式送出request之後必須一直等待到response,才可以做其他事情。 而非同步作業時常與多執行緒作業畫上等號,實際上是不同的,多執行緒就像是有六十個人要在銀行開戶,所以銀行開了10個櫃台來處理這60個作業,但是每個櫃台實際上還是執行著上面說的同步作業。 而非同步作業是你今天要開戶,填好單子給行員之後,你可以去隔壁買飲料,點完飲料你可以去隔壁買衣服,店員幫你包裝衣服的時候你可以去7-11繳個電話費,然後飲料店叫到你的號碼了你回去拿飲料,服飾店員說你的衣服包好了你回去拿衣服,最後回到銀行剛好叫到你的號碼再去櫃檯拿你的存摺;對於程式而言, 你的程式送出request之後,到收到response之間,程式可以去做其他事情。 當瞭解同步與非同步作業之後,會延伸一個問題,你要對誰送出的request跟誰會送給你response?對於這個程式角色他必須有一個特性,它必須一直都存在,當你送出一個request之後,它會接收、處理,然後回覆給你一個response,當你再次送出一個request的時候,它也會重複同樣的程序,就像一個等待你的request的迴圈一樣;這樣的設計模式(Design Pattern)有個名字叫反應堆模式(Reactor Pattern),或者叫事件迴圈(Event Loop)、 Select迴圈(Select Loop) 。 下面這張圖就說明了反應堆迴圈的執行方式-等待事件、處理事件的無限迴圈;這個反應堆在程式執行期間會一直存在著,你給他一個request,就是一個event,它會處理完,給你response,然後繼續安靜的等待下一個request。 Callback Function 接著說明一下callback function,在一般的程式中,你寫了一個function,然後你在程式碼中呼叫這個function,我們可以稱為「call」一個function;如果你寫了一個function,然後把這個function的指給了某一個套件、框架、或者其他的程式,這個function在合適的時間,會由這些套...

[Twisted] Part 22: The End

圖片
本文由Dave的 Part 22: The End 翻譯而成,你可以由 Part 1 開始閱讀這個系列的文章,也可以在 這裡 找到整個系列的目錄。 All Done 呼!感謝你支持我。當我開始這個系列時,我沒有想過這會這麼長,或者花費這麼多時間來製作。但我很享受創造這個系列的過程,也希望你享受閱讀它的過程。 現在我已經完成了,我會研究生成PDF格式的可能性。但是不保證。 最後,我想就如何繼續你的Twisted學習提出一些建議。 Further Reading 首先,我建議閱讀Twsited的 線上文件 。雖然它受到很多中傷,但我認為這比經常受到讚賞好。 如果你想使用Twisted進行網路程式設計,那麼Jean-Paul Calderone有一個備受推崇的系列,叫做「 Twisted Web in 60 Seconds 」。不過,我懷疑它會花比60秒更長的時間去閱讀。 還有一本 Twisted的書 ,由於我沒有讀過所以我不能談論太多。 但我認為比上面更重要的是閱讀Twisted的原始碼。由於那些程式碼是由非常了解Twisted的人撰寫的,它是如何以「Twisted方式」做事情的優秀的範例來源。 Suggested Exercises 將你寫過的一個同步程式轉變為使用Twsited。 從頭開始轉寫一個新的Twisted程式。 從Twisted bug資料庫 選擇一個bug然後修復它。向Twisted開發人員提交更新。不要忘記閱讀關於投稿的 程序 。 The End, Really 祝你研究愉快! 圖47.結束

[Twisted] Part 21: Lazy is as Lazy Doesn’t: Twisted and Haskell

圖片
本文由Dave的 Part 21: Lazy is as Lazy Doesn’t: Twisted and Haskell 翻譯而成,你可以由 Part 1 開始閱讀這個系列的文章,也可以在 這裡 找到整個系列的目錄。 Introduction 上個章節中,我們比較了Twisted與 Erlang ,並將注意力集中在它們共同的一些想法上。最後我們也了解使用Erlang非常簡單,因為非同步I/O與回應式程式設計是Erlang runtime與程序模型的關鍵元件。 今天我們將來到離我們的主題更遠的地方來看看 Haskell ,另一種與Erlang(當然,還有Python)完全不同的函式型(functional)語言。這次將不會有太多相似之處,但我們仍然會發現一些非同步I/O隱藏在其中。 Functional with a Capital F 雖然Erlang也是一種函式型語言,它主要關注是可靠的並行性(concurrency)模型。另一方面,Haskell是徹徹底底的函式型,毫不掩飾的使用像 functors 與 monads 這些範疇論( category theory )的概念 不要擔心,我們不會深入範疇論的東西(說得好像我們可以一樣)。相反的,我們將專注於一個Haskell更傳統的函式型功能:懶惰。如同許多函式型語言(但不像Erlang),Haskell支援 惰性求值(lazy evaluation) 。 在惰性求值語言中,程式的內容並沒有很直接地描述如何計算需要計算的東西。實際執行計算的細節通常留給編譯器與runtime系統。 並且,更重要的是當惰性求值的計算進入runtime時,可能只部分(懶惰的)而不是一次性的計算運算式。 通常runtime將只計算讓目前的運算可以有進展所需要的運算式。 這是一個應用haed得簡單的Haskell statement,對於串列[1, 2, 3],這個函式會取回串列中的第一個元素(Haskell與Python共用一些列表語法): head [1,2,3] 如果你安裝的 GHC 這個Haskell runtime,你可以自己嘗試看看: [~] ghci GHCi, version 6.12.1: http://www.haskell.org/ghc/ : ? for help Loading p...

[Twisted] Part 20: Wheels within Wheels: Twisted and Erlang

圖片
本文由Dave的 Part 20: Wheels within Wheels: Twisted and Erlang 翻譯而成,你可以由 Part 1 開始閱讀這個系列的文章,也可以在 這裡 找到整個系列的目錄。 Introduction 在這個系列中我們發現一件事情,將同步的「普通Python」程式碼與非同步的Twisted程式碼混用並不是一項簡單的任務,因為在Twisted程式中阻塞一段不確定的時間將使你喪失嘗試使用非同步模型的許多好處。 如果這是你的第一的非同步程式設計的介紹,那麼你得到的知識似乎有些應用的侷限。你可以在Twisted中使用這些新技術,但是不能在一般Python程式碼的更廣闊的世界中使用。當使用Twisted時,你通常受限於特別寫來作為Twisted程式的一部分使用的函式庫,至少如果你想直接的從執行reactor的執行緒中呼叫它們的話。 但是非同步程式設計的技術已經存在很長的時間,而且絲毫不侷限於Twisted。事實上,光Python中就有數量驚人的非同步程式設計框架。稍微 搜尋一下 可能就有幾十個結果。 它們的細節與Twisted不同,但是基本的想法(非同步I/O、以多個資料串流的小區塊來處理資料)是相同的。 所以如果你需要或選擇去使用其他的框架,你會因為已經學習了Twisted而有很好的啟蒙。 而在Python之外,有許多其他的語言與系統,基於或使用了非同步程式設計的模型。當你在探索這個主題其他更廣泛的領域時,你Twisted的知識將會技術的幫助你。 在這個章節我們會瀏覽一下 Erlang ,它是一種程式語言與runtime system,它廣泛的使用非同步程式設計的概念,但以它獨特的方式實現。請注意這不是對Erlang的概論。相反的,這是對嵌入在Erlang中的一些概念的簡短探索,以及它們如何與Twisted中的概念產生連接。基本的主題是你在學習Twisted中得到的知識可以被應用在學習其他技術時。 Callbacks Reimagined 研究一下 圖6 ,callback的圖形表示。在 Part 6 中介紹的 3.0版本用戶端 與之後所有的詩歌用戶端,主要的callback都是 dataReceived 方法。每次我們從其中一台我們已經連接的詩歌伺服器取得一部分詩歌時,這個callback就會被調用。 假設...

[Twisted] Part 19: I Thought I Wanted It But I Changed My Mind

圖片
本文由Dave的 Part 19: I Thought I Wanted It But I Changed My Mind 翻譯而成,你可以由 Part 1 開始閱讀這個系列的文章,也可以在 這裡 找到整個系列的目錄。 Introduction Twisted是一個進行中的專案,Twisted的開發人員會定期的加入新的功能並擴展舊的功能。隨著Twisted 10.1.0的發布,開發人員為Deferred類別加入了一個新的能力-取消(cancellation),我們今天會來探討這個能力。 非同步程式設計將請求從回應中脫離,因而提升了一種新的可能性:在請求結果與取回結果之間,你可能決定你不再需要它了。想一想 Part 14 的詩歌代理伺服器。以下是代理伺服器的運作方式,至少第一次詩歌請求是這樣子: 來了一個詩歌的請求。 代理伺服器聯絡真的伺服器來取得詩歌。 一但詩歌下載完成,將它傳送給原來的用戶端。 這樣看起來都很好,但是如果用戶端在收到詩歌前中止了怎麼辦?也許它們一開始請求 Paradise Lost 的完整文本,後來決定它們真的想要的是 Kojo 的俳句。現在我們的代理伺服器正卡在下載前者,而慢速伺服器還需要一點時間。我們最好關閉這個連接,並且讓慢速伺服器回去睡覺。 回憶一下 圖15 ,那張顯示同步程式控制的概念流程的圖。在那張圖中我們看到函式呼叫是由上而下,而例外是由下而上返回。如果我們想要取消同步函式的呼叫(而這只是假設),流程控制會與函式呼叫的方向相同,像圖38從高層程式碼到底層程式碼: 圖38.有假設性取消的同步程式流程 當然,在同步程式中這是不可能的,因為直到底層程式碼操作完成前,高層程式碼根本不會恢復執行,在這個時間根本沒有東西可以取消。 但是在非同步程式中,高層程式碼在底層程式碼完成前得到控制權,這至少提升了在底層請求完成之前取消它的可能性。 在Twisted程式中,底層請求是由Deferred物件來具體化的,你可以想像它是未完成的非同步操作的「handle」。在deferred實例中訊息的一般流程是向下的,從底層程式碼到高層程式碼,這與同步程式中的回傳訊息流程一致。從Twisted 10.1.0開始,高層程式碼可以向反方向傳送訊息-這樣可以告訴底層程式碼它不在需要底層程式碼的結果了。看看圖39: 圖39.在def...

[Twisted] Part 18: Deferreds En Masse

圖片
本文由Dave的 Part 18: Deferreds En Masse 翻譯而成,你可以由 Part 1 開始閱讀這個系列的文章,也可以在 這裡 找到整個系列的目錄。 Introduction 在上個章節,我們學習了使用生成器建構連續的非同步callbacks的新方法。因此,包括了deferreds,我們現在有兩種技術將非同步操作鏈接在一起。 然而,有時候我們希望以「並行(parallel)」的方式執行一組(group)非同步操作。由於Twisted是單執行緒的,它們不會真正的同時執行,但重點在我們希望使用非同步I/O,盡快的處理一組任務(tasks)。例如,我們的詩歌用戶端可以同時從多個伺服器下載詩歌,而不是一個伺服器接著另外一個。畢竟,這就是使用Twisted取得詩歌的重點。 因此,我們所有的詩歌用戶端必須解決這個問題:你怎麼知道你啟動的所有非同步操作完成了?到目前為止,我們已經藉由收集我們的結果到一個串列中(像7.0版本用戶端的 results 串列),並且檢查列表的長度來解決這個問題。我們除了必須小心的收集成功結果之外,還要收集失敗結果,否則一個失敗結果會導致城市認為還有工作要做而永遠執行。 如你所料,Twisted包含了一個抽象讓你可以用來解決這個問題,而我們今天要來看一下。 The DeferredList DeferredList類別讓我們可以將一個deferred物件串列作為一個deferred實例來處理。 這樣我們可以啟動一堆非同步操作,並且只在它們都完成時才得到通知(無論它們成功或失敗)。讓我們看看一些範例。 在 deferred-list/deferred-list-1.py 你可以找到這段程式碼: from twisted.internet import defer def got_results(res): print 'We got:', res print 'Empty List.' d = defer.DeferredList([]) print 'Adding Callback.' d.addCallback(got_results) 如果你執行它,你會得到這樣的輸出: Empty List. Adding Callback. We got:...

[Twisted] Part 17: Just Another Way to Spell “Callback”

圖片
本文由Dave的 Part 17: Just Another Way to Spell “Callback” 翻譯而成,你可以由 Part 1 開始閱讀這個系列的文章,也可以在 這裡 找到整個系列的目錄。 Introduction 在這個章節中我們將回到callback這個主題。我們將介紹另一種在Twisted中撰寫callback的技術,那就是使用 生成器(generator) 。我們會展示這種技術如何運作,並把它與使用「純」Deferreds的技術進行對比。最後,我們將使用這種技術重寫我們的詩歌用戶端。但首先讓我們回顧一下生成器是如何運作的,以便我們可以了解為什麼它是建立callback的候選方法。 A BRIEF REVIEW OF GENERATORS 你可能知道,Python生成器是一種「可重新啟動的函式」,你可以藉由在你的函式主體中使用yield表達式來建立。透過這種做法,該函示成為一個「生成器函式」,它會回傳一個你可以用來以一系列的步驟來執行這個函式的 迭代器(iterator) 。 迭代器的每個循環都會重新啟動這個函式,這個函式會繼續執行直到它到達下一個yield。 (譯註:如果這個生成器函式有多個yeild,第一個迴圈會執行到第一個yield,第二次迴圈會從第一個yield之後開始執行到第二個yield,並以此類推,所以前面才會說這是「一系列的步驟」,因為它是一段一段在執行的) 生成器(和迭代器)通常用來表示以惰性建立(lazily-created)的數值序列(譯註:關於惰性可以參考一下維基的 Lazy evaluation )。看一下 inline-callbacks/gen-1.py 中的範例: def my_generator(): print 'starting up' yield 1 print "workin'" yield 2 print "still workin'" yield 3 print 'done' for n in my_generator(): print n 這裡我們有一個建立了序列1、2、3的生成器。如果你執行程式碼,當迴圈的循環遍歷生成器時,你會...

[Twisted] Part 16: Twisted Daemonologie

圖片
本文由Dave的 Part 16: Twisted Daemonologie 翻譯而成,你可以由 Part 1 開始閱讀這個系列的文章,也可以在 這裡 找到整個系列的目錄。 Introduction 到目前為止我們已經寫過的伺服器只能在終端視窗執行,並透過print statement輸出到螢幕。這是用於開發階段,但作為一個產品來布署服務還遠遠不足。一個作為良好產品的伺服器應該: 作為 daemon 程序執行,與任何終端或使用者session無關。你不會希望服務只是因為管理者登出就被關閉。 將除錯與錯誤訊息傳送到一組輪替(rotate)的log檔,或者 syslog 服務。 放棄過高的權限,例如在執行前切換到低權限的使用者。 在檔案中記錄它的 pid ,以便管理者向daemon 發送信號 。 我們可以使用Twisted提供的twistd script來取得這些功能。但首先我們需要稍微修改我們的程式碼。 The Concepts 要理解twistd script需要學習一些Twisted的新概念,其中最重要的是Service。跟往常一樣,一些新的概念也伴隨著一些新的Interface。 ISERVICE IService 介面定義一個由我們命名的服務,並且可以啟動或停止它。 這個服務要做什麼?任何你喜歡的事情-而不是定義服務的特定函式,這個介面只需要它提供的一些通用的屬性與方法。 有兩個必要的屬性:name和running。Name屬性只是一個字串,像「fastpoetry」,如果你不想為你的服務命名就用None。Running屬性是一個布林值,如果服務已經被成功啟動則為true。 我們只簡單的談談一些IService的方法。我們將跳過一些一看就懂的方法,以及在一簡單Twisted程式中不常使用的進階方法。IService中兩個基本方法為startService與stopService: def startService(): """ Start the service. """ def stopService(): """ Stop the se...