import socket, sys, re, multiprocessing, time
# 定义WSGI服务器类
class WSGIServer(object):
# 初始化服务端socket
def __init__(self, docRoot, app):
# 创建socket
self.svrSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置地址复用
self.svrSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定地址
self.svrSocket.bind(("", 80))
# 改主动为被动
self.svrSocket.listen(128)
# 设定html页面根目录
self.docRoot = docRoot
# 把传进来的app变为对象的app
self.app = app
# 定义运行服务器的方法
def runServer(self):
# 接受客户端请求
cltSocket, _ = self.svrSocket.accept()
# 设定客户端超时时间
# cltSocket.settimeout(3)
# 开启一个新的进程,处理客户端请求
newProcces = multiprocessing.Process(target=self.dealWithRequest, args=(cltSocket,))
# 启动新进程
newProcces.start()
# 设置动态数据的请求头
def setResponse(self, status, headers):
# 设置一些默认请求头的数据
responseHeaderDefault = [
("Data", time.ctime()),
("Server", "BDQN-python mini web server")
]
# 拼接响应头部数据
self.headers = [status, responseHeaderDefault + headers]
# 定义处理客户端请求的函数
def dealWithRequest(self, cltSocket):
while True:
try:
# 接收客户端的数据
content = cltSocket.recv(1024).decode("utf-8")
# 异常捕获
except Exception as ret:
print("========>", ret)
cltSocket.close()
return
# 判断客户端是不是要关闭连接
if not content:
# 如果没有数据,则关闭客户端
cltSocket.close()
return
# 处理客户端传递的数据
requestLines = content.splitlines()
# 提取客户端请求的路径
ret = re.match(r"[^/]+(/[^ ]*)", requestLines[0])
# 判断请求的路径是什么
if ret.group(1) == "/":
# 如果请求的是根路径,让他获取index页面
pathName = ret.group(1) + "index.html"
else:
# 如果请求的不是根路径,则把原有路径赋值
pathName = ret.group(1)
# 处理静态请求
if not pathName.endswith(".html"):
# 如果请求的是静态文件
try:
f = open(self.docRoot + pathName, "r")
# 如果读取不到,捕获异常
except Exception as ret:
# 准备响应头和响应体
responseBody = "file not found, Please input right url"
responseHeader = "HTTP/1.1 404 not found\r\n"
responseHeader += "Content-Type: text/html; charset=utf-8\r\n"
responseHeader += "Content-Length: %d\r\n" % (len(responseBody))
responseHeader += "\r\n"
# 拼接异常的响应数据
response = responseHeader + responseBody
# 如果没有没有异常
else:
# 读取文件数据
content = f.read()
# 准备响应头和响应体
responseBody = content
responseHeader = "HTTP/1.1 200 OK\r\n"
responseHeader += "Content-Type: text/html; charset=utf-8\r\n"
responseHeader += "Content-Length: %d\r\n" % (len(responseBody))
responseHeader += "\r\n"
# 拼接响应数据
response = responseHeader + responseBody
# 将响应数据发送给客户端
cltSocket.send(response.encode('utf-8'))
# 处理动态请求
else:
# 存储所有需要处理的请求的key-value
requestDict = {"pathName": pathName}
# 通过myWeb下的app函数处理动态请求,获取响应数据
responseBody = self.app(requestDict, self.setResponse)
# 设置响应头
responseHeader = "HTTP/1.1 {status}\r\n".format(status=self.headers[0])
responseHeader += "Content-Type: text/html; charset=utf-8\r\n"
responseHeader += "Content-Length: %d\r\n" % (len(responseBody))
# 设置响应头
for tempHead in self.headers[1]:
responseHeader += "{0}:{1}\r\n".format(*tempHead)
# 拼接响应数据
response = responseHeader + "\r\n" + responseBody
# 发送数据给客户端
cltSocket.send(response.encode("utf-8"))
# 设置静态资源访问的路径
gStaticDocumentRoot = "./html"
# 设置动态资源访问的路径
gDynamicDocumentRoot = "./web"
# 定义服务器的入口
def main():
# 判断程序参数符不符合要求
if len(sys.argv) == 2:
# 获取程序的参数,获取要执行的函数名
webModuleAppName = sys.argv[1]
# 如果程序参数不符合要求,中断程序
else:
print("Please input like 'python fileName modelName:applicationName'")
# 导入程序传参模块名以及应用名
ret = re.match(r"([^:]*):(.*)", webModuleAppName)
# 获取模块以及应用名
modelName = ret.group(1)
appName = ret.group(2)
# 添加模块路径到代码环境变量中
sys.path.append(gDynamicDocumentRoot)
# 导入模块名
model = __import__(modelName)
# 将模块内的app应用变成可用的对象或者函数
app = getattr(model, appName)
# 初始化http服务器对象
httpServer = WSGIServer(gStaticDocumentRoot, app)
# 运行http服务器
httpServer.runServer()
if __name__ == "__main__":
main()
web/myWeb.py
import time, re, pymysql
# 定义模版文件存放的位置
templateRoot = "./templates"
# 定义全局路由列表
gUrlRoute = dict()
# 定义装饰器工厂
def route(url):
def func1(func):
gUrlRoute[url] = func
def func2(fileName):
return func(fileName)
return func2
return func1
# 定义查看函数
@route(r"/index/(\d*).html")
def index(fileName, url):
# 异常处理
try:
fileName = "/index.html"
f = open(templateRoot + fileName)
# 捕获异常
except Exception as ret:
return "%s" % ret
# 正常返回数据
else:
# 保存读取的内容
content = f.read()
# 关闭打开的文件
f.close()
# 连接数据库
conn = pymysql.connect(host='172.16.238.130', port=3306, user='root',password='123456',database='my_mysql',charset='utf8')
# 获取游标
cs = conn.cursor()
# 准备查询语句
sql = """select * from goods;"""
# 游标执行语句
cs.execute(sql)
# 获取游标内的数据
dataFromMysql = cs.fetchall()
# 准备html格式
html_template = """
<tr>
<td>%d</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>
<input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="%s">
</td>
</tr>
<br>"""
html = ""
# 准备数据
for data in dataFromMysql:
html += html_template % (data[0], data[1], data[2], data[3], data[4], data[1])
# 进行模版数据的替换
content = re.sub(r"\{%content%\}", html, content)
# 返回数据
return content.encode("utf-8")
@route(r"/center.html")
def center(fileName, url):
# 异常处理
try:
f = open(templateRoot + fileName)
# 捕获异常
except Exception as ret:
return "%s" % ret
# 正常返回数据
else:
# 保存读取的内容
content = f.read()
# 关闭打开的文件
f.close()
# 准备替换数据
dataFromMysql = "center no data,,,,~~~~(>_<)~~~~ \n %s" % time.ctime()
# 进行模版数据的替换
content = re.sub(r"\{%content%\}", dataFromMysql, content)
# 返回数据
return "content"
# 定义添加函数
@route(r"/add/(\d*).html")
def add(fileName, url):
# 获取url中的数字
ret = re.match(url, fileName)
id = ret.group(1)
# 连接数据库
conn = pymysql.connect(host='172.16.238.130', port=3306, user='root',password='123456',database='my_mysql',charset='utf8')
# 获取数据库游标
cs = conn.cursor()
# 定义查询sql语句
sql = '''select * from goods where id=%s''' % id
# 去数据库查询相应ID的数据,如果有则返回数据已存在,没有则添加
cs.execute(sql)
data = cs.fetchall()
# 判断数据是否存在
if data:
return "already exit"
# 数据不存在就添加数据
else:
# 添加sql语句
sql = '''insert into goods
(id, name, cname, bname, price)
values
(%s, "aaa", "bbb", "ccc", 1000)''' % id
# 执行sql语句
cs.execute(sql)
# 提交数据
conn.commit()
# 关闭游标
cs.close()
# 关闭数据连接
conn.close()
# 返回提示信息
return "success"
# 定义修改函数
@route(r"/update/(\d*).html")
def update(fileName, url):
# 获取url中的数字
ret = re.match(url, fileName)
id = ret.group(1)
# 连接数据库
conn = pymysql.connect(host='172.16.238.130', port=3306, user='root',password='123456',database='my_mysql',charset='utf8')
# 获取数据库游标
cs = conn.cursor()
#定义查找的sql语句
sql = '''select * from goods where id=%s''' % id
# 去数据库查询是否有相应的ID的数据, 如果有则修改,没有提示数据不存在
cs.execute(sql)
data = cs.fetchall()
# 如果数据不存在
if not data:
return "data not txt"
# 数据存在
else:
# 修改sql语句
sql = '''update goods set name=cccc where id=%s''' % id
# 执行sql语句
cs.execute(sql)
# 提交数据
conn.commit()
# 关闭游标
cs.close()
# 关闭数据库
conn.close()
# 提示修改成功信息
return "success"
# 定义删除函数
@route(r"/delete/(\d*).html")
def delete(fileName, url):
# 获取url中的数字
ret = re.match(url, fileName)
id = ret.group(1)
# 连接数据库
conn = pymysql.connect(host='172.16.238.130', port=3306, user='root',password='123456',database='my_mysql',charset='utf8')
# 获取数据库游标
cs = conn.cursor()
#定义查找的sql语句
sql = '''select * from goods where id=%s''' % id
# 去数据库查询是否有相应的ID的数据, 如果有则删除,没有提示数据不存在
cs.execute(sql)
data = cs.fetchall()
# 如果数据不存在
if not data:
return "data not txt"
# 数据存在
else:
# 修改sql语句
sql = '''delete from goods where id=%s''' % id
# 执行sql语句
cs.execute(sql)
# 提交数据
conn.commit()
# 关闭游标
cs.close()
# 关闭数据库
conn.close()
# 提示修改成功信息
return "success"
def app(requestDict, setResponse):
# 定义状态码
status = 200
# 定义响应头
responseHeader = [('Content-Type', 'text/html')]
# 设置返回的响应头
setResponse(status, responseHeader)
# 获取客户端请求的路径
pathName = requestDict["pathName"]
# 根据客户端的请求,返回相应的页面
try:
# 遍历路由表,将url键和func函数值取出,做路径对比
for url, callFunc in gUrlRoute.items():
# 用取出的url正则表达式,匹配用户请求的路径
ret = re.match(url, pathName)
# 如果上面的正则获取到了结果,说明路径匹配成功
if ret:
# 如果匹配成功,返回函数的调用结果,也就是responseBody
return callFunc(pathName, url)
# 如果遍历完列表还没结果,说明路径请求错误
else:
return "没有访问的页面--->%s" % pathName
except Exception as ret:
# 没有页面返回的数据
return str(requestDict) + '%s--->%s\n' % (ret, time.ctime())