HTTP服务器开发项目(Python)

完整源代码 https://github.com/skyerhxx/HttpServer

 

简易HTTP服务器开发项目

开发环境

      Python 3.7

      IDE:Pycharm

功能

  • 能访问 127.0.0.1:9999
  • 能访问 127.0.0.1:9999/index.html
  • 能够用户名和密码登录127.0.0.1:9999/index.html,然后页面会自动跳转到另一个页面

 

最终项目目录结构

 

http服务器是用到了TCP协议和HTTP协议
http server是在TCP server的基础上加了一些功能,这也正好对应了HTTP协议是TCP协议的上层

 

我们说的Web服务器就是HTTP服务器

 

 

 

传输层TCP协议

https://blog.csdn.net/hxxjxw/article/details/105896043

 

面向TCP协议的套接字服务端编程

实现TCPServer和StreamRequestHandler

 

实现网络服务器TCPServer类

初始化 服务器地址、处理请求类、套接字

启动服务器
    接受请求
    处理请求
    关闭连接

关闭服务器

socket_server.py

#实现TCPServer类

import socket

class TCPServer:

    def __init__(self,server_address,handler_class):
        self.server_address = server_address
        self.HandlerClass = handler_class #处理请求的类
        self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.is_shutdown = False
    
    #服务器的启动函数
    def serve_forever(self):
        self.socket.bind(self.server_address) #绑定服务器地址
        self.socket.listen(10) #启动并监听
        #while True:
        while not self.is_shutdown:
            #1.接收请求
            request, client_address = self.get_request() 
            #2.处理请求
            try:
                self.process_request(request, client_address)
            except Exception as e:
                print(e)
            finally:
                #3.关闭连接
                self.close_request(request)
        

    #接受请求
    def get_request(self):
        return self.socket.accept()

    #处理请求
    def process_request(self, request, client_address):
        handler = self.HandlerClass(request, client_address)
        handler.handle()


    #关闭请求 
    def close_request(self,request):
        request.shutdown()
        request.close()
    
    #关闭服务器
    def shutdown(self):
        self.is_shutdown = True

 

实现网络请求处理器Handler类

转换字节码用一个bytes()就行了

缓存是一个自己定义的list

 

base_handler.py

# -*- encoding=utf-8 -*-


class BaseRequestHandler:
    def __init__(self, server, request, client_address):
        self.server = server
        self.request = request
        self.client_address = client_address

    def handle(self): #不需要做任何工作,主要由后面继承它的类去做相关工作
        pass

#功能:编码、解码、读写消息
class StreamRequestHandler(BaseRequestHandler):

    def __init__(self, server, request, client_address):
        BaseRequestHandler.__init__(self, server, request, client_address)

        self.rfile = self.request.makefile('rb')
        self.wfile = self.request.makefile('wb')
        self.wbuf = []

    # 编码
    # 字符串—>字节码
    def encode(self, msg):
        if not isinstance(msg, bytes):  #如果不是字节码就编码成字节码
            msg = bytes(msg, encoding='utf-8')
        return msg

    # 解码
    # 字节码—>字符串
    def decode(self, msg):
        if isinstance(msg, bytes):
            msg = msg.decode()
        return msg

    # 读消息
    def read(self, length):
        msg = self.rfile.read(length)
        return self.decode(msg)

    # 读取一行消息
    def readline(self, length=65536):  #65536是http请求报文的最大长度
        msg = self.rfile.readline(length).strip()
        return self.decode(msg)

    # 写消息
    #接受内容,然后写到缓存里面
    def write_content(self, msg):
        msg = self.encode(msg)  #把字符串转成字节码
        self.wbuf.append(msg)

    # 发送消息
    def send(self):
        for line in self.wbuf:
            self.wfile.write(line)
        self.wfile.flush()
        self.wbuf = []  #发送完之后清空缓冲区

    def close(self):
        self.wfile.close()
        self.rfile.close()

编写网络服务器的测试用例

测试前面实现的TCPServer和Handler是否可以正常工作

编写客户端来连接服务端,测试服务端是否可以正常工作

 

改进成多线程

 

此时项目结构

 

应用层HTTP协议

https://blog.csdn.net/hxxjxw/article/details/105896043

 

HTTP服务器实现

实现一个支持HTTP协议的Web服务器

Handler才是真正处理HTTP请求的处理的类

 

实现BaseHTTPRequestHandler

继承base_handler

HTTP请求报文格式

base_http_handler.py


import logging


from handler.base_handler import StreamRequestHandler

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')

class BaseHTTPRequestHandler(StreamRequestHandler):

    def __init__(self, server, request, client_address):
        self.method = None
        self.path = None
        self.version = None
        self.headers = None
        self.body = None
        StreamRequestHandler.__init__(self,server, request, client_address)

    #请求的处理
    def handle(self):
        try:
            #1、解析请求
            if not self.parse_request():
                return
            #2、方法执行(GET、POST)
            method_name = 'do_' + self.method
            #自检判断方法是否存在
            if not hasattr(self,method_name):
                #发送错误
                return
            method = getattr(self,method_name)
            method() #应答报文的封装
            #3、发送结果
            self.send()
        except Exception as e:
            logging.exception(e)


    #解析请求头
    def parse_headers(self):
        #请求头是以key:value的形式存在的
        headers = {}
        while True:
            line = self.readline()
            #如果是空行,表示请求头已经结束
            if line:
                key,value = line.split(":",1)  #这个1是分割次数,就是指分割一次
                key = key.strip()
                value = value.strip()
                #将key,value保存到map中
                headers[key] = value
            else:
                break
        return headers


    #解析请求
    def parse_request(self):
        #1、解析请求行
        #读取第一行————请求行
        first_line = self.readline()
        words = first_line.split()
        #请求方法、请求地址、请求的HTTP版本
        self.method, self.path, self.version = words

        #2、解析请求头
        self.headers = self.parse_headers()

        #3、解析请求内容
        #如果请求头有内容,那么它的长度将会保存在headers里面
        key = 'Content-Length'
        if key in self.headers.keys():
            #请求内容的长度
            body_length = int(self.headers[key])
            self.body = self.read(body_length)

        return True

 

HTTP应答报文

 

编写基础HTTP服务器测试工作,测试其是否正常工作

新建base_http_server.py

在原来的test.py的基础上

 

 

此时,用浏览器访问localhost:9999

 

添加了个do_GET方法

可以看到这些我们写的内容都能正常返回

 

到目前为止,我们已经把一个基础的web服务器搭建起来了,这个服务器可以

具备这三个功能,一个基础的web服务器就已经实现了,我们项目的目的也已经达到了

此时的目录结构

 

即HttpServer4就是一个可以实现基本功能的http服务器了

 

-----------------------------------------------------------------------------------------------------------------------

 

但是为了更好的理解GET方法以及POST方法的工作原理

我们来编写自定义HTTP应用之GET方法和POST方法

编写自定义HTTP应用之GET方法

web服务器是怎样把html页面以及图片返回给浏览器的,以及怎样进行账号和密码的校验

我们来看webserver是怎样把资源/数据返回给浏览器的

新建simple_http_handler.py

 

编写测试用例,看是否可用

新建simple_http_server.py

 

如果请求一个不存在的资源

GET方法
首先判断资源是否存在
不存在直接返回404,存在的话,首先把资源的文件打开,读取文件的长度,写到头部,再把内容读取出来,写到缓冲区。就是一行一行的读。返回浏览器之所以能成网页的界面是因为要读取的那个文件就是html的,http服务器并没有怎么处理

 

编写自定义HTTP应用之POST方法

POST就是提交数据到服务器端进行处理,这里以账号密码为例

来看数据提交到后台之后,后台是怎么来处理的

提交是用js来提交的

正确的用户名密码是 hxx  123456

给他设置的是登录成功后会自动跳转到我的博客

如果是错误的

 

至此,项目完结

此时项目结构

 

 

未来可以增添的功能

功能方面

①更完善的异常处理机制

      状态码只利用了404状态码,还有很多其他的没有用

②更丰富的功能支持

    日志、长连接、https安全协议

性能方面

①引入线程池

      否则频繁创建和销毁线程会对性能造成一定的影响

②不使用多线程

      用事件驱动引擎(epoll、select),改造成事件驱动的web服务器

 

 

 

参考:

https://www.imooc.com/learn/1172

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值