手动搭建服务器—Python

2023-05-16

目录

1.HTTP协议

2.HTTP请求头

3.IP地址的绑定

4.根据不同的请求返回不同的内容

5.面向对象的服务器封装

6.WSGI服务器

6.1 WSGI接口

6.2 WSGI不同路径返回不同内容

6.3 读取文件并加载返回给浏览器

6.4 方法的封装 

6.5 requests模块的使用


1.HTTP协议

HTTP协议:HyperText Transfer Protocol   超文本传输协议
协议的作用:就是用来传输超文本(HTML:HyperTextMarkupLanguage超文本标记语言)

HTML:超文本标记语言

HTTP:用来传输超文本的一个协议

C/S架构:client-server          手机淘宝APP

B/S架构:browser-server      浏览器访问淘宝

 在Web应用中,服务器把网页传给浏览器,实际上就是把网页的HTML代码发送给浏览器,让浏览器显示出来。而浏览器和服务器之间的传输协议是HTTP,所以:

  • HTML是一种用来定义网页的文本,会HTML,就可以编写网页;
  • HTTP是在网络上传输HTML的协议,用于浏览器和服务器的通信。

        Chrome浏览器提供了一套完整地调试工具,非常适合Web开发。

        安装好Chrome浏览器后,打开Chrome,在菜单中选择“视图”,“开发者",“开发者工具”,就可以显示开发者工具。

import socket

port=int(input('请输入端口号:'))
n=int(input('请输入您允许访问该网站的次数:'))
#HTTP 服务器都是基于TCP的socket连接
server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.bind(('192.168.1.223',port))
server_socket.listen(128)
print('server is running ar 192.168.1.223:{}'.format(port))
#获取到数据时一个元组
#第0个元素:客户端的socket连接
#第1个元素:客户端的ip和端口号

while n:
    n-=1
    client_socket,client_addr=server_socket.accept()

    #从客户端的socket中获取数据
    data=client_socket.recv(1024)
    print('接收到了来自{}地址{}端口号的的信息,内容是:{}'.format(client_addr[0],client_addr[1],data.decode('gbk')))

    #在返回内容之前需要设置HTTP响应头
    #设置一个响应头就换一行
    client_socket.send('HTTP/1.1 200 OK\n'.encode('gbk'))
    client_socket.send('content-type:text/html\n'.encode('gbk'))
    #所有的响应头设置完成后再换行
    client_socket.send('\n'.encode('gbk'))

    #给客户端的返回消息
    client_socket.send(client_addr[0].encode('gbk'))

运行结果: 

2.HTTP请求头

"""
#GET           请求方式,GET/POST/PUT/DELETE...
#/index.html   请求的路径
#HTTP/1.1      HTTP的版本号

GET / HTTP/1.1       
Host: 192.168.1.223:8080      #客户端请求的服务器地址
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1

#UA 用户代理,设计目的是为了能从请求头里辨识浏览器的类型
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.66 Safari/537.36 Edg/103.0.1264.44
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
"""

3.IP地址的绑定

#IP地址能够通过IP地址访问
#server_socket.bind(('192.168.1.223', 8080))
#能够通过127.0.0.1 和localhost(只有局域网内的主机才可以访问) 来访问
#127.0.0.1 和0.0.0.0都表示本机  0.0.0.0表示所有的可用的地址
server_socket.bind(('127.0.0.1', 8080))

4.根据不同的请求返回不同的内容

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_socket.bind(('127.0.0.1', 8080))

server_socket.listen(128)
print('server is running ar 192.168.1.223:{}'.format(8080))

while True:
    client_socket, client_addr = server_socket.accept()
    data = client_socket.recv(1024).decode('gbk')#浏览器发送的数据有可能是空的
    #print('接收到了来自{}地址{}端口号的的信息,内容是:{}'.format(client_addr[0], client_addr[1], data))
    path = ''
    if data:
        path=data.splitlines()[0].split()[1]#切字符串
        print('请求的路径是:{}'.format(path))

    # 响应体
    response_body = 'hello zmj!'

    # 响应头
    response_header = 'HTTP/1.1 200 OK\n'  # 200是OK状态码

    if path=='/login':
        response_body='欢迎来到登录页面!'
    elif path=='/register':
        response_body='欢迎来到注册页面'
    elif path=='/':
        response_body='欢迎来到首页'
    else:
        #页面没找到   404 Page Not Found
        response_header = 'HTTP/1.1 404 Page Not Found\n'  # 200是OK状态码
        response_body='对不起,您要查找的页面不存在!!!'

    response_header+='content-type:text/html;charset=utf8\n'
    response_header+='\n'

    #响应
    response=response_header+response_body
    #发送给客户端
    client_socket.send(response.encode('utf8'))

运行结果:

5.面向对象的服务器封装

import socket

class MyServer(object):
    def __init__(self,ip,port):
        self.socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.socket.bind((ip,port))
        self.socket.listen(128)

    def run_forever(self):

        while True:
            client_socket, client_addr = self.socket.accept()
            data = client_socket.recv(1024).decode('gbk')
            path = ''
            if data:
                path = data.splitlines()[0].split()[1]  # 切字符串

            response_body = 'hello zmj!'
            response_header = 'HTTP/1.1 200 OK\n'  # 200是OK状态码

            if path == '/login':
                response_body = '欢迎来到登录页面!'
            elif path == '/register':
                response_body = '欢迎来到注册页面'
            elif path == '/':
                response_body = '欢迎来到首页'
            else:
                response_header = 'HTTP/1.1 404 Page Not Found\n'  # 200是OK状态码
                response_body = '对不起,您要查找的页面不存在!!!'

            response_header += 'content-type:text/html;charset=utf8\n'
            response_header += '\n'

            response = response_header + response_body

            client_socket.send(response.encode('utf8'))



server=MyServer('127.0.0.1',8080)
server.run_forever()

6.WSGI服务器

6.1 WSGI接口

WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。我们来看一个最简单的Web版本的“Hello, web!”: 

def application(environ,start_response):
    start_response('200 OK',[('Content-Type','text/html')]
    return '<h1>Hello,web!</h1>'

上面的application()函数就是符合WSGI标准的一个HTTL处理函数,它接收两个参数:

  • environ:一个包含所有的HTTL请求信息的dict对象;
  • start_response:一个发送HTTP响应的函数

在application()函数中调用:start_response('200 OK',[('Content-Type','text/html')],就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。start_response()函数调用两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每个Header用一个包含两个str的tuple表示。

通常情况下,都应该把Content-Type头发送给浏览器,其他很多常用的HTTP Header也应该发送。

代码一: 

#直接使用库里面的

import webbrowser
from wsgiref.simple_server import make_server, demo_app

if __name__=='__main__':
    httpd=make_server('',8000,demo_app)
    sa=httpd.socket.getsockname()
    print('Serving HTTP on',sa[0],'port',sa[1],'...')
    webbrowser.open('http://localhost:8000/xyz?abc')
    httpd.serve_forever()

 结果:

代码二:

#自定义显示内容

import webbrowser
from wsgiref.simple_server import make_server

#demo_app需要两个参数,
#第1个参数:表示环境(电脑的环境;请求路径的相关的环境)
#第2个参数:是一个函数,用于返回响应头
#需要返回值,返回值是一个列表,列表中只有一个元素,是一个二进制,表示返回给浏览器的数据
def demo_app(environ,start_response):
    #environ 是一个字典,保存了很多数据
    #其中重要的一个是PATH_INFO能够获取到用户的访问路径
    path=environ['PATH_INFO']
    print('path={}'.format(path))

    #start_response第一个参数是状态码,第二个是响应头
    start_response('200 OK',[('Content-Type','text/html;charset=utf8')])
    return ['hello'.encode('utf8')]#浏览器显示的内容


if __name__=='__main__':
    #demo_app是一个函数,用来处理用户的请求
    #8000是一个端口号
    httpd=make_server('',8000,demo_app)
    sa=httpd.socket.getsockname()
    print('Serving HTTP on',sa[0],'port',sa[1],'...')

    #作用:打开电脑的浏览器,并在浏览器中输入'http://localhost:8000/xyz?abc'
    #也可以手动打开
    webbrowser.open('http://localhost:8000/xyz?abc')

    # 只处理一个请求,然后退出
    #httpd.handle_request()
    httpd.serve_forever()#服务器在后台一直运行

结果:

 

6.2 WSGI不同路径返回不同内容

# 状态码:RSETFUL ==>前后端分离
# 2XX:请求响应成功
# 3XX:重定向
# 4XX:客户端的错误。  404:客户端访问了一个不存在的地址  405:请求方式不被允许
# 5XX:服务器的错误。

import webbrowser
from wsgiref.simple_server import make_server

#demo_app需要两个参数,
#第1个参数:表示环境(电脑的环境;请求路径的相关的环境)
#第2个参数:是一个函数,用于返回响应头
#需要返回值,返回值是一个列表,列表中只有一个元素,是一个二进制,表示返回给浏览器的数据
def demo_app(environ,start_response):
    #environ 是一个字典,保存了很多数据
    #其中重要的一个是PATH_INFO能够获取到用户的访问路径
    path=environ['PATH_INFO']


    status_code='200 OK'#默认状态码是200
    if path=='/':
        response='欢迎来到我的首页'
    elif path=='/text':
        response='欢迎来到张梦姣的页面'
    elif path=='/demo':
        response='欢迎来到demo页面'
    else:
        response='页面走丢了!'#如果页面出问题了,
        status_code='404 Not Found'


    #start_response第一个参数是状态码,第二个是响应头
    start_response(status_code,[('Content-Type','text/html;charset=utf8')])
    return [response.encode('utf8')]#浏览器显示的内容


if __name__=='__main__':
    #demo_app是一个函数,用来处理用户的请求
    #8000是一个端口号
    httpd=make_server('127.0.0.1',8080,demo_app)#这里第一个参数是地址,空表示是'0.0.0.0'
    sa=httpd.socket.getsockname()
    print('Serving HTTP on',sa[0],'port',sa[1],'...')

    #作用:打开电脑的浏览器,并在浏览器中输入'http://localhost:8000/xyz?abc'
    #也可以手动打开
    #webbrowser.open('http://localhost:8000/xyz?abc')

    # 只处理一个请求,然后退出
    #httpd.handle_request()
    httpd.serve_forever()#服务器在后台一直运行

去掉注释的代码:

import webbrowser
from wsgiref.simple_server import make_server

def demo_app(environ,start_response):
    path=environ['PATH_INFO']

    status_code='200 OK'#默认状态码是200
    if path=='/':
        response='欢迎来到我的首页'
    elif path=='/text':
        response='欢迎来到张梦姣的页面'
    elif path=='/demo':
        response='欢迎来到demo页面'
    else:
        response='页面走丢了!'#如果页面出问题了,
        status_code='404 Not Found'

    start_response(status_code,[('Content-Type','text/html;charset=utf8')])
    return [response.encode('utf8')]


if __name__=='__main__':
    httpd=make_server('127.0.0.1',8080,demo_app)

    sa=httpd.socket.getsockname()
    print('Serving HTTP on',sa[0],'port',sa[1],'...')

    httpd.serve_forever()

 结果:

6.3 读取文件并加载返回给浏览器

import json
import webbrowser
from wsgiref.simple_server import make_server

def demo_app(environ,start_response):
    path=environ['PATH_INFO']
    #print(environ.get('QUERY_STRING'))#query_string  ==>获取到客户端GET请求方式传递的参数

    status_code='200 OK'
    if path=='/':
        response='欢迎来到我的首页'
    elif path=='/test':
        response=json.dumps({'name':'zhangsan','age':20,'gender':'male'})
    elif path=='/demo':
        with open('./pages/xxxx.txt','r',encoding='utf8') as file:
            response = file.read()
    elif path=='/hello':
        with open('./pages/hello.html', 'r', encoding='utf8') as file:
            response = file.read()
    elif path=='/info':
        #查找数据库,获取到用户名
        name='Tom'
        with open('./pages/info.html', 'r', encoding='utf8') as file:
            #flash django  模板,渲染引擎
            response = file.read().format(username=name)#读取的就是字符串
    else:
        response='页面走丢了!'#如果页面出问题了,
        status_code='404 Not Found'


    #start_response第一个参数是状态码,第二个是响应头
    start_response(status_code,[('Content-Type','text/html;charset=utf8')])
    return [response.encode('utf8')]#浏览器显示的内容


if __name__=='__main__':
    httpd=make_server('127.0.0.1',8080,demo_app)
    sa=httpd.socket.getsockname()
    print('Serving HTTP on',sa[0],'port',sa[1],'...')

    httpd.serve_forever()#服务器在后台一直运行

hello.html文件里面的内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .box{
            margin:0 auto;
        }
        .div{
            width:1000px;
        }
        .top{
            height:80px;
            background-color:red;
            margin-bottom:10px;
        }
        .middle{
            height:400px;
        }
        .left{
            width:100px;
            height:100%;
            background-color:yellow;
            float:left;
            margin-right:10px;
        }
        .content{
            width:970px;
            height:100%;
            background-color:pink;
            float:left;
            margin-right:10px;
        }
        .right{
            width:100px;
            height:100%;
            background-color:blue;
            float:right;
        }
        .bottom{
            height:80px;
            background-color:lime;
            margin-top:10px;
        }
    </style>
</head>
<body>
<div class="box">
        <div class="middle">
        <div class="left"></div>
        <div class="content"></div>
        <div class="right"></div>
    </div>
    <div class="bottom"></div>
</div>

</body>
</html>

info.html文件里面的内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{username},欢迎回来,
</body>
</html>

前端结果:

 

 

6.4 方法的封装 

import json
import webbrowser
from wsgiref.simple_server import make_server


def load_html(file_name):
    try:
        with open('./pages/'+file_name,'r',encoding='utf8') as file:
            content=file.read()
            return content
    except FileNotFoundError:
        print(file_name,'文件没找到!')

def index():
    return '欢迎来到我的首页'

def show_test():
    return json.dumps({'name':'zhangsan','age':20,'gender':'male'})

def show_demo():
    return load_html('xxxx.txt')

def show_hello():
    return load_html('hello.html')

def show_info():
    # 查找数据库,获取到用户名
    name = 'Tom'
    return load_html('info.html').format(username=name)

url={'/':index,
     '/test':show_test,
     '/demo':show_demo,
     '/info':show_info,
     '/hello':show_hello()
}
def demo_app(environ,start_response):
    path=environ['PATH_INFO']
    status_code='200 OK'
    method=url.get(path)
    if method:
        response=method()
    else:
        response = '页面走丢了!'  # 如果页面出问题了,
        status_code = '404 Not Found'
    start_response(status_code,[('Content-Type','text/html;charset=utf8')])
    return [response.encode('utf8')]

if __name__=='__main__':
    httpd=make_server('127.0.0.1',8000,demo_app)
    sa=httpd.socket.getsockname()
    print('Serving HTTP on',sa[0],'port',sa[1],'...')

    httpd.serve_forever()

6.5 requests模块的使用

作用就是模拟浏览器,获取请求的功能。 

#requests模块是第三方的模块,可以用来发送网络连接
import requests
response=requests.get('http://127.0.0.1:8000')#注意:这个路径需要写http
print(response)#<Response [200]> ==> 结果是一个Response对象
print(response.content.decode('utf8'))#"欢迎来到我的首页" ==> 获取的内容,返回的是一个二进制(可以用来传递图片),需要decode
print(response.text,'  类型:',type(response.text))#'欢迎来到我的首页'  ==> 结果就是字符串,不需要decode
print(response.status_code)#200  ==> 获取状态码

#若果返回的结果是json串,就用这个解析
#print(response.json())#json的返回类型不是字符串,而是原数据类型

运行结果:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

手动搭建服务器—Python 的相关文章