您的位置:首页 > 编程语言 > Python开发

最终版的Web(Python实现)

2017-01-04 20:35 316 查看


今天把最终版的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>


 运行效果如图:





好好准备期末考了。。。。

 重新改了下。。。

运行效果如下:

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My own page</title>
<link rel="stylesheet" href="hxmstyle.css">
<link rel="stylesheet" href="backstyle.css">
<!--[if It IE 9]
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>

<form action="calc.py" >
<p>First number: <input type="text" name="a" value=""/>
<br>Secod number: <input type="text" name="b" value=""/></p>
<input type="submit" value="Submit" />
</form>

<article>
<header>
<hgroup>
<h1 style="color:green">My own web page</h1>
<p class="Byline"  style="color:blue">by Hai Xiaomei</p>
</hgroup>
</header>

<div class="Content">

<div class="FloatFigure" >
<img src="hxm.jpg" >
<p style="color:pink">This is the picture of my own page Will you be the <br>first person view my own page if one of these ....</p>
</div>

<aside class="PullQuote">
<img src="q_start.png">
I am 面朝大海#...
I don't know how the universe started, so I can't be sure it won't
just end, maybe today.
<img src="q_end.png">
</aside>
<a href="http://WWW.baidu.com">Baidu.com</a>
<p >You can BaiDu me in Baidu ~~</p>

</div>
</article>

<a href="AboutMe.html">About Me</a>
<a href="Disclaimer.html">Disclaimer</a>
<a href="ContactUs.html">Contact Me</a>

<p>Copyright © 2017/1/1   Hai XiaoMei</p>
</div>

<a href="index.html">Back</a>

</body>
</html>


  plain.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My Test</title>
</head>
<body>
<p style="color:green">Ha ha, this is plain page...</p>
<img src="a.jpg">
<p>响应静态页面
这一步就 is 处理静态页面了,处理静态页面就是根据请求的页面名得到磁
盘上的页面文件并返回。
在当前目录下创建新文件 plain.html,这是测试用的静态页面</p>
</body>
</html>


  效果如下:











再不详细说了。。。

改错改的好乱。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: