mini—web搭建
各位 想学python的小伙伴 上篇文章我讲到了循环 不知道大家学习的怎么样 有没有不懂的地方啊 我这边可能人气太低了 也没有小伙伴评论和我交流 那今天我就不往下讲了 今天给大家像一个比较有意思的 东西 就是标题上写的 mini——web的搭建 相信大家看完我这篇文章 也能够搭建出属于自己的服务。 好了 话不多说 咱们进入今天的主题
**
python搭建服务端
**
在python中搭建服务端框架 是一件特别容易的事情
细分的话一共也就是7个步骤
1、导入网络模块工具 socket
2、创建服务端连接对象
3、绑定IP地址和端口 方便后续监听是否有客户端请求服务端的ip和端口
4、指定监听数量
5、等待客户端连接
6、接收客户端传递的数据
7、返回数据给客户端
8、关闭服务端
理清步骤以后我们来上代码看一下
#导入网络模块
import socket
#创建服务端连接对象 AF_INET指定IP地址类型 IPV4 SOCK_STREAM 表示传输协议 TCP协议
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定IP地址和端口 这里传入得地址是你自己的ip地址
# 端口号是建议端口号设置在8000到9999 它们是以元组的方式传入的
server.bind(('127.0.0.1',8080))
# 指定监听数量 自己电脑测试5个就管够了 最多不要超过128
server.listen(5)
#这里在你运行以后打印一下 告诉你 服务端启动了
print('服务端启动')
# 4、等待客户端连接 (阻塞) 为什么要加阻塞呢 这个步骤就相当于是一个阻塞函数 这里不接收到值 程序时不往下执行的
#clien,addr 是变量名 随意定义
#代码执行到此 说明连接建立成功
clinet_sockt, addr = server.accept()
print('客户端socket', clinet_sockt)
print('客户端地址', addr)
#接收客户端发来的数据 接收的字节为1024
recv_data = clinet_sockt.recv(1024)
#获取接收数据的长度
recv_data_len = len(recv_data)
#对二进制数据进行解码
recv_count = recv_data.decode('gbk')
print('接收客户端数据为',recv_count)
#返回数据给客户端
#这里的clien 是上面等待客户端连接指令里面的客户端信息
data = 'hello python'
clinet_sockt.send(data.encode('gbk'))
#关闭服务端
server.close()
这里如果大家复制粘贴 运行过后 你们应该会发现一个问题 程序只能运行一次 接收一次值 很麻烦 真实的生产场景中 服务器总是源源不断的接收客户端发过来的请求 那怎么样去实现呢 不知道大家还记不记得 我一篇文章中的讲到的死循环 我们利用死循环 让服务端不断地去运行 交给线程去处理
上个代码
#导入网络开发工具
import socket
import threading
'''
1、创建服务端连接对象
2、绑定ip和端口 方便后续监听是否有客户端请求服务端的ip和端口
3、指定监听的数量
4、等待客户端连接 (阻塞)
5、接收客户端传递的数据
6、返回数据给客户端
7、关闭服务端
服务端持续运行 需要将while循环
可以将 客户端处理封装成函数 在创建线程处理
'''
#封装处理客户端的方法
def client_data(clinet_sockt):
while True:
# 5、接收客户端传递的数据
recv_data = clinet_sockt.recv(1024)
# print(recv_data)
# 6、返回数据给客户端
data = 'hello client'
clinet_sockt.send(data.encode('gbk'))
# 1、创建服务端连接对象
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2、绑定ip和端口 方便后续监听是否有客户端请求服务端的ip和端口
server.bind(('192.168.14.48',8006))
# 3、指定监听的数量
server.listen(5)
print('服务端启动.......')
#让服务端持续接收客户端请求的数据
while True:
# 4、等待客户端连接 (阻塞)
clinet_sockt,addr = server.accept()
print('客户端socket',clinet_sockt)
print('客户端地址',addr)
#创建线程处理客户的请求数据
t = threading.Thread(target=client_data,args=(clinet_sockt,))
t.start()
# 7、关闭服务端
# server.close()
这里有好多的东西都没有讲 大家就先运行这玩儿一玩儿
像函数 网络协议(TCP HTTP) 线程 都没有给大家讲 大家就先对这些代码 先混个脸熟
给大家弄一个客户端的后台代码
#导入开发工具
import socket
'''
1、创建socket对象
2、连接服务器
3、发送数据
4、接收服务端返回数据
5、关闭客户端
'''
# 1、创建socket对象 socket.AF_INET 指定ip地址为IPV4,socket.SOCK_STREAM指定通讯协议为TCP协议
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2、连接服务器 (元组)
client.connect(('127.0.0.1',8080))
# 3、发送数据 b'hello server' 直接按照bytes类型传递数据
#将字符串转换为 bytes类型 data.encode()
data = '123.txt'
client.send(data.encode('gbk'))
# 4、接收服务端返回数据 recv(1024)需要指定接受数据的大小
#将bytes类型转换为字符串 str_data = recv_data.decode()
recv_data = client.recv(1024)
str_data = recv_data.decode('gbk')
print(str_data)
# 5、关闭客户端
client.close()
在放一个HTTP服务器的代码
这里会涉及到 请求报文和 响应报文 对于请求的字符切割 我们后续慢慢的来讲这些东西
import socket
#创建socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定ip和端口
server.bind(('192.168.14.50',8080))
#指定监听数量
server.listen(5)
print('服务器启动......')
#等待连接
clint_socket,addr = server.accept()
#获取客户端数据
recv_data = clint_socket.recv(1024)
#将bytes转化为字符串
print('客户端数据:',recv_data.decode())
#返回数据给客户端
send_data = 'hello python'
# 构建响应报文
#响应行
response_line ='HTTP/1.1 200 ok \r\n'
#响应头
response_header = 'Server:python\r\n\r\n'
#响应体
response_body = send_data
#拼接三部分数据构成完整的响应报文
response_data = response_line + response_header + response_body
clint_socket.send(response_data.encode())
Web静态服务器
import socket
#创建socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定ip和端口
server.bind(('192.168.14.50',8081))
#指定监听数量
server.listen(5)
print('服务器启动......')
while True:
#等待连接
clint_socket,addr = server.accept()
#获取客户端数据
recv_data = clint_socket.recv(1024)
#将bytes转化为字符串
print('客户端数据:',recv_data.decode())
#返回数据给客户端
#读取文件
file =open('./index.html','r',encoding='utf-8')
send_data = file.read()
# 构建响应报文
#响应行
response_line ='HTTP/1.1 200 ok \r\n'
#响应头
response_header = 'Server:python\r\n\r\n'
#响应体
response_body = send_data
#拼接三部分数据构成完整的响应报文
response_data = response_line + response_header + response_body
clint_socket.send(response_data.encode())
你们细心点看的话 一定会发现 这几个的服务的代码都好像 没错啦 它们都是从最基本的服务器代码 变化过来的 只是为了实现不同的功能
多页面返回
import socket
import threading
# 1、创建服务端对象
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定ip和端口
server.bind(('127.0.0.1',8008))
#3、监听
server.listen(5)
#循环等待客户端连接
while True:
clinet_data,addr = server.accept()
#接收客户端数据
recv_data = clinet_data.recv(1024)
print(recv_data)
#读取请求报文中的请求路径,根据不同的请求路径返回不同的页面
#1、将bytes类型转为字符串
str_data = recv_data.decode()
#2、字符串切割 按照\r\n进行切割 得到请求行 请求头请求体数据
data_list = str_data.split('\r\n')
print('切割后的列表数据',data_list)
#3、从切割后的列表中提取请求行数据 在按照空格切割请求行数
request_line = data_list[0]
print('请求行数据',request_line)
#4、空格切割请求路径
url_path = request_line.split(' ')[1]
print('切割数据',url_path)
#5、根据不同的路径返回不同的页面
if url_path == '/':
file = open('./index.html','r',encoding='utf-8')
send_data = file.read()
file.close()
elif url_path == '/request':
#注册页面
#读取注册页面的信息
file1 = open('./request.html','r',encoding='utf-8')
send_data = file1.read()
file1.close()
else:
send_data = 'No found'
#返回数据给客户端
# file = open('./index.html','r',encoding='utf-8')
# send_data = file.read()
#构建报文数据
#响应行
response_line = 'http/1.1 200 ok \r\n'
# 响应头
response_header = 'Server:python\r\n\r\n'
# 响应体
response_body = send_data
# 拼接三部分数据构成完整的响应报文
response_data = response_line + response_header + response_body
clinet_data.send(response_data.encode())
多任务静态页面
import socket
import threading
#处理客户端请求
def clinet_info(clinet_data):
# 接收客户端数据
recv_data = clinet_data.recv(1024)
print(recv_data)
# 解决方案1 直接判断数据是否为空
# if len(recv_data) == 0:
# clinet_data.send('not data')
#解决方案二 捕获数据异常 捕获到异常就结束函数的业务逻辑执行
try:
# 读取请求报文中的请求路径,根据不同的请求路径返回不同的页面
# 1、将bytes类型转为字符串
str_data = recv_data.decode()
# 2、字符串切割 按照\r\n进行切割 得到请求行 请求头请求体数据
data_list = str_data.split('\r\n')
print('切割后的列表数据', data_list)
# 3、从切割后的列表中提取请求行数据 在按照空格切割请求行数
request_line = data_list[0]
print('请求行数据', request_line)
# 4、空格切割请求路径
url_path = request_line.split(' ')[1]
print('切割数据', url_path)
except Exception as e:
print(e)
clinet_data.send('not data')
return None
# 5、根据不同的路径返回不同的页面
if url_path == '/':
file = open('./index.html', 'r', encoding='utf-8')
send_data = file.read()
file.close()
elif url_path == '/request':
# 注册页面
# 读取注册页面的信息
file1 = open('./request.html', 'r', encoding='utf-8')
send_data = file1.read()
file1.close()
else:
send_data = 'No found'
# 返回数据给客户端
# file = open('./index.html','r',encoding='utf-8')
# send_data = file.read()
# 构建报文数据
# 响应行
response_line = 'http/1.1 200 ok \r\n'
# 响应头
response_header = 'Server:python\r\n\r\n'
# 响应体
response_body = send_data
# 拼接三部分数据构成完整的响应报文
response_data = response_line + response_header + response_body
clinet_data.send(response_data.encode())
# 1、创建服务端对象
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定ip和端口
server.bind(('127.0.0.1',8080))
#3、监听
server.listen(5)
print('服务器就绪·······')
#循环等待客户端连接
while True:
clinet_data,addr = server.accept()
#创建线程
t = threading.Thread(target=clinet_info,args=(clinet_data,))
t.start()
server.close()
面向对象的静态服务器
import socket
import threading
class WebServer():
def __init__(self):
# 1、创建服务端对象
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定ip和端口
self.server.bind(('127.0.0.1', 8080))
# 3、监听
self.server.listen(5)
def clinet_request(self,clinet_data):
# 接收客户端数据
recv_data = clinet_data.recv(1024)
print(recv_data)
# 解决方案1 直接判断数据是否为空
# if len(recv_data) == 0:
# clinet_data.send('not data')
# 解决方案二 捕获数据异常 捕获到异常就结束函数的业务逻辑执行
try:
# 读取请求报文中的请求路径,根据不同的请求路径返回不同的页面
# 1、将bytes类型转为字符串
str_data = recv_data.decode()
# 2、字符串切割 按照\r\n进行切割 得到请求行 请求头请求体数据
data_list = str_data.split('\r\n')
print('切割后的列表数据', data_list)
# 3、从切割后的列表中提取请求行数据 在按照空格切割请求行数
request_line = data_list[0]
print('请求行数据', request_line)
# 4、空格切割请求路径
url_path = request_line.split(' ')[1]
print('切割数据', url_path)
except Exception as e:
print(e)
clinet_data.send('not data')
return None
# 5、根据不同的路径返回不同的页面
if url_path == '/':
file = open('./index.html', 'r', encoding='utf-8')
send_data = file.read()
file.close()
elif url_path == '/request':
# 注册页面
# 读取注册页面的信息
file1 = open('./request.html', 'r', encoding='utf-8')
send_data = file1.read()
file1.close()
else:
send_data = 'No found'
# 返回数据给客户端
# file = open('./index.html','r',encoding='utf-8')
# send_data = file.read()
# 构建报文数据
# 响应行
response_line = 'http/1.1 200 ok \r\n'
# 响应头
response_header = 'Server:python\r\n\r\n'
# 响应体
response_body = send_data
# 拼接三部分数据构成完整的响应报文
response_data = response_line + response_header + response_body
clinet_data.send(response_data.encode())
def start(self):
print('服务器就绪·······')
clinet_data, addr = self.server.accept()
# 创建线程
t = threading.Thread(target=self.clinet_request, args=(clinet_data,))
t.start()
最后 演变出我们的mini_web服务器
import socket
import threading
import pymysql
import json
class WebServer():
def __init__(self):
# 1、创建服务端对象
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定ip和端口
self.server.bind(('127.0.0.1', 8000))
# 3、监听
self.server.listen(5)
#路由列表
self.url_list = [
('/index',self.index),
('/detail',self.detail)
]
def index(self,evn):
db = pymysql.connect(user='数据库用户名', password='数据库密码', host='IP地址', database='所需使用的数据库')
# 创建对象 (游标)
cursor = db.cursor()
# 编写sql语句
sql_str = 'select * from bookinfo'
cursor.execute(sql_str)
# 获取所有的图书数据
res_data = cursor.fetchall()
data_list = []
# 需要将所有图书数据转化为字典形式进行保存
for book in res_data:
# book数据还是元组 1是id 2是书名 3是作者 4是照片 5是分组
data_list.append(
{
'id': book[0],
'name': book[1],
'auth': book[2],
'img_url': book[3],
'rank': book[4]
}
)
# 再将字典数据转化为json返回
send_data = json.dumps(data_list)
return send_data
def detail(self,evn):
query_data = evn['query_data']
db = pymysql.connect(user='数据库用户名', password='数据库密码', host='IP地址', database='所需使用的数据库')
# 创建对象 (游标)
cursor = db.cursor()
# 编写sql语句
sql_str = 'select * from bookinfo where ' + query_data
cursor.execute(sql_str)
# 获取图书数据
book = cursor.fetchone()
# 将获取的元组数据转化为字典
data_dict = {
'id': book[0],
'name': book[1],
'auth': book[2],
'img_url': book[3],
'rank': book[4]
}
# 将字典数据转化为json
send_data = json.dumps(data_dict)
return send_data
def url_route(self,evn):
#封装处理路径判断的业务逻辑
url_path = evn['url_path']
# if url_path == '/':
# #查询所有数据再返回
# send_data= self.index(evn)
#
# elif url_path == '/detail':
# #获取图书详情数据
# send_data = self.detail(evn)
# else:
# send_data = 'No found'
for url,func in self.url_list:
if url == url_path:
send_data = func(evn)
break
else:
send_data = ''
return send_data
def clinet_request(self,clinet_data):
# 接收客户端数据
recv_data = clinet_data.recv(1024)
print(recv_data)
# 解决方案1 直接判断数据是否为空
# if len(recv_data) == 0:
# clinet_data.send('not data')
# 解决方案二 捕获数据异常 捕获到异常就结束函数的业务逻辑执行
try:
# 读取请求报文中的请求路径,根据不同的请求路径返回不同的页面
# 1、将bytes类型转为字符串
str_data = recv_data.decode()
# 2、字符串切割 按照\r\n进行切割 得到请求行 请求头请求体数据
data_list = str_data.split('\r\n')
print('切割后的列表数据', data_list)
# 3、从切割后的列表中提取请求行数据 在按照空格切割请求行数
request_line = data_list[0]
print('请求行数据', request_line)
# 4、空格切割请求路径
url_path = request_line.split(' ')[1]
print('切割数据', url_path)
except Exception as e:
print(e)
clinet_data.send(b'not data')
return None
print(url_path)
#判断路径是否有问号携带的数据
url_data = url_path.split('?')
if len(url_data) > 1:
#说明路径中有问号
#重新给路径赋值
url_path = url_data[0]
#获取问号后的查询数据
query_data = url_data[1]
else:
#没有问号?数据
query_data = ''
# 5、根据不同的路径返回不同的页面
evn = {
'url_path':url_path,
'query_data':query_data
}
#接收查询后的数据
send_data = self.url_route(evn)
# 返回数据给客户端
# file = open('./index.html','r',encoding='utf-8')
# send_data = file.read()
# 构建报文数据
# 响应行
response_line = 'http/1.1 200 ok \r\n'
# 响应头
response_header = 'Server:python\r\n\r\n'
# 响应体
response_body = send_data
# 拼接三部分数据构成完整的响应报文
response_data = response_line + response_header + response_body
clinet_data.send(response_data.encode('utf8'))
def start(self):
print('服务器就绪·······')
while True:
clinet_data, addr = self.server.accept()
# 创建线程
t = threading.Thread(target=self.clinet_request, args=(clinet_data,))
t.start()
web = WebServer()
web.start()
这里面的代码 我来来回回的也改了好多 有些杂乱 最近很忙没什么时间 有什么问题 欢迎到评论区留言
拜拜