标签:
改写上一篇文章中的程序。并引入更高级的Python包,以写出更成熟的Pythonserver。
# A messy HTTP server based on TCP socket import socket # Address HOST = '' PORT = 8000 text_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 size method = request.split(' ')[0] src = request.split(' ')[1] print 'Connected by', addr print 'Request is:', request # if GET method request if method == 'GET': # if ULR is /test.jpg if src == '/test.jpg': content = pic_content else: content = text_content # send message conn.sendall(content) # if POST method request if method == 'POST': form = request.split('rn') idx = form.index('') # Find the empty line entry = 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()
我们看到了新增的表格以及提交(submit)button。在表格中输入aa并提交表格,我们的Pythonserver给出上面的结果。
SocketServer: # use TCPServer import SocketServer HOST = '' PORT = 8000 text_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 client request = self.request.recv(1024) print 'Connected by',self.client_address[0] print 'Request is', request method = request.split(' ')[0] src = request.split(' ')[1] if method == 'GET': if src == '/test.jpg': content = pic_content else: content = text_content self.request.sendall(content) if method == 'POST': form = request.split('rn') idx = form.index('') # Find the empty line entry = 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一个MyTCPHandler类。用对socket作出操作。
注意。MyTCPHandler继承自BaseRequestHandler,我们通过改写handler()方法来个性化我们的操作。
在handler()中,能够通过self.request来引用socket (正如我们在handler()中对socket进行recv()和sendall()操作),
还能够使用self.address来引用socket的client地址。
当中,SimpleHTTPServer能够用于处理GET方法和HEAD方法的请求。
它读取request中的URL地址,并在当前文件夹中找到相应的静态文件。并将文件的内容发送给client。
相应于我们的情况,就是将text_content放置在index.html中,而不用读取text.jpg文件。
当一个HTTP请求到来时,其URL指向某个文件,SimpleHTTPServer会读取这个文件,并分析文件类型,自己主动生成response,回复client。
假设URL指向某个目录,SimpleHTTPServer会读取该目录下的index.html或者index.hml文件。
首先,我们在当前文件夹下生成例如以下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>
SimpleHTTPServer: # Simple HTTPsERVER import SocketServer import SimpleHTTPServer HOST = '' 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()
我们会在后面使用CGI来弥补这个缺陷。
但要点是,我们的Pythonserver程序已经变得很easy。
我们将内容存放于静态文件,并依据URL指向的静态文件为client提供内容,从而让内容和Pythonserver相分离。
这种话。我们每次更新内容的时候就能够仅仅改动静态文件,而不用停止整个Pythonserver。
我们也应该注意到使用这些改进付出的代价。
比方说。对于原始程序来说。request中的URL仅仅具有指导意义,我们能够随意规定对应的操作。
而在 SimpleHTTPServer的改进中,response固化成为:读取URL相应文件并将其内容呈现给客户。这大大限制了我们的自由度。
即使在后面我们使用CGI增大了自由度。但相对于原始程序,我们依旧是添加了自己的限制。
有时候,程序的便捷与程序的自由度相抵触。程序猿须要在两者之间取舍。
对于一个小的项目来说,我们能够尾随已经 制定的标准(比方这里的SimpleHTTPServer,或者使用一个框架),使用这些新的标准能够让开发变得非常便捷。
然而对于一个大型的项目来说。我们往往须要争取回自己的自由度,修订成为项目须要的标准。
此外,CGIHTTPRequestHandler类还能够用来执行CGI脚本。
首先,我们先看看什么是CGI (Common Gateway Interface)。CGI是server和应用脚本之间的一套接口标准。目的是让server程序执行脚本程序,将程序的输出作为response发送给客户。
通常来说,支持CGI的server程在接收到客户的request之后,依据request中的URL。执行相应的脚本文件。
server会将HTTP request信息以及socket信息输入给脚本文件,也负责收集脚本的输出,并组装成为合法的HTTP response。
利用CGI,我们能够充分发挥server的可编程性,动态的生成response。而不必局限于静态文件。
server和CGI脚本之间通过CGI标准作为接口。
这样就能够让server与不同语言写的CGI脚本相配合,比方说使用Apacheserver与Perl写的CGI脚本,或者Pythonserver与shell写的CGI脚本。
到这里为止,我们都在使用TCPServer来构建server。
为了使用CGI,我们须要使用BaseHTTPServer包中的HTTPServer类来构建server。
事实上HTTPServer是TCPServer的子类,其用法也与TCPServer同样。它仅仅是添加了server_name和server_port两个属性。
但不凑巧的是。我们的CGIHTTPRequestHandler须要调用这两个属性…
Pythonserver的修改非常easy。
CGIHTTPServer: # A messy HTTP server based on TCP socket import BaseHTTPServer import CGIHTTPServer HOST = '' PORT = 8000 # Create the server, CGIHTTPRequestHandler is pre-defined handler server = BaseHTTPServer.HTTPServer((HOST, PORT), CGIHTTPServer.CGIHTTPRequestHandler) # Start the server server.serve_forever()
<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>"
第一行必需要有,以便告诉Pythonserver,脚本所使用的语言 (我们这里的CGI是Python。当然也能够是别的语言,比方bash)。
cgi包用于提取request中提交的表格信息(我们临时不深入cgi包)。脚本仅仅负责将全部的结果输出到标准输出(使用print)。
而CGIHTTPRequestHandler会收集这些输出。并组装成为response传送给client。
假设一个请求是POST方法,那么它的URL必须指向一个CGI脚本(也就是在cgi-bin或者ht-bin中的文件)。
CGIHTTPRequestHandler继承自SimpleHTTPRequestHandler,所以也能够处理GET方法和HEAD方法的请求。
此时。假设URL指向CGI脚本时。server将脚本的执行结果传送到client;当此时URL指向静态文件时,server将文件的内容传送到client。
我们能够让CGI脚本运行数据库操作。比方将接收到的数据放入到数据库中,以及更丰富的程序操作。
CGI脚本提供了LAMP架构中PHP任务 (我们的Pythonserver等价物LAMP中间Apache)。
版权声明:本文博主原创文章,博客,未经同意不得转载。
标签:
原文地址:http://www.cnblogs.com/lcchuguo/p/4864956.html