天啦,要考试了,要期末考试了,今天把最终版的Python搭建Web代码先写这里记下了。详细的过程先不写了。
这次是在前面的基础上重写 HTTPServer 与 BaseHTTPRequestHandler,主要利用 python 提供
的 socket 进行编程,从而实现消息的接收与相应;然后再接着引入多线程,分别处理来自客户
端的请求;最后实现根据客户端传递的参数动态生成页面的功能。
主要步骤如下:
一、 .重写 HTTPServer 与 BaseHTTPRequestHandler
Python socket 编程流程(服务器端) :
1. 第一步是创建 socket 对象。调用 socket 构造函数。如:
socket = socket.socket( family, type )
family 参数代表地址家族, 可为 AF_INET 或 AF_UNIX。 AF_INET 家族包括 Internet
地址,AF_UNIX 家族用于同一台机器上的进程间通信。
type 参数代表套接字类型,可为 SOCK_STREAM(流套接字)和 SOCK_DGRAM(数
据报套接字)。
2. 第二步是将socket绑定到指定地址。 这是通过socket对象的bind方法来实现的:
socket.bind( address )
由 AF_INET 所创建的套接字,address 地址必须是一个双元素元组,格式是
(host,port)。host 代表主机,port 代表端口号。如果端口号正在使用、主机名不正
确或端口已被保留,bind 方法将引发 socket.error 异常。
3. 第三步是使用 socket 套接字的 listen 方法接收连接请求。
socket.listen( backlog )
backlog 指定最多允许多少个客户连接到服务器。 它的值至少为 1。 收到连接请求后,
这些请求需要排队,如果队列满,就拒绝请求。
4. 第四步是服务器套接字通过 socket 的 accept 方法等待客户请求一个连接。
connection, address = socket.accept()
调 用 accept 方法时,socket 会时入“waiting”状态。客户请求连接时,方法建立连
接并返回服务器。 accept 方法返回一个含有两个元素的 元组(connection,address)。
第一个元素 connection 是新的 socket 对象,服务器必须通过它与客户通信;第二
个元素 address 是客户的 Internet 地址。
5. 第五步是处理阶段, 服务器和客户端通过 send 和 recv 方法通信(传输 数据)。 服
务器调用 send,并采用字符串形式向客户发送信息。send 方法返回已发送的字符
个数。服务器使用 recv 方法从客户接收信息。调用 recv 时,服务器必须指定一个
整数,它对应于可通过本次方法调用来接收的最大数据量。recv 方法在接收数据时
会进入“blocked”状态,最后返回一个字符 串,用它表示收到的数据。如果发送的数
据量超过了 recv 所允许的,数据会被截短。多余的数据将缓冲于接收端。以后调用
recv 时,多余的数据会从缓冲区 删除(以及自上次调用 recv 以来,客户可能发送的
其它任何数据)。
6. 传输结束,服务器调用 socket 的 close 方法关闭连接。
整个代码块儿如下:
注释有点乱, 中英文结合。。
Test.py
# -*-coding:utf-8 -*- import BaseHTTPServer import os import socket import subprocess import threading from datetime import datetime class ServerException( Exception ): pass # # 重写 HTTPServer 与 BaseHTTPRequestHandler,主要利用 python 提供 # 的 socket 进行编程,从而实现消息的接收与相应;然后再接着引入多线程,分别处理来自客户 # 端的请求;最后实现根据客户端传递的参数动态生成页面的功能。 # step1:reWrite HttpServer and BaseHTTPRequestHandler class HttpServer: def __init__(self, serverAddr, RequestHandler): self.serverAddr = serverAddr self.requestHandler = RequestHandler def serve_forever(self): # 1. create socket object(对象), call socket create function server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 1family=AF_INET,type=SOCK_STREAM server_sock.bind(self.serverAddr) # 2. call socket bind, aim to bind socket to pointed address # address must be a two-elements yuanzu, style is (host, port) # host stands for port number. if port number is in using\ #、host name is wrong or port number has been saved, bind way will # bring socket.error yi chang server_sock.listen(10) # 3. using socket's listen way to receive connect request # listen parament backlog=10:point allow no more than 10 clients # can connect to server. its value at least is 1. when received # request, those requests need pai dui,if list full, then refuse request while True: print 'waiting for connection...' clientsock, addr = server_sock.accept() # 4. server socket wait for client to request a connection # when call accept() function, socket will come into "wating" # states. when client request connection,function create # connection and return server.. # accept function return with two elements # (connection, address)., the first connection is new socket's # object, server must through it to tong xin with client. # the second element address is clients' Internet address print 'received from :', addr thread = threading.Thread(target=self.startThread, args=(clientsock, addr,)) thread.setDaemon(True) thread.start() # handler = RequestHandler(clientsock, addr,self) server_sock.close() def startThread(self, clientsock, addr): handler = RequestHandler(clientsock, addr, self) class HttpRequestHandler: bufsize = 1024 def __init__(self, clientsock, addr): self.cliensock = clientsock self.client_address = addr self.date_time_string = datetime.now() self.analyze() # http head part analyze def analyze(self): # receive dates, bufsize points to read dates num one time """ :type self: object """ data = self.cliensock.recv(self.bufsize) # print'receive ------->%s\n%s' %(datetime.now(), data) # chrome sometimes will send two request consist, tne second is null, reason is unknow if data.repalce(" ", "") == "": print "data is null" return data = data.split('\r\n') # first line is "GET/something.html?a=1&b=2 HTTP/1.1 firstLine = data[0] arr = firstLine.split(' ') self.command = arr[0] self.protocol = arr[2] if '?' in arr[1]: # path put absolute way self.path, self.paramStr = arr[1].spilt('?') else: self.path = arr[1] self.paramStr = None # put the remain of head information in heades's dictionary in the way of key value # Accept-Language : zh - cn # Connection : Keep - Alive # Host : Localhost # Accept - Encoding : gzip, deflate self.headers = {} for line in data[1:]: if ':' in line: key, value = line.split(':', 1) self.headers[key] = value # call function to deal with, this function has come in the first self.do_GET() # time.sleep(30) # when this function receive data, first feng li data # char string as th rule of '\r\n' # then ti qu first line, that is "GET/something.html?a=1&b=2 HTTP/1.1 # then analyze it , put it to the variable # path http_response = "HTTP/1.1" def send_response(self, status): if status == 200: self.http_response += "200" + " " + "OK" elif status == 404: self.http_response += "400" + " " + "Not Found" self.http_response += '\r\n' # "Content_Type", "text/html" # "Content-Length", Length def send_heade(self, key, value): self.http_response += str(key) + ": " + str(value) + '\r\n' def end_headers(self): self.http_response += '\r\n' def write(self, page): self.http_response += str(page) self.clientsock.send(self.http_response) self.cliensock.close() # those functions are pin zhuang http_response char string # as the rule of response head style class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """dealt with and return page""" # page model Page = ''' <html> <body> <table border=2s> <tr> <td>Header</td> <td>Value</td> </tr> <tr> <td>Date</td><td> and time</td> <td>{date_time}</td> </tr> <tr> <td>Client host</td> <td>{client_host}</td> </tr> <tr> <td>Client port</td> <td>{client_port}</td> </tr> <tr> <td>Command</td> <td>{command}</td> </tr> <tr> <td>Path</td> <td>{path}</td> </tr> </table> </body> </html> ''' Error_Page = """\ <html> <body> <h1>Error accessing {path}</h1> <p>{msg}</p> </body> </html> """ def handle_error(self, msg): content = self.Error_Page.format( path=self.path, msg=msg ) self.send_content( content, 404 ) def handle_file(self, full_path): # 处理 python 脚本 if full_path.endswith('.py'): # data 为脚本运行后的返回值 data = subprocess.check_output(['python', full_path, self.paramStr] ) self.send_content(data) return try: with open(full_path, 'rb') as reader: content = reader.read() self.send_content(content) except IOError as msg: msg = "'{0}' cannot be read: {1}".format(self.path, msg ) self.handle_error(msg) # deal with a request def do_GET(self): # type: () -> object try: full_path = os.getcwd() + self.path if not os.path.exists(full_path): raise ServerException("'{0}' not found".format( self.path ) ) elif os.path.isfile(full_path): self.handle_file(full_path) # 访问根路径 elif os.path.isdir(full_path): # fullPath = os.path.join(fullPath, "index.html") full_path += "index.html" if os.path.isfile(full_path): self.handle_file(full_path ) else: raise ServerException( "'{0}' not found".format( self.path ) ) else: raise ServerException( "Unknown object '{0}'".format( self.path ) ) except Exception as msg: self.handle_error(msg) @property def create_page(self): values = { 'date_time': self.date_time_string( ), 'client_host': self.client_address[0], 'client_port': self.client_address[1], 'command': self.command, 'path': self.path } page = self.Page.format( **values ) return page pass def send_content(self, content, status=200): self.send_response(status) self.send_header("Content-type", "text/html" ) self.send_header("Content-Length", str( len( content ) ) ) self.end_headers() # self.wfile.write(self.create_page) self.wfile.write(content) # self.write(page) pass if __name__ == '__main__': serverAddr = ('localhost', 5555) server = HttpServer(serverAddr, RequestHandler ) server.serve_forever()
calc.py
import sys paramStr = sys.argv[1] paramArr = paramStr.split('&') paramDict = {} for param in paramArr: key, value = param.split('=') paramDict[key] = value print '''\ <html> <body> <p>a + b = {0}</p> </body> </html>'''.format((int(paramDict['a']) + int(paramDict['b'])))
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h1>Index Page </h1> <p>I love Python, to be honest</p> <table border=2s> <tr> <td>Header</td> <td>Value</td> </tr> <tr> <td>Date</td><td> and time</td> <td>{date_time}</td> </tr> <tr> <td>Client host</td> <td>{client_host}</td> </tr> <tr> <td>Client port</td> <td>{client_port}</td> </tr> <tr> <td>Command</td> <td>{command}</td> </tr> <tr> <td>Path</td> <td>{path}</td> </tr> </table> <p>please input first number:</p> <input> <br> <p>please input second number:</p> <input> <button>add</button> </body> </html>
运行效果如图:
好好准备期末考了。。。。