mini—web搭建

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()

这里面的代码 我来来回回的也改了好多 有些杂乱 最近很忙没什么时间 有什么问题 欢迎到评论区留言

拜拜

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值