日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Python应用02 Python服务器进化

發布時間:2023/12/4 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python应用02 Python服务器进化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!

**注意,在Python 3.x中,BaseHTTPServer, SimpleHTTPServer, CGIHTTPServer整合到http.server包,SocketServer改名為socketserver,請注意查閱官方文檔。

在上一篇文章中(用socket寫一個Python服務器),我使用socket接口,制作了一個處理HTTP請求的Python服務器。任何一臺裝有操作系統和Python解釋器的計算機,都可以作為HTTP服務器使用。我將在這里不斷改寫上一篇文章中的程序,引入更高級的Python包,以寫出更成熟的Python服務器。

?

支持POST

我首先增加該服務器的功能。這里增添了表格,以及處理表格提交數據的"POST"方法。如果你已經讀過用socket寫一個Python服務器,會發現這里只是增加很少的一點內容。

原始程序:

# Written by Vamei # A messy HTTP server based on TCP socket import socket
#
Address HOST
= '' PORT = 8000text_content = ''' HTTP/1.x 200 OK Content-Type: text/html<head> <title>WOW</title> </head> <html> <p>Wow, Python Server</p> <IMG src="test.jpg"/> <form name="input" action="/" method="post"> First name:<input type="text" name="firstname"><br> <input type="submit" value="Submit"> </form> </html> '''f = open('test.jpg','rb') pic_content = ''' HTTP/1.x 200 OK Content-Type: image/jpg''' pic_content = pic_content + f.read()# Configure socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT))
# Serve forever
while True:s.listen(3)conn, addr = s.accept() request = conn.recv(1024) # 1024 is the receiving buffer sizemethod = request.split(' ')[0]src = request.split(' ')[1]print 'Connected by', addrprint 'Request is:', request
# if GET method request
if method == 'GET':
# if ULR is /test.jpg
if src == '/test.jpg':content = pic_contentelse: content = text_content
# send messageconn.sendall(content)# if POST method request
if method == 'POST':form = request.split('\r\n')idx = form.index('') # Find the empty lineentry = form[idx:] # Main content of the request value = entry[-1].split('=')[-1]conn.sendall(text_content + '\n <p>' + value + '</p>')####### More operations, such as put the form into database# ...######
# close connection
conn.close()

服務器進行的操作很簡單,即從POST請求中提取數據,再顯示在屏幕上。

運行上面Python服務器,像上一篇文章那樣,使用一個瀏覽器打開。

?

?

頁面新增了表格和提交(submit)按鈕。在表格中輸入aa并提交,頁面顯示出aa。

?

我下一步要用一些高級包,來簡化之前的代碼。

?

?

使用SocketServer

首先使用SocketServer包來方便的架設服務器。在上面使用socket的過程中,我們先設置了socket的類型,然后依次調用bind(),listen(),accept(),最后使用while循環來讓服務器不斷的接受請求。上面的這些步驟可以通過SocketServer包來簡化。

SocketServer:

# Written by Vamei # use TCPServerimport SocketServerHOST = '' PORT = 8000text_content = ''' HTTP/1.x 200 OK Content-Type: text/html<head> <title>WOW</title> </head> <html> <p>Wow, Python Server</p> <IMG src="test.jpg"/> <form name="input" action="/" method="post"> First name:<input type="text" name="firstname"><br> <input type="submit" value="Submit"> </form> </html> '''f = open('test.jpg','rb') pic_content = ''' HTTP/1.x 200 OK Content-Type: image/jpg''' pic_content = pic_content + f.read()# This class defines response to each request class MyTCPHandler(SocketServer.BaseRequestHandler):def handle(self):# self.request is the TCP socket connected to the clientrequest = self.request.recv(1024)print 'Connected by',self.client_address[0]print 'Request is', requestmethod = request.split(' ')[0]src = request.split(' ')[1]if method == 'GET':if src == '/test.jpg':content = pic_contentelse: content = text_contentself.request.sendall(content)if method == 'POST':form = request.split('\r\n')idx = form.index('') # Find the empty lineentry = form[idx:] # Main content of the request value = entry[-1].split('=')[-1]self.request.sendall(text_content + '\n <p>' + value + '</p>')####### More operations, such as put the form into database# ...####### Create the server server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler) # Start the server, and work forever server.serve_forever()

?

我建立了一個TCPServer對象,即一個使用TCP socket的服務器。在建立TCPServe的同時,設置該服務器的IP地址和端口。使用server_forever()方法來讓服務器不斷工作(就像原始程序中的while循環一樣)。

我們傳遞給TCPServer一個MyTCPHandler類。這個類定義了如何操作socket。MyTCPHandler繼承自BaseRequestHandler。改寫handler()方法,來具體規定不同情況下服務器的操作。

在handler()中,通過self.request來查詢通過socket進入服務器的請求 (正如我們在handler()中對socket進行recv()sendall()操作),還使用self.address來引用socket的客戶端地址。

?

經過SocketServer的改造之后,代碼還是不夠簡單。?我們上面的通信基于TCP協議,而不是HTTP協議。因此,我們必須手動的解析HTTP協議。我們將建立基于HTTP協議的服務器。

?

SimpleHTTPServer: 使用靜態文件來回應請求

HTTP協議基于TCP協議,但增加了更多的規范。這些規范,雖然限制了TCP協議的功能,但大大提高了信息封裝和提取的方便程度。

對于一個HTTP請求(request)來說,它包含有兩個重要信息:請求方法和URL。

請求方法(request method)?????? URL??????????????? 操作

GET?????????????????????????? /????????????????? 發送text_content

GET?????????????????????????? /text.jpg????????? 發送pic_content

POST????????????????????????? /????????????????? 分析request主體中包含的value(實際上是我們填入表格的內容); 發送text_content和value

?

根據請求方法和URL的不同,一個大型的HTTP服務器可以應付成千上萬種不同的請求。在Python中,我們可以使用SimpleHTTPServer包和CGIHTTPServer包來規定針對不同請求的操作。其中,SimpleHTTPServer可以用于處理GET方法和HEAD方法的請求。它讀取request中的URL地址,找到對應的靜態文件,分析文件類型,用HTTP協議將文件發送給客戶。

?

SimpleHTTPServer

?

我們將text_content放置在index.html中,并單獨存儲text.jpg文件。如果URL指向index_html的母文件夾時,SimpleHTTPServer會讀取該文件夾下的index.html文件。

?

我在當前目錄下生成index.html文件:

<head> <title>WOW</title> </head> <html> <p>Wow, Python Server</p> <IMG src="test.jpg"/> <form name="input" action="/" method="post"> First name:<input type="text" name="firstname"><br> <input type="submit" value="Submit"> </form> </html>

?

改寫Python服務器程序。使用SimpleHTTPServer包中唯一的類SimpleHTTPRequestHandler:

# Written by Vamei # Simple HTTPsERVERimport SocketServer import SimpleHTTPServerHOST = '' PORT = 8000# Create the server, SimpleHTTPRequestHander is pre-defined handler in SimpleHTTPServer package server = SocketServer.TCPServer((HOST, PORT), SimpleHTTPServer.SimpleHTTPRequestHandler) # Start the server server.serve_forever()

?

這里的程序不能處理POST請求我會在后面使用CGI來彌補這個缺陷。值得注意的是,Python服務器程序變得非常簡單。將內容存放于靜態文件,并根據URL為客戶端提供內容,這讓內容和服務器邏輯分離。每次更新內容時,我可以只修改靜態文件,而不用停止整個Python服務器。

這些改進也付出代價。在原始程序中,request中的URL只具有指導意義,我可以規定任意的操作。在SimpleHTTPServer中,操作與URL的指向密切相關。我用自由度,換來了更加簡潔的程序。

?

CGIHTTPServer:使用靜態文件或者CGI來回應請求

CGIHTTPServer包中的CGIHTTPRequestHandler類繼承自SimpleHTTPRequestHandler類,所以可以用來代替上面的例子,來提供靜態文件的服務。此外,CGIHTTPRequestHandler類還可以用來運行CGI腳本

CGIHTTPServer

?

先看看什么是CGI (Common Gateway Interface)。CGI是服務器和應用腳本之間的一套接口標準。它的功能是讓服務器程序運行腳本程序,將程序的輸出作為response發送給客戶。總體的效果,是允許服務器動態的生成回復內容,而不必局限于靜態文件。

支持CGI的服務器程接收到客戶的請求,根據請求中的URL,運行對應的腳本文件。服務器會將HTTP請求的信息和socket信息傳遞給腳本文件,并等待腳本的輸出。腳本的輸出封裝成合法的HTTP回復,發送給客戶。CGI可以充分發揮服務器的可編程性,讓服務器變得“更聰明”。

服務器和CGI腳本之間的通信要符合CGI標準。CGI的實現方式有很多,比如說使用Apache服務器與Perl寫的CGI腳本,或者Python服務器與shell寫的CGI腳本。

?

為了使用CGI,我們需要使用BaseHTTPServer包中的HTTPServer類來構建服務器。Python服務器的改動很簡單。

CGIHTTPServer:

# Written by Vamei # A messy HTTP server based on TCP socket import BaseHTTPServer import CGIHTTPServerHOST = '' PORT = 8000# Create the server, CGIHTTPRequestHandler is pre-defined handler server = BaseHTTPServer.HTTPServer((HOST, PORT), CGIHTTPServer.CGIHTTPRequestHandler) # Start the server server.serve_forever()

?

CGIHTTPRequestHandler默認當前目錄下的cgi-binht-bin文件夾中的文件為CGI腳本,而存放于其他地方的文件被認為是靜態文件。因此,我們需要修改一下index.html,將其中form元素指向的action改為cgi-bin/post.py。

<head> <title>WOW</title> </head> <html> <p>Wow, Python Server</p> <IMG src="test.jpg"/> <form name="input" action="cgi-bin/post.py" method="post"> First name:<input type="text" name="firstname"><br> <input type="submit" value="Submit"> </form> </html>

?

我創建一個cgi-bin的文件夾,并在cgi-bin中放入如下post.py文件,也就是我們的CGI腳本

#!/usr/bin/env python # Written by Vamei import cgi form = cgi.FieldStorage()# Output to stdout, CGIHttpServer will take this as response to the client print "Content-Type: text/html" # HTML is following print # blank line, end of headers print "<p>Hello world!</p>" # Start of content print "<p>" + repr(form['firstname']) + "</p>"

(post.py需要有執行權限,見評論區)

第一行說明了腳本所使用的語言,即Python。 cgi包用于提取請求中包含的表格信息。腳本只負責將所有的結果輸出到標準輸出(使用print)。CGIHTTPRequestHandler會收集這些輸出,封裝成HTTP回復,傳送給客戶端。

對于POST方法的請求,它的URL需要指向一個CGI腳本(也就是在cgi-bin或者ht-bin中的文件)。CGIHTTPRequestHandler繼承自SimpleHTTPRequestHandler,所以也可以處理GET方法和HEAD方法的請求。此時,如果URL指向CGI腳本時,服務器將腳本的運行結果傳送到客戶端;當此時URL指向靜態文件時,服務器將文件的內容傳送到客戶端。

更進一步,我可以讓CGI腳本執行數據庫操作,比如將接收到的數據放入到數據庫中,以及更豐富的程序操作。相關內容從略。

?

總結

我使用了Python標準庫中的一些高級包簡化了Python服務器。最終的效果分離靜態內容、CGI應用和服務器,降低三者之間的耦合,讓代碼變得簡單而容易維護。

希望你享受在自己的電腦上架設服務器的過程。

?

歡迎繼續閱讀“Python快速教程”

總結

以上是生活随笔為你收集整理的Python应用02 Python服务器进化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。