打開你寫python代碼用的編輯器,不要問為什么,把下面的代碼一個字不差地錄入進去,并命名保存為hello.py(目錄自己任意定)。
~~~
#!/usr/bin/env python
#coding:utf-8
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)
class IndexHandler(tornado.web.RequestHandler):
def get(self):
greeting = self.get_argument('greeting', 'Hello')
self.write(greeting + ', welcome you to read: www.itdiffer.com')
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
~~~
進入到保存hello.py文件的目錄,執行:
~~~
$ python hello.py
~~~
用python運行這個文件,其實就已經發布了一個網站,只不過這個網站太簡單了。
接下來,打開瀏覽器,在瀏覽器中輸入:http://localhost:8000,得到如下界面:
[](https://github.com/qiwsir/StarterLearningPython/blob/master/3images/30201.png)
我在ubuntu的shell中還可以用下面方式運行:
~~~
$ curl http://localhost:8000/
Hello, welcome you to read: www.itdiffer.com
$ curl http://localhost:8000/?greeting=Qiwsir
Qiwsir, welcome you to read: www.itdiffer.com
~~~
此操作,讀者可以根據自己系統而定。
恭喜你,邁出了決定性一步,已經可以用Tornado發布網站了。在這里似乎沒有做什么部署,只是安裝了Tornado。是的,不需要多做什么,因為Tornado就是一個很好的server,也是一個開發框架。
下面以這個非常簡單的網站為例,對用tornado做的網站的基本結構進行解釋。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/302.md#web服務器工作流程)WEB服務器工作流程
任何一個網站都離不開Web服務器,這里所說的不是指那個更計算機一樣的硬件設備,是指里面安裝的軟件,有時候初次接觸的看官容易搞混。就來偉大的[維基百科都這么說](http://zh.wikipedia.org/wiki/%E6%9C%8D%E5%8A%A1%E5%99%A8):
> 有時,這兩種定義會引起混淆,如Web服務器。它可能是指用于網站的計算機,也可能是指像Apache這樣的軟件,運行在這樣的計算機上以管理網頁組件和回應網頁瀏覽器的請求。
在具體的語境中,看官要注意分析,到底指的是什么。
關于Web服務器比較好的解釋,推薦看看百度百科的內容,我這里就不復制粘貼了,具體可以點擊連接查閱:[WEB服務器](http://baike.baidu.com/view/460250.htm)
在WEB上,用的最多的就是輸入網址,訪問某個網站。全世界那么多網站網頁,如果去訪問,怎么能夠做到彼此互通互聯呢。為了協調彼此,就制定了很多通用的協議,其中http協議,就是網絡協議中的一種。關于這個協議的介紹,網上隨處就能找到,請自己google.
網上偷來的[一張圖](http://kenby.iteye.com/blog/1159621)(從哪里偷來的,我都告訴你了,多實在呀。哈哈。),顯示在下面,簡要說明web服務器的工作過程
[](https://github.com/qiwsir/StarterLearningPython/blob/master/3images/30202.png)
偷個徹底,把原文中的說明也貼上:
1. 創建listen socket, 在指定的監聽端口, 等待客戶端請求的到來
2. listen socket接受客戶端的請求, 得到client socket, 接下來通過client socket與客戶端通信
3. 處理客戶端的請求, 首先從client socket讀取http請求的協議頭, 如果是post協議, 還可能要讀取客戶端上傳的數據, 然后處理請求, 準備好客戶端需要的數據, 通過client socket寫給客戶端
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/302.md#引入模塊)引入模塊
~~~
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
~~~
這四個都是Tornado的模塊,在本例中都是必須的。它們四個在一般的網站開發中,都要用到,基本作用分別是:
* tornado.httpserver:這個模塊就是用來解決web服務器的http協議問題,它提供了不少屬性方法,實現客戶端和服務器端的互通。Tornado的非阻塞、單線程的特點在這個模塊中體現。
* tornado.ioloop:這個也非常重要,能夠實現非阻塞socket循環,不能互通一次就結束呀。
* tornado.options:這是命令行解析模塊,也常用到。
* tornado.web:這是必不可少的模塊,它提供了一個簡單的Web框架與異步功能,從而使其擴展到大量打開的連接,使其成為理想的長輪詢。
讀者看到這里可能有點莫名其妙,對一些屬于不理解。沒關系,你可以先不用管它,如果愿意管,就把不理解屬于放到google立面查查看。一定要硬著頭皮一字一句地讀下去,隨著學習和實踐的深入,現在不理解的以后就會逐漸領悟理解的。
還有一個模塊引入,是用from...import完成的
~~~
from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)
~~~
這兩句就顯示了所謂“命令行解析模塊”的用途了。在這里通過`tornado.options.define()`定義了訪問本服務器的端口,就是當在瀏覽器地址欄中輸入`http:localhost:8000`的時候,才能訪問本網站,因為http協議默認的端口是80,為了區分,我在這里設置為8000,為什么要區分呢?因為我的計算機或許你的也是,已經部署了別(或許是Nginx、Apache)服務器了,它的端口是80,所以要區分開(也可能是故意不用80端口),并且,后面我們還會將tornado和Nginx聯合起來工作,這樣兩個服務器在同一臺計算機上,就要分開嘍。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/302.md#定義請求-處理程序類)定義請求-處理程序類
~~~
class IndexHandler(tornado.web.RequestHandler):
def get(self):
greeting = self.get_argument('greeting', 'Hello')
self.write(greeting + ', welcome you to read: www.itdiffer.com')
~~~
所謂“請求處理”程序類,就是要定義一個類,專門應付客戶端(就是你打開的那個瀏覽器界面)向服務器提出的請求(這個請求也許是要讀取某個網頁,也許是要將某些信息存到服務器上),服務器要有相應的程序來接收并處理這個請求,并且反饋某些信息(或者是針對請求反饋所要的信息,或者返回其它的錯誤信息等)。
于是,就定義了一個類,名字是IndexHandler,當然,名字可以隨便取了,但是,按照習慣,類的名字中的單詞首字母都是大寫的,并且如果這個類是請求處理程序類,那么就最好用Handler結尾,這樣在名稱上很明確,是干什么的。
類IndexHandler繼承`tornado.web.RequestHandler`,其中再定義`get()`和`post()`兩個在web中應用最多的方法的內容(關于這兩個方法的詳細解釋,可以參考:[HTTP GET POST的本質區別詳解](https://github.com/qiwsir/ITArticles/blob/master/Tornado/DifferenceHttpGetPost.md),作者在這篇文章中,闡述了兩個方法的本質)。
在本例中,只定義了一個`get()`方法。
用`greeting = self.get_argument('greeting', 'Hello')`的方式可以得到url中傳遞的參數,比如
~~~
$ curl http://localhost:8000/?greeting=Qiwsir
Qiwsir, welcome you to read: www.itdiffer.com
~~~
就得到了在url中為greeting設定的值Qiwsir。如果url中沒有提供值,就是Hello.
官方文檔對這個方法的描述如下:
> RequestHandler.get_argument(name, default=, []strip=True)
>
> Returns the value of the argument with the given name.
>
> If default is not provided, the argument is considered to be required, and we raise a MissingArgumentError if it is missing.
>
> If the argument appears in the url more than once, we return the last value.
>
> The returned value is always unicode.
接下來的那句`self.write(greeting + ',weblcome you to read: www.itdiffer.com)'`中,`write()`方法主要功能是向客戶端反饋信息。也瀏覽一下官方文檔信息,對以后正確理解使用有幫助:
> RequestHandler.write(chunk)[source]
>
> Writes the given chunk to the output buffer.
>
> To write the output to the network, use the flush() method below.
>
> If the given chunk is a dictionary, we write it as JSON and set the Content-Type of the response to be application/json. (if you want to send JSON as a different Content-Type, call set_header after calling write()).
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/302.md#main方法)main()方法
`if __name__ == "__main__"`,這個方法跟以往執行python程序是一樣的。
`tornado.options.parse_command_line()`,這是在執行tornado的解析命令行。在tornado的程序中,只要import模塊之后,就會在運行的時候自動加載,不需要了解細節,但是,在main()方法中如果有命令行解析,必須要提前將模塊引入。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/302.md#application類)Application類
下面這句是重點:
~~~
app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
~~~
將tornado.web.Application類實例化。這個實例化,本質上是建立了整個網站程序的請求處理集合,然后它可以被HTTPServer做為參數調用,實現http協議服務器訪問。Application類的`__init__`方法參數形式:
~~~
def __init__(self, handlers=None, default_host="", transforms=None,**settings):
pass
~~~
在一般情況下,handlers是不能為空的,因為Application類通過這個參數的值處理所得到的請求。例如在本例中,`handlers=[(r"/", IndexHandler)]`,就意味著如果通過瀏覽器的地址欄輸入根路徑(`http://localhost:8000`就是根路徑,如果是`http://localhost:8000/qiwsir`,就不屬于根,而是一個子路徑或目錄了),對應著就是讓名字為IndexHandler類處理這個請求。
通過handlers傳入的數值格式,一定要注意,在后面做復雜結構的網站是,這里就顯得重要了。它是一個list,list里面的元素是tuple,tuple的組成包括兩部分,一部分是請求路徑,另外一部分是處理程序的類名稱。注意請求路徑可以用正則表達式書寫(關于正則表達式,后面會進行簡要介紹)。舉例說明:
~~~
handlers = [
(r"/", IndexHandlers), #來自根路徑的請求用IndesHandlers處理
(r"/qiwsir/(.*)", QiwsirHandlers), #來自/qiwsir/以及其下任何請求(正則表達式表示任何字符)都由QiwsirHandlers處理
]
~~~
**注意**
在這里我使用了`r"/"`的樣式,意味著就不需要使用轉義符,r后面的都表示該符號本來的含義。例如,\n,如果單純這么來使用,就以為著換行,因為符號“\”具有轉義功能(關于轉義詳細閱讀[《字符串(1)》](https://github.com/qiwsir/StarterLearningPython/blob/master/106.md)),當寫成`r"\n"`的形式是,就不再表示換行了,而是兩個字符,\和n,不會轉意。一般情況下,由于正則表達式和 \ 會有沖突,因此,當一個字符串使用了正則表達式后,最好在前面加上'r'。
關于Application類的介紹,告一段落,但是并未完全講述了,因為還有別的參數設置沒有講,請繼續關注后續內容。
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/302.md#httpserver類)HTTPServer類
實例化之后,Application對象(用app做為標簽的)就可以被另外一個類HTTPServer引用,形式為:
~~~
http_server = tornado.httpserver.HTTPServer(app)
~~~
HTTPServer是tornado.httpserver里面定義的類。HTTPServer是一個單線程非阻塞HTTP服務器,執行HTTPServer一般要回調Application對象,并提供發送響應的接口,也就是下面的內容是跟隨上面語句的(options.port的值在IndexHandler類前面通過from...import..設置的)。
~~~
http_server.listen(options.port)
~~~
這種方法,就建立了單進程的http服務。
請看官牢記,如果在以后編碼中,遇到需要多進程,請參考官方文檔說明:[http://tornado.readthedocs.org/en/latest/httpserver.html#http-server](http://tornado.readthedocs.org/en/latest/httpserver.html#http-server)
## [](https://github.com/qiwsir/StarterLearningPython/blob/master/302.md#ioloop類)IOLoop類
剩下最后一句了:
~~~
tornado.ioloop.IOLoop.instance().start()
~~~
這句話,總是在`__main()__`的最后一句。表示可以接收來自HTTP的請求了。
以上把一個簡單的hello.py剖析。想必讀者對Tornado編寫網站的基本概念已經有了。
如果一頭霧水,也不要著急,以來將上面的內容多看幾遍。對整體結構有一個基本了解,不要拘泥于細節或者某些詞匯含義。然后即繼續學習。
- 第零章 預備
- 關于Python的故事
- 從小工到專家
- Python安裝
- 集成開發環境
- 第壹章 基本數據類型
- 數和四則運算
- 除法
- 常用數學函數和運算優先級
- 寫一個簡單的程序
- 字符串(1)
- 字符串(2)
- 字符串(3)
- 字符串(4)
- 字符編碼
- 列表(1)
- 列表(2)
- 列表(3)
- 回顧list和str
- 元組
- 字典(1)
- 字典(2)
- 集合(1)
- 集合(2)
- 第貳章 語句和文件
- 運算符
- 語句(1)
- 語句(2)
- 語句(3)
- 語句(4)
- 語句(5)
- 文件(1)
- 文件(2)
- 迭代
- 練習
- 自省
- 第叁章 函數
- 函數(1)
- 函數(2)
- 函數(3)
- 函數(4)
- 函數練習
- 第肆章 類
- 類(1)
- 類(2)
- 類(3)
- 類(4)
- 類(5)
- 多態和封裝
- 特殊方法(1)
- 特殊方法(2)
- 迭代器
- 生成器
- 上下文管理器
- 第伍章 錯誤和異常
- 錯誤和異常(1)
- 錯誤和異常(2)
- 錯誤和異常(3)
- 第陸章 模塊
- 編寫模塊
- 標準庫(1)
- 標準庫(2)
- 標準庫(3)
- 標準庫(4)
- 標準庫(5)
- 標準庫(6)
- 標準庫(7)
- 標準庫(8)
- 第三方庫
- 第柒章 保存數據
- 將數據存入文件
- mysql數據庫(1)
- MySQL數據庫(2)
- mongodb數據庫(1)
- SQLite數據庫
- 電子表格
- 第捌章 用Tornado做網站
- 為做網站而準備
- 分析Hello
- 用tornado做網站(1)
- 用tornado做網站(2)
- 用tornado做網站(3)
- 用tornado做網站(4)
- 用tornado做網站(5)
- 用tornado做網站(6)
- 用tornado做網站(7)
- 第玖章 科學計算
- 為計算做準備
- Pandas使用(1)
- Pandas使用(2)
- 處理股票數據
- 附:網絡文摘
- 如何成為Python高手
- ASCII、Unicode、GBK和UTF-8字符編碼的區別聯系