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

本文介绍如何从零开始构建一个Web动态服务器,包括服务器的工作原理、动态服务器的实现方式及使用WSGI协议。此外,还提供了具体的Python代码示例,演示如何创建一个简单的Web框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,介绍

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值