最近的工做是給微信作一個消息類的後臺類的應用。python
消息類的後臺類的應用的意思就是,這個應用不須要界面,不須要美工,也不須要客戶端。它只是微信的一個普通帳號。你能夠加這個帳號爲好友。而後你能夠和這個帳號聊天獲取你想要的內容。這個帳號也會自動發消息給你。其實有點像聊天機器人。linux
我寫的這個後臺類的應用是爲泰國用戶寫的。會根據用戶發過來的日期發送這個用戶當天的運氣好壞。包括財運、黴運、桃花運和幸運數字這些。世界上真的有人信這些? 我謹慎的表示懷疑。數據庫
我是在linux平臺上用Python寫的。第一個須要解決的問題就是如何保持在後臺運行不退出。幸虧Python保持了很好的和C語言libc庫函數的兼容性,用幾行代碼能夠搞定。編程
import os if os.fork(): os.setsid() .... else: os.exit()
和libc的函數原型幾乎如出一轍。這段代碼的意思是先fork出一個子進程。而後在讓子進程脫離原進程組建立一個新的後臺進程組,從而與終端脫離,成爲後臺運行的不死進程。關於這方面的知識能夠看《UNIX環境高級編程》9.6控制終端。
我用了3個後臺進程來實現產品的需求。 首先用戶發送生日的日期,我須要返回該日期對應的星期幾的今日的運程。好比用戶發送1/11/1985, 這表明1985年11月1日。 我須要計算這一天是星期五,而後給他返回星期五這一天出生的人今天的運氣怎麼樣。運氣怎麼樣不是我說的,聽說是泰國合做方聘請了一個真正的算命的人天天去編輯的。因此我須要從一個url來拉取每一天,出生於一周的每一天的人的當天運氣狀況。因而第一個後臺進程的功能就是須要去定時去拉取這個url的最新內容,並存放在本地。比較糟糕的一點是,我不知道這個算命的人天天會在何時去更新。他多是頭一天晚上8點鐘更新,也多是當天的4點。這比較煩,我須要每隔一段時間去拉取。而後還須要從內容中分析這是哪一天的內容。這是第一個進程。api
解決了內容的來源問題以後我所要面臨的第二個問題是我從哪裏獲取用戶的消息。從微信那裏拿來了一份MessageAPI文檔。這份文檔如今我還不能公開由於沒有對外發布。微信能夠經過HTTP長鏈接不斷的向你PUSH用戶發送的消息過來,而你所須要作的就是拿到消息作處理。就跟用電飯煲作米飯那麼簡單。那麼這裏所須要解決的問題就只有一個,Python如何保持HTTP長鏈接,並能不斷的收取數據包?微信
嗯,我知道你會想到的urllib2。 這也是個人第一反應。不過惋惜的是urllib2並不提供保持長鏈接的辦法。直接用recv、read這些系統調用監聽fd? 我知道你是一個不怕麻煩不懼艱險的人。可我並不像你。通過一番google和stackoverflow的查詢以後我獲得了一個好東西——urlgrabber。不過在這篇文章裏我不打算捨本逐末的去介紹urlgrabber的使用細節。並且我也沒有詳細的研究過它。不過通過個人測試,urlgrabber確實能很好的處理長鏈接HTTP的消息接收。因此我強烈的推薦這種方式而不是去用更底層的TCP鏈接API。函數
使用方法也很簡單:測試
import urllib2 from urlgrabber.keepalive import HTTPHandler keepalive_handler = HTTPHandler() opener = urllib2.build_opener(keepalive_handler) urllib2.install_opener(opener) f = urllib2.urlopen('http://www.python.org')
而後你就能像讀一個文件同樣從HTTP鏈接中源源不斷的讀出數據來了。不過值得注意的一點是,這個文件打開的是阻塞式的IO。阻塞式IO在python中的處理和libc中不太同樣。假如一個鏈接沒有關閉且是阻塞式的,在python中你沒法一次讀到當前已收到全部數據。解決的方法有: 1 改爲非阻塞。 2 每次讀一個字節,直到讀到一個完整數據包的結束。
很遺憾的告訴你們,在時間不充裕的狀況下,方法1我沒能成功。而keepalive的HTTP發送來的數據,每一段數據都是有規律的。好比標準的HTTP trunked的數據的開始老是會告訴你這一次會發送多少個字節,而後你讀相應的字節數就能夠了。而微信的message API在每個數據包的最後都會出現\r\n。憑這個規律,咱們足以判斷出是否收完一個數據包了。網站
大概的代碼以下,僅用來講明個人思路:ui
while True: sPkg += f.read(1) if sPkg.endswith('\r\n'): #package over sPkg = ''
嗯,這是第二個進程。收取微信的消息。
而後剩下的工做就是須要把消息發給微信用戶了。固然你不能保證每次發送的消息都是成功的。所以我利用數據庫作了一個消息隊列。實現起來很是簡單,就是每次從數據庫中獲取10條待發的消息發送。發送成功的消息在數據庫中標記發送成功,以保證不會重複發送。發送不成功消息,在數據庫中將發送次數增長1,這樣這條消息會在下一次出隊列時繼續發送,直到發送的次數達到一個閾值。這是第三個進程。
不過如今微信的open message api尚未對外公開發布,很差更多的透露更多技術細節了。有興趣的能夠和我聯繫。個人郵箱是xxb.sklse@gmail.com。 在此處留言也能夠。只是以爲有了這個API你們能夠作出一些更多有意思的東西,好比電子商務網站能夠經過這個來作到免費的訂單到達的提醒。 甚至餐飲店能夠利用微信免費點餐。呵呵。這個微信API遲早會發布,算我作了一點廣告吧。