server(3)

2018-01-28  本文已影响0人  马梦里

两个亮点:

server.py

import socket
import urllib.parse
from utils import log
from routes import route_static
from routes import route_dict

class Request(object):
    def __init__(self):
        self.method = 'GET'
        self.path = ''
        self.query = {}
        self.header = ''
        self.body = ''

    def form(self):
        body = urllib.parse.unquote(self.body)
        args = body.split('&')
        f = {}
        for arg in args:
            k, v = arg.split('=')
            f[k] = v
        log('form() 字典', f)
        return f

    def header_dict(self):
        header = self.header
        header_list = header.split('\r\n')
        h = {}
        for ele in header_list:
            (k, v) = ele.split(':')
            h[k] = v
        return h

解析请求行,存储请求数据

def error(code=404):
    e = {
        404: b'HTTP/1.1 404 NOT FOUND\r\n\r\n<h1>NOT FOUND</h1>',
    }
    return e.get(code, b'')

def parsed_path(path):
    index = path.find('?')
    if index == -1:
        return path, {}
    else:
        path, query_string = path.split('?', 1)
        args = query_string.split('&')
        query = {}
        for arg in args:
            k, v = arg.split('=')
            query[k] = v
        return path, query

def response_for_path(path):
    path, query = parsed_path(path)
    request.path = path
    request.query = query
    r = {
        '/static': route_static,
    }
    r.update(route_dict)
    response = r.get(path, error)
    return response(request)

这个是根据解析的路径分发路由

import _thread

def run(host='', port=3000):
    with socket.socket() as s:
        s.bind((host, port))
        s.listen()
        while True:
            connection, address = s.accept()
            _thread.start_new_thread(process_request, (address, connection))

def process_request(address, connection):
    r = connection.recv(1024)
    r = r.decode()
    if len(r) > 0:
        request = Request()
        header, request.body = r.split('\r\n\r\n', 1)
        h = header.split('\r\n')
        parts = h[0].split()
        request.header = h[1:]
        path = parts[1]
        request.method = parts[0]
        response = response_for_path(path)
        connection.sendall(response)
    else:
        log('接收到了一个空请求')
    connection.close()

if __name__ == '__main__':
    config = dict(
        host='127.0.0.1',
        port=3000,
    )
    run(**config)

routes.py

from utils import log
from models import Message
from models import User

message_list = []

def template(name):
    path = 'templates/' + name
    with open(path, 'r', encoding='utf-8') as f:
        return f.read()

def route_index(request):
    header = 'HTTP/1.1 210 VERY OK\r\nContent-Type: text/html\r\n'
    body = template('index.html')
    r = header + '\r\n' + body
    return r.encode()

def route_login(request):
    header = 'HTTP/1.1 210 VERY OK\r\nContent-Type: text/html\r\n'
    if request.method == 'POST':
        form = request.form()
        u = User.new(form)

        if u.validate_login():
            result = '登录成功'
        else:
            result = '用户名或者密码错误'
    else:
        result = ''
    body = template('login.html')
    body = body.replace('{{result}}', result)
    r = header + '\r\n' + body
    # 有中文的时候最好用 utf-8 进行编码
    return r.encode(encoding='utf-8')

def route_register(request):
    header = 'HTTP/1.1 210 VERY OK\r\nContent-Type: text/html\r\n'
    if request.method == 'POST':
        form = request.form()
        # 将表单提交的数据数实例化,也就是将字典变为属性
        u = User.new(form)
        if u.validate_register():
            u.save()
            #log('u的id为:', u.id)
            result = '注册成功<br> <pre>{}</pre>'.format(User.all())
        else:
            result = '用户名或者密码长度必须大于2'
    else:
        result = ''
    body = template('register.html')
    body = body.replace('{{result}}', result)
    r = header + '\r\n' + body
    return r.encode(encoding='utf-8')


def route_message(request):
    log('本次请求的 method', request.method)
    if request.method == 'POST':
        data = request.form()
    else:
        data = request.query

    if len(data) > 0:
        msg = Message.new(data)
        log('post', data)
        # 应该在这里保存 message_list
        message_list.append(msg)

    header = 'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n'
    body = template('html_basic.html')
    ms = '<br>'.join([str(m) for m in message_list])
    body = body.replace('{{messages}}', ms)
    r = header + '\r\n' + body
    return r.encode()

def route_static(request):
    filename = request.query.get('file', 'doge.gif')
    path = 'static/' + filename
    #  通过Content-Type指定传输文件类型(比较松散)
    with open(path, 'rb') as f:
        header = b'HTTP/1.1 200 OK\r\nContent-Type: image/gif\r\n'
        r = header + b'\r\n' + f.read()
        return r

route_dict = {
    '/': route_index,
    '/login': route_login,
    '/register': route_register,
    '/messages': route_message,
}

多线程
单线程:不处理完当前请求,就无法处理下一个请求,也就是一次处理一个链接。
每个程序(qq/知乎)是一个进程,相当于一条大马路,这个大马路有很多车道,那么就是每个进程有很多线程,进程的子线程崩溃了不会导致这个主进程崩溃。

上一篇下一篇

猜你喜欢

热点阅读