鍍金池/ 教程/ Python/ 分析 Hello
標準庫 (4)
如何成為 Python 高手
標準庫 (6)
標準庫 (3)
類(2)
Pandas 使用 (2)
xml
用 tornado 做網(wǎng)站 (5)
文件(1)
練習
列表(3)
從小工到專家
除法
錯誤和異常 (2)
函數(shù)(1)
用 tornado 做網(wǎng)站 (7)
為做網(wǎng)站而準備
函數(shù)練習
標準庫 (8)
Pandas 使用 (1)
回顧 list 和 str
字典(1)
用 tornado 做網(wǎng)站 (3)
字符串(1)
函數(shù)(2)
寫一個簡單的程序
將數(shù)據(jù)存入文件
語句(5)
SQLite 數(shù)據(jù)庫
集成開發(fā)環(huán)境(IDE)
集合(1)
類(1)
用 tornado 做網(wǎng)站 (6)
用 tornado 做網(wǎng)站 (2)
自省
語句(4)
錯誤和異常 (1)
用 tornado 做網(wǎng)站 (4)
集合(2)
列表(1)
標準庫 (1)
生成器
mysql 數(shù)據(jù)庫 (1)
第三方庫
實戰(zhàn)
運算符
類(3)
字典(2)
語句(1)
數(shù)和四則運算
語句(2)
文件(2)
MySQL 數(shù)據(jù)庫 (2)
電子表格
迭代器
mongodb 數(shù)據(jù)庫 (1)
特殊方法 (2)
特殊方法 (1)
字符編碼
編寫模塊
用 tornado 做網(wǎng)站 (1)
標準庫 (5)
函數(shù)(4)
類(5)
字符串(2)
關(guān)于 Python 的故事
函數(shù)(3)
字符串(4)
處理股票數(shù)據(jù)
常用數(shù)學函數(shù)和運算優(yōu)先級
字符串(3)
為計算做準備
多態(tài)和封裝
類(4)
迭代
語句(3)
錯誤和異常 (3)
分析 Hello
Python 安裝
標準庫 (2)
列表(2)
元組

分析 Hello

打開你寫 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 文件的目錄,執(zhí)行:

$ python hello.py

用 Python 運行這個文件,其實就已經(jīng)發(fā)布了一個網(wǎng)站,只不過這個網(wǎng)站太簡單了。

接下來,打開瀏覽器,在瀏覽器中輸入:http://localhost:8000,得到如下界面

http://wiki.jikexueyuan.com/project/start-learning-python/images/30201.png" alt="" />

我在 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 

此操作,讀者可以根據(jù)自己系統(tǒng)而定。

恭喜你,邁出了決定性一步,已經(jīng)可以用 Tornado 發(fā)布網(wǎng)站了。在這里似乎沒有做什么部署,只是安裝了 Tornado。是的,不需要多做什么,因為 Tornado 就是一個很好的 server,也是一個開發(fā)框架。

下面以這個非常簡單的網(wǎng)站為例,對用 tornado 做的網(wǎng)站的基本結(jié)構(gòu)進行解釋。

WEB 服務器工作流程

任何一個網(wǎng)站都離不開 Web 服務器,這里所說的不是指那個更計算機一樣的硬件設(shè)備,是指里面安裝的軟件,有時候初次接觸的看官容易搞混。就來偉大的維基百科都這么說

有時,這兩種定義會引起混淆,如 Web 服務器。它可能是指用于網(wǎng)站的計算機,也可能是指像 Apache 這樣的軟件,運行在這樣的計算機上以管理網(wǎng)頁組件和回應網(wǎng)頁瀏覽器的請求。

在具體的語境中,看官要注意分析,到底指的是什么。

關(guān)于 Web 服務器比較好的解釋,推薦看看百度百科的內(nèi)容,我這里就不復制粘貼了,具體可以點擊連接查閱:WEB 服務器

在 WEB 上,用的最多的就是輸入網(wǎng)址,訪問某個網(wǎng)站。全世界那么多網(wǎng)站網(wǎng)頁,如果去訪問,怎么能夠做到彼此互通互聯(lián)呢。為了協(xié)調(diào)彼此,就制定了很多通用的協(xié)議,其中 http 協(xié)議,就是網(wǎng)絡(luò)協(xié)議中的一種。關(guān)于這個協(xié)議的介紹,網(wǎng)上隨處就能找到,請自己 google.

網(wǎng)上偷來的一張圖(從哪里偷來的,我都告訴你了,多實在呀。哈哈。),顯示在下面,簡要說明web服務器的工作過程

http://wiki.jikexueyuan.com/project/start-learning-python/images/30202.png" alt="" />

偷個徹底,把原文中的說明也貼上:

  1. 創(chuàng)建 listen socket, 在指定的監(jiān)聽端口, 等待客戶端請求的到來
  2. listen socket 接受客戶端的請求, 得到 client socket, 接下來通過 client socket 與客戶端通信
  3. 處理客戶端的請求, 首先從 client socket 讀取 http 請求的協(xié)議頭, 如果是 post 協(xié)議, 還可能要讀取客戶端上傳的數(shù)據(jù), 然后處理請求, 準備好客戶端需要的數(shù)據(jù), 通過 client socket 寫給客戶端

引入模塊

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

這四個都是 Tornado 的模塊,在本例中都是必須的。它們四個在一般的網(wǎng)站開發(fā)中,都要用到,基本作用分別是:

  • tornado.httpserver:這個模塊就是用來解決 web 服務器的 http 協(xié)議問題,它提供了不少屬性方法,實現(xiàn)客戶端和服務器端的互通。Tornado 的非阻塞、單線程的特點在這個模塊中體現(xiàn)。
  • tornado.ioloop:這個也非常重要,能夠?qū)崿F(xiàn)非阻塞 socket 循環(huán),不能互通一次就結(jié)束呀。
  • tornado.options:這是命令行解析模塊,也常用到。
  • tornado.web:這是必不可少的模塊,它提供了一個簡單的 Web 框架與異步功能,從而使其擴展到大量打開的連接,使其成為理想的長輪詢。

讀者看到這里可能有點莫名其妙,對一些屬于不理解。沒關(guān)系,你可以先不用管它,如果愿意管,就把不理解屬于放到 google 立面查查看。一定要硬著頭皮一字一句地讀下去,隨著學習和實踐的深入,現(xiàn)在不理解的以后就會逐漸領(lǐng)悟理解的。

還有一個模塊引入,是用 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 的時候,才能訪問本網(wǎng)站,因為 http 協(xié)議默認的端口是 80,為了區(qū)分,我在這里設(shè)置為 8000,為什么要區(qū)分呢?因為我的計算機或許你的也是,已經(jīng)部署了別(或許是 Nginx、Apache)服務器了,它的端口是 80,所以要區(qū)分開(也可能是故意不用80端口),并且,后面我們還會將 tornado 和 Nginx 聯(lián)合起來工作,這樣兩個服務器在同一臺計算機上,就要分開嘍。

定義請求-處理程序類

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        greeting = self.get_argument('greeting', 'Hello')
        self.write(greeting + ', welcome you to read: www.itdiffer.com')

所謂“請求處理”程序類,就是要定義一個類,專門應付客戶端(就是你打開的那個瀏覽器界面)向服務器提出的請求(這個請求也許是要讀取某個網(wǎng)頁,也許是要將某些信息存到服務器上),服務器要有相應的程序來接收并處理這個請求,并且反饋某些信息(或者是針對請求反饋所要的信息,或者返回其它的錯誤信息等)。

于是,就定義了一個類,名字是 IndexHandler,當然,名字可以隨便取了,但是,按照習慣,類的名字中的單詞首字母都是大寫的,并且如果這個類是請求處理程序類,那么就最好用 Handler 結(jié)尾,這樣在名稱上很明確,是干什么的。

類 IndexHandler 繼承 tornado.web.RequestHandler,其中再定義 get()post() 兩個在 web 中應用最多的方法的內(nèi)容(關(guān)于這兩個方法的詳細解釋,可以參考:HTTP GET POST 的本質(zhì)區(qū)別詳解,作者在這篇文章中,闡述了兩個方法的本質(zhì))。

在本例中,只定義了一個 get() 方法。

greeting = self.get_argument('greeting', 'Hello') 的方式可以得到 url 中傳遞的參數(shù),比如

$ curl http://localhost:8000/?greeting=Qiwsir
Qiwsir, welcome you to read: www.itdiffer.com 

就得到了在 url 中為 greeting 設(shè)定的值 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()).

main() 方法

if __name__ == "__main__",這個方法跟以往執(zhí)行 Python 程序是一樣的。

tornado.options.parse_command_line(),這是在執(zhí)行 tornado 的解析命令行。在 tornado 的程序中,只要 import 模塊之后,就會在運行的時候自動加載,不需要了解細節(jié),但是,在 main()方法中如果有命令行解析,必須要提前將模塊引入。

Application 類

下面這句是重點:

app = tornado.web.Application(handlers=[(r"/", IndexHandler)])

將 tornado.web.Application 類實例化。這個實例化,本質(zhì)上是建立了整個網(wǎng)站程序的請求處理集合,然后它可以被 HTTPServer 做為參數(shù)調(diào)用,實現(xiàn) http 協(xié)議服務器訪問。Application 類的__init__方法參數(shù)形式:

def __init__(self, handlers=None, default_host="", transforms=None,**settings):
    pass

在一般情況下,handlers 是不能為空的,因為 Application 類通過這個參數(shù)的值處理所得到的請求。例如在本例中,handlers=[(r"/", IndexHandler)],就意味著如果通過瀏覽器的地址欄輸入根路徑(http://localhost:8000 就是根路徑,如果是 http://localhost:8000/qiwsir,就不屬于根,而是一個子路徑或目錄了),對應著就是讓名字為 IndexHandler 類處理這個請求。

通過 handlers 傳入的數(shù)值格式,一定要注意,在后面做復雜結(jié)構(gòu)的網(wǎng)站是,這里就顯得重要了。它是一個 list,list 里面的元素是 tuple,tuple 的組成包括兩部分,一部分是請求路徑,另外一部分是處理程序的類名稱。注意請求路徑可以用正則表達式書寫(關(guān)于正則表達式,后面會進行簡要介紹)。舉例說明:

handlers = [
    (r"/", IndexHandlers),              #來自根路徑的請求用 IndesHandlers 處理
    (r"/qiwsir/(.*)", QiwsirHandlers),  #來自 /qiwsir/ 以及其下任何請求(正則表達式表示任何字符)都由 QiwsirHandlers 處理
]

注意

在這里我使用了 r"/"的樣式,意味著就不需要使用轉(zhuǎn)義符,r 后面的都表示該符號本來的含義。例如,\n,如果單純這么來使用,就以為著換行,因為符號“\”具有轉(zhuǎn)義功能(關(guān)于轉(zhuǎn)義詳細閱讀《字符串(1)》),當寫成 r"\n" 的形式是,就不再表示換行了,而是兩個字符,\ 和 n,不會轉(zhuǎn)意。一般情況下,由于正則表達式和 \ 會有沖突,因此,當一個字符串使用了正則表達式后,最好在前面加上'r'。

關(guān)于 Application 類的介紹,告一段落,但是并未完全講述了,因為還有別的參數(shù)設(shè)置沒有講,請繼續(xù)關(guān)注后續(xù)內(nèi)容。

HTTPServer 類

實例化之后,Application 對象(用app做為標簽的)就可以被另外一個類 HTTPServer 引用,形式為:

http_server = tornado.httpserver.HTTPServer(app)

HTTPServer 是 tornado.httpserver 里面定義的類。HTTPServer 是一個單線程非阻塞 HTTP 服務器,執(zhí)行 HTTPServer 一般要回調(diào) Application 對象,并提供發(fā)送響應的接口,也就是下面的內(nèi)容是跟隨上面語句的(options.port 的值在 IndexHandler 類前面通過 from...import.. 設(shè)置的)。

http_server.listen(options.port)

這種方法,就建立了單進程的 http 服務。

請看官牢記,如果在以后編碼中,遇到需要多進程,請參考官方文檔說明:http://tornado.readthedocs.org/en/latest/httpserver.html#http-server

IOLoop 類

剩下最后一句了:

tornado.ioloop.IOLoop.instance().start()

這句話,總是在__main()__的最后一句。表示可以接收來自 HTTP 的請求了。

以上把一個簡單的 hello.py 剖析。想必讀者對 Tornado 編寫網(wǎng)站的基本概念已經(jīng)有了。

如果一頭霧水,也不要著急,以來將上面的內(nèi)容多看幾遍。對整體結(jié)構(gòu)有一個基本了解,不要拘泥于細節(jié)或者某些詞匯含義。然后即繼續(xù)學習。


總目錄   |   上節(jié):為做網(wǎng)站而準備   |   下節(jié):用 tornado 做網(wǎng)站(1)

如果你認為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。

上一篇:類(5)下一篇:函數(shù)練習