专栏首页python成长之路面向对象封装的web服务器

面向对象封装的web服务器

import socket
import re
import os
import sys

# 由于前面太繁琐,可以用类封装一下,也可以分几个模块
class HttpServer(object):

    def __init__(self,port):
        # 1、服务器创建负责监听的socket
        self.socket_watch = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 2、设置地址重用
        self.socket_watch.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 3、绑定监听的端口
        self.socket_watch.bind(('', port))
        # 4、设置监听队列
        self.socket_watch.listen(128)

    def handle_client(self,socket_con):
        """
         接收来自客户端的请求,并接收请求报文,解析,返回
        """
        # 1、服务器接收客户端的请求报文
        request = socket_con.recv(4096).decode()

        # 2、截取请求报文,获取请求行
        request_lines = request.split("\r\n")
        # 3、获取请求行
        request_line = request_lines[0]
        # GET /a/ab/c.html HTTP/1.1
        # 通过正则表达式 匹配出请求行中请求资源路径
        res = re.match(r"\w+\s+(\S+)",request_line)
        # 获取资源路径
        path = res.group(1)
        # 将资源路径和我的web文件夹的绝对路径拼接(自己填写)
        path ="# 本地绝对路径" + path
        # 在判断是文件还是文件夹之前,首先要判断你这个路径在服务器中是否存在
        if not os.path.exists(path):
            response_line = 'HTTP/1.1 404 Not Found\r\n'
            response_head = 'Server:skylark 2.0\r\n'
            response_head += 'Content-type:text/html;charset=utf-8\r\n'
            response_body = '你请求'+ path +'不存在'
            response = response_line + response_head + '\r\n' +response_body
            socket_con.send(response.encode())
            socket_con.close()
            return
        else:
            # 判断用户请求的是文件还是文件夹
             if os.path.isfile(path):
                 # 如果文件存在 读取页面数据,然后返回
                response_line = "HTTP/1.1 200 OK\r\n"
                response_head = "Server:skylark 2.0\r\n"
                # 注意请求图片需要使用"rb"的方式进行读取
                file = open(path,"rb")
                # response_body 是二进制所以不用再次编码
                response_body = file.read()
                response = response_line.encode() + response_head.encode() +"\r\n".encode() +response_body
                socket_con.send(response)
                socket_con.close()
                return
             else:
                if path.endswith("/"):
                    # 例如 www.baidu.com/images
                    # 用户请求的文件夹
                    # 1、判断该文件夹下是否有默认的文件,如果有,则返回,如果没有
                    # index.html default.html
                    default_document = False
                    # 如果允许你访问我目录下的默认文档
                    if default_document:
                        # 判断用户访问的文件夹下是否有index.html 或者 default.html
                        if os.path.exists(path + '/index.html'):
                            response_line = 'HTTP/1.1 200 OK\r\n'
                            response_head = 'Server:skylark 2.0\r\n'
                            file = open(path+'/index.html', 'rb')
                            response_body = file.read()
                            response = response_line.encode() + response_head.encode() +'\r\n'.encode()+response_body
                            socket_con.send(response)
                            socket_con.close()
                            return
                        elif os.path.exists(path + '/default.html'):
                            response_line = 'HTTP/1.1 200 OK\r\n'
                            response_head = 'Server:skylark 2.0\r\n'
                            file = open(path + '/default.html', 'rb')
                            response_body = file.read()
                            response = response_line.encode() + response_head.encode() + '\r\n'.encode() + response_body
                            socket_con.send(response)
                            socket_con.close()
                            return
                        else:
                            # 访问的目录下,既没有index.html 也没有default.html
                            response_line = 'HTTP/1.1 404 Not Found\r\n'
                            response_head = 'Server:skylark 2.0\r\n'
                            response_head += 'Content-Type:text/html;charset=utf-8\r\n'
                            response_body = 'index.html 或者 default.html 不存在'
                            response = response_line +response_head +'\r\n' +response_body
                            socket_con.send(response.encode())
                            socket_con.close()
                        # 2、判断服务器是否开启了目录浏览
                    else:
                        # 判断你是否开启了目录浏览
                        dir_browsing = True
                        if dir_browsing:
                            # 把用户请求的文件夹中所有的文件和文件夹以目录的形式返回到页面中
                            # 获取用户请求的文件夹
                            list_names = os.listdir(path)
                            response_line = 'HTTP/1.1 200 OK\r\n'
                            response_head = 'Server:skylark 2.0\r\n'
                            # 动态的拼接页面,将目录中的文件或者文件夹的名称以HTML页面的方式返回给浏览器
                            response_body = '<html><head><body><ul>'
                            for item in  list_names:
                                response_body +="<li><a href = '#'>"+item+"</a></li>"
                            response_body+='</ul></body></head></html>'
                            response =response_line + response_head +'\r\n' +response_body
                            socket_con.send(response.encode())
                            socket_con.close()
                            return

                else:
                    # 用户请求的路径没有斜线
                    # 重定向到+斜线的目录下
                    response_line = 'HTTP/1.1 302 Found\r\n'
                    response_head = 'Server:skylark 2.0\r\n'
                    response_body = 'redirect'+ path +'/'
                    response = response_line +response_head +'\r\n' +response_body
                    socket_con.send(response.encode())
                    socket_con.close()

    def run_server(self):
        # 5、通过循环,不停的接收来自客户端的连接请求
        while True:
            socket_con, con_adds = self.socket_watch.accept()
            # 注意将con_adds转成字符串
            print('客户端:%s连接成功!!!' % str(con_adds))
            # 接收来自客户端的请求,并接收请求报文,解析,返回
            self.handle_client(socket_con)

def main():
    # sys.argv方法的用法如下:
    # 在终端输入 python3 面向对象封装的web服务器.py 8888
    # 在使用解释器执行任意py文件的时候,可以传入不止一个参数,会以字符串的形式用列表保存起来
    # 但是列表的第一个参数[0]位是它自己。所以传入的参数是从[1]第二位开始的
    # 所以在上面输入8888以后,调取这个列表的[1]下标就会传入这个8888作为进到下面的代码
    # 再转换一下类型为int就相当于用户指定端口了
    port = int(sys.argv[1])
    http_server = HttpServer(port)
    http_server.run_server()


if __name__ == '__main__':
    main()

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 返回用户指定页面的web服务器

    skylark
  • 返回固定数据的web服务器

    skylark
  • 返回固定页面的web服务器

    skylark
  • 返回用户指定页面的web服务器

    skylark
  • Response响应

    在去发送一个请求时,先会找到主机服务器再找到对应的Service,找到Servoce对应的引擎

    木瓜煲鸡脚
  • Java 通过网络流转发文件到浏览器

    本文由 小马哥 创作,采用 知识共享署名4.0 国际许可协议进行许可 本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名

    IT小马哥
  • Laravel 如何优雅的实现输出结构统一的功能?

    一般的项目需求都会要求统一的输出结构,特别是对于api应用而言。因此,如果有beforeResponse的功能,则可以在数据输出之前对response进行统一格...

    写PHP的老王
  • 爬爬更健康

    爬取淘宝商品的信息,数据主要用于分析市场趋势,从而制定一系列营销方案。实现功能如下:

    公众号---人生代码
  • IOS Alamofire使用Post获取数据

    用户5760343
  • IOS Alamofire使用get获取数据

    用户5760343

扫码关注云+社区

领取腾讯云代金券