您的位置:首页 > 理论基础 > 计算机网络

Note7:网络编程之Web动态服务器

2018-03-06 22:02 141 查看
一,介绍
    Web静态服务器的原理是浏览器发送一个请求给服务器,服务器接到请求后解析,然后返回一个响应报文给浏览器,浏览器通过渲染得到用户看到的页面。假如现在有一个要求,我们要求得到的页面是动态的,意思是不同时间可以访问到不同的页面内容。我们不可能时刻的去改写页面数据。这时如果让服务器返回给浏览器的数据是一个程序,那么程序自动执行,我们每次访问页面的时候,就可以得到的是不同的页面数据。即我们只要让服务器的返回消息体是一个程序的话,我们的Web动态服务器就可以实现了。

二,Web动态服务器实现原理:
    服务器要执行一个程序的话,那么我们就要开始构造响应数据了。

    实现Web动态服务器有一个WSGI协议,WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。
def application(env, start_response):
status = '200 OK'
header = [('content','txt')]
start_response(status, header)
return time.ctime()1.status是一个状态码,每个程序执行时所产生的状态码可能不同,所以要写在程序中,不能在服务器中定义
2.header是这个程序的的一些信息
3.status和header组成服务器的响应报文,所以通过start_response中把信息传给服务器,因此服务器要定义一个start_response函数来接收程序给服务器传的一些信息来组成响应报文
4.application函数中有一个env参数,它是一个字典类型,里面是服务器传给这个程序的请求报文(这个请求报文是浏览器给服务器的),而这个请求数据中的一些信息是对执行这个程序是有用的。
5.application函数返回给服务器的信息是一个响应体,因此响应头是通过start_response传给服务器的

三,简单的Web动态服务器
服务器:import socket
import re
import sys
from multiprocessing import Process

HTML_ROOT_DIR = '.\html'
WSGI_DIR = '.\wsgi'

class MyServer(object):

def __init__(self, port):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def bind(self,port):
"""邦定端口"""
self.server.bind(('',port))

def start(self):
self.server.listen(10)
while True:
# 监听链接
conn, addr = self.server.accept()
p = Process(target=self.handle_request, args=(conn,))
p.start()
conn.close()

def handle_request(self, conn):
"""处理客户端的请求,找出其中的path,并将路径符转换为windows中的"""
recv_request = conn.recv(1024).decode()

# 客户端请求数据行首
request = recv_request.splitlines()
for line in request:
print(line)
request_start = request[0]

# 由于windows中的文件目录为‘\’,所以要将其中'/'替换为'\'
path = request_start.split()[1]
new_path = re.sub('/', r'\\', path)

self.response_info(conn, new_path)

def handle_response(self, status, headers):
"""将程序执行的返回的响应消息进行处理来作为本次服务器给浏览器的响应头"""
response_header ='HTTP/1.1 '+status+'\r\n'
for line in headers:
response_header += '%s: %s'%(line) + '\r\n'

self.response_header = response_header

def response_info(self, conn, path):
"""找出文件在服务器中的位置"""

if path.endswith('.py'):
#导入要执行的程序
m = __import__(path[1:-3])
#浏览器的请求数据传给程序
env = {}
#程序的执行通过application函数接口来执行,它返回的是一个响应消息体
response_body = m.application(env, self.handle_response)
info = self.response_header+'\r\n'+response_body
else:

filename = HTML_ROOT_DIR + path
if '\\' == path:
filename = '.\html\index.html'
print(filename)

# 若没有找到正确的文件,则报404 Not Found错误,找到了,则打开读取数据
try:
f = open(filename, 'rb')
response_body = f.read().decode()

4000
except IOError:
response_start = 'HTTP/1.1 404 Not Found\r\n'
response_head = 'server:My server\r\n'
response_body = 'the file is exist\r\n'
else:
response_start = 'HTTP/1.1 200 OK\r\n'
response_head = 'server:My server\r\n'
finally:
info = response_start + response_head + '\r\n' + response_body

conn.send(info.encode('utf-8'))
conn.close()

def main():
sys.path.insert(1, WSGI_DIR)
myserver = MyServer(8000)
myserver.start()

if __name__ == '__main__':
main()程序:import time

def application(env, handle_respose):
status = '200 OK'
headers = [('content', 'text')]
handle_respose(status, headers)
return time.ctime()

四,Web框架的编写
目录:



MyWebFrame:from MyWebServer import MyServer
import time
import re

HTML_DIR = '.\html'

class Application(object):
"""接口"""
def __init__(self, urls):
self.urls = urls

def __call__(self, env, start_response):
path = env.get('PATH_INFO')

#静态页面
if path.startswith('/static'):
#/static/index.html
filename = path[7:]
filename = re.sub('/', r'\\', filename)
print(filename)
try:
f = open(HTML_DIR + filename, 'rb')
data = f.read().decode()
f.close()
status = '200 OK'
headers = [('content', 'txt')]
start_response(status, headers)
return data

except IOError:
status = '404 Not Found'
headers = []
start_response(status, headers)
return 'Error 404 Not Found'

#动态页面
for url, handle in self.urls:
if url == path:
res = handle(env,start_response)
return res

status = '404 Not Found'
headers = []
start_response(status,headers)
return 'file is not exist'

def show_time(env, start_response):
status = '200 OK'
headers = [('content','text/plain')]
start_response(status,headers)
return time.ctime()

def say_hello(env, start_response):
status = '200 OK'
headers = [('content', 'text/plain')]
start_response(status, headers)
return 'hello word'.title()

if __name__ == '__main__':
urls = [('/ctime', show_time), ('/hello', say_hello),('/', show_time)]
app = Application(urls)
myServer = MyServer(app)
myServer.bind(8000)
myServer.start()MyWebServer:import socket
import re
from multiprocessing import Process

class MyServer(object):
""""""
def __init__(self, application):
"""把接口传到服务器中"""
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.app = application

def bind(self,port):
"""邦定端口"""
self.server.bind(('', port))

def start(self):
self.server.listen(100)
while True:
# 监听链接
conn, addr = self.server.accept()
p = Process(target=self.handle_request, args=(conn,))
p.start()
conn.close()

def handle_request(self, conn):
"""处理客户端的请求,找出其中的path,"""
recv_request = conn.recv(1024).decode()

# 客户端请求数据行首
try:
request = recv_request.splitlines()
for line in request:
print(line)
request_start = request[0]
path = request_start.split()[1]
self.response_info(conn, path)
except Exception:
pass

def handle_response(self, status, headers):
"""将响应的消息进行处理"""
response_header ='HTTP/1.1 '+status+'\r\n'
for line in headers:
response_header += '%s: %s'%(line) + '\r\n'

self.response_header = response_header

def response_info(self, conn, path):
"""找出文件在服务器中的位置"""
env = {'PATH_INFO': path}
response_body = self.app(env, self.handle_response)
info = self.response_header+'\r\n'+response_body

conn.send(info.encode('utf-8'))
conn.close()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: