面向对象封装的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 条评论
登录 后参与评论

相关文章

来自专栏前端杂谈

通过核心概念了解webpack工作机制

34080
来自专栏前端小叙

vue报错集锦

1、vue报错: 没安装 less-loader css-loader style-loader        可能的很大原因:没安装less 2、vuex报错...

45860
来自专栏北京马哥教育

用 Python 脚本实现对 Linux 服务器的监控

目前 Linux 下有一些使用 Python 语言编写的 Linux 系统监控工具 比如 inotify-sync(文件系统安全监控软件)、 glances(资...

64460
来自专栏大史住在大前端

express中间件系统的基本实现

一直觉得express的中间件系统这种流式处理非常形象,就好像加工流水线一样,每个环节都在针对同一个产品的不同部分完成自己的工作,最后得到一个成品。今天就来实现...

18150
来自专栏北京马哥教育

25个shell脚本代码分享,日常工作够用了

引言 自己写了一下小的shell实例,虽然很小,但所有的大的程序都是由小的模块堆积起来的。 程序员一定要懂得一种脚本的书写,而我,只会在linux下工作,所以...

447110
来自专栏程序员同行者

django权限管理(Permission)

1.4K40
来自专栏Aloys的开发之路

javadoc相关问题

欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinn...

12550
来自专栏北京马哥教育

rsync - Linux下进行文件同步命令

rsync是Linux下进行文件同步到一个命令,可以同步两台计算机到文件与目录,利用查找文件中到不同块以减少数据传输。也可以在一台电脑到不同目录间同步,比如可以...

60560
来自专栏码匠的流水账

java9迁移注意事项

1、代码不模块化,先迁移到jdk9上,好利用jdk9的api 2、代码同时也模块化迁移

19810
来自专栏黑泽君的专栏

用gcc编译c语言程序以及其编译过程

对于初学c语言编程的我们来说,学会如何使用gcc编译器工具,对理解c语言的执行过程,加深对c语言的理解很重要!!!

18210

扫码关注云+社区

领取腾讯云代金券