静态服务器、动态服务器及框架

静态服务器
‘’‘这个程序实现的是一个静态服务器’’’

import socket
import re
def main():
    '''主函数,实现逻辑'''
    server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    server_socket.bind(('',8080))
    server_socket.listen()
    while True:
        handler_socket,address = server_socket.accept()
        data = handler_socket.recv(1024).decode() #字节流文件--字符串
        print(data)
        request_datas_list = data.split('\r\n')
        print(request_datas_list)
        first_line = request_datas_list[0]
        ret = re.search('GET (/.*?) HTTP/1.1',first_line)
        # 判断是否有ret值,如果没有,说明是一个非法请求
        if not ret:
            handler_socket.close()
            return
        request_path = ret.group(1)
        print('**********************')
        '''
        HTTP/1.1 状态码 说明\r\n
        Headername1:header_value\r\n
        Headername2:header_value\r\n
        Headername3:header_value\r\n
        \r\n
        Response_body 响应体,就是数据,网页、图片、文本
        '''
        responseHeader = 'HTTP/1.1 200 ok123\r\n'
        responseHeader += '\r\n'
        if request_path == '/':
            responsebody = 'hello world!'
        elif request_path == '/index.html':
            with open('index.html') as f:
                response_data = f.read()
            responsebody = response_data
        elif request_path == '/login.html':
            with open('login.html') as f:
                responsebody = f.read()

        else:
            with open('err.html') as f:
                responsebody = f.read()
            reponse = responseHeader+responsebody
        handler_socket.send(reponse.encode('gbk'))



if __name__ == '__main__':
    main()

动态服务器

import socket
import chardet
import multiprocessing
import sys


class HttpServer(object):
    def __init__(self,port,app):
        # 创建服务器套接字
        # 1、浏览器与服务器进行链接
        self.sever_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sever_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)#关闭端口
        self.sever_socket.bind(('', port))
        self.sever_socket.listen()
        self.response_data = None # 响应报文的数据(除了响应体之外的内容)
        self.app = app


    def handler_client(self,client_server_socket):
        '''人工客服处理客户端的请求'''
        # 3、浏览器向服务器发送请求报文,服务器接收报文,报文是二进制
        data = client_server_socket.recv(1024).decode()
        # print(data)
        ret_list = data.split('\r\n')
        for obj in ret_list:
            print(obj)
        print('##############分割########################')
        # data是接收到的浏览器请求报文,并且是二进制文件,
        # 4、服务器根据浏览器发送的报文返回具体的响应
        # todo:  开始拼接的响应报文
        # todo:截取请求的路径,获取请求的具体内容,根据路径的不同,返回不同的数据
        # 4.0 获取请求报文的第一行,并且获取到路径
        request_first_line = ret_list[0]
        fistline_list = request_first_line.split(' ')
        print(fistline_list)
        try:
            request_path = fistline_list[1]
        except:
            request_path = '/'
        print(request_path)

        environ ={'path':request_path}
        if request_path.endswith('.py'):
            #交给动态资源处理框架去做
            # 第一步调用框架的接口
            response_body = self.app(environ,self.start_response)
            data = self.response_data + response_body
            client_server_socket.send(data.encode('gbk'))
            client_server_socket.close()
        else:
            # 静态资源处理
        # 根据路径,获取对应的数据
            if request_path == '/':
                status_code = '200 ok'
                with open('index.html') as f:
                    responsebody = f.read()

            elif request_path == '/login':
                status_code = '200 ok'
                with open('login.PNG', 'rb') as f:
                    responsebody = f.read()

            else:
                status_code = '404 not found'
                with open('err.html') as f:
                    responsebody = f.read()

            # 4.1 拼接第一行的数据HTTP/1.1 状态码 说明\r\n
            first_line = 'HTTP/1.1' + status_code + '\r\n'
            first_line += 'name:server\r\n'
            first_line += 'data:html\r\n'
            first_line += '\r\n'

            # 判断response的数据类型,进行和响应头的拼接,响应头是一个普通字符串
            try:
                chardet.detect(responsebody)
            except:
                response = first_line + responsebody
                response = response.encode('gbk')  # 凭借完成之后,直接编码
            else:
                # 说明试错语言没有问题,responsebody是一个二进制文件
                response = first_line.encode() + responsebody

            client_server_socket.send(response)
            # 5、人工客服完成任务之后被销毁
            client_server_socket.close()
            # 6、服务器套接字一般不会关闭

    def start(self):
        # 开始创建人工客服
        while True:
            # 2、在三次握手完成之后,为客户端套接字创建客服
            # accept 是指从三次握手完成的队列中取出客户端套接字,为他创建人工客服
            client_server_socket, addressinfo = self.sever_socket.accept()
            pro = multiprocessing.Process(target=self.handler_client, args=(client_server_socket,))
            pro.start()

    def start_response(self,status,header_list):
        '''
        这个函数实现的是拼接响应报文,遵循的还是响应报文的格式,请求动态资源的时候需要调用的
        :param status: 状态码 例如:'200 ok'
        :param header_list: 列表 例如[(server,wsgisever),(name,guazi)]
        :return:
        HTTP/1.1 状态码 说明\r\n
        server:WSGI\r\n
        name:guazi\r\n
        \r\n
        Response_body 响应体,就是数据,网页、图片、文本
        '''
        response_header_firstline = 'HTTP/1.1 %s\r\n'%status
        reponse_header = ''
        for header_key,header_value in header_list:
            reponse_header += ('%s:%s\r\n'%(header_key,header_value))

        self.response_data = response_header_firstline + reponse_header + '\r\n'







def main():
    '''实现主要的逻辑'''
    print('此时获取的参数列表',sys.argv)
    try:
        # 获取命令行参数
        port = int(sys.argv[1])
        kuangjia_name = sys.argv[2]
        print(kuangjia_name)
    except:
        # print('参数缺少')
        # return
        # 如果出现参数的获取失败问题,直接赋值默认值
        port = 8080

    finally:
        # 不管正确还是错误,都要进入的分支,启动服务器
        jiekou_list = kuangjia_name.split(':')
        # 这一步获取需要导入的框架已经使用的接口的名字,进行切分,获取的是一个列表
        modle_name = jiekou_list[0] # 框架的名字
        app_name = jiekou_list[1] # 接口的名字


        # 进行模块的导入以及接口的导入,app是指接口的引用,之所以用__import__,是因为获取的框架的名字是一个字符串
        kuangjia_obj = __import__(modle_name)
        app = getattr(kuangjia_obj,app_name)


        server_obj = HttpServer(port=port,app=app)
        server_obj.start()






if __name__ == '__main__':
    main()

app框架

'''此文件实现的是应用程序框架'''
# WSGI接口
def app(environ,start_response):
    '''
    :param environ: 跟HTTP请求相关的数据(用户的请求路径,用户的请求头),字典
    :param start_response:函数引用(由服务器提供),作用:设置状态和响应头
    start_reponse这个方法:设置状态和响应头,这个函数有两个参数,第一个参数表示状态,第二个表示响应的头部(类型:列表),写在服务器上,但是框架上调用
    :return:
    '''
    print('environ:',environ)
    start_response('200 ok',[('server','wsgisever'),('name','guazi')])
    return 'hello world from WSGI'

你可能感兴趣的:(python学习)