利用Python实现极简版的静态网页Apache服务器

这一周的时间都用来写了一个极简版的静态网页的“Apache”服务器,其实写到这里我自己都笑了,因为功能实在是太简陋了,不过对于当前水平的我来说已经很不容易了,下面细说。
首先想自己实现这么些个功能,肯定不能用Python里人家写好的模块和接口,所以我选择了用socket来实现。
在这里插入图片描述

上方就是socket的一些函数接口,因为想要实现类似于Web服务器的功能,肯定要选用基于TCP协议的连接。
因为我是网络专业的学生,所以在此就不再对网络方面的东西进行过多的赘述,具体使用socket实现TCP连接的过程,就是先调用bind函数,绑定服务器端的IP地址和端口号,接着调用listen函数开始监听端口,然后调用accept函数开始等待接收请求信息,利用recv函数接收请求信息,再将回应信息用send函数返回给客户机,大概就是这么一个流程。
我是利用配置文件来控制了所需要绑定的IP地址和端口号,以及设定了一些功能的开关在配置文件里,据此,我写了两个类,一个类用来读取配置文件,并把数据存放在字典里,另一个类用来建立TCP连接并且实现具体功能。
接着就是要分析HTTP请求报文的头部来读取信息了。
在这里插入图片描述
此处是我用WireShark获取的一个HTTP协议的请求报文的头部信息,有了这个信息比对,我们就可以利用正则匹配出我们想要获取的信息。
然后就是我觉得代码里最核心的部分除了利用socket建立连接和正则获取信息外,就是对于目录的判断,HTTP协议请求报文头部的路径 / 就是不加任何URL直接访问IP地址或者域名时进入的页面,因此我们需要给一个主页面,用作主页。
我直接将正则匹配结果以字典形式输出,这样便于提取信息。我们先指定一个根路径用于存放主页,判断当请求信息中路径为 / 时,路径就指为该根路径,当不是 / 且该路径存在并是文件时,就用正则抓取到的URL加在根路径后面,然后将这个路径返回给另一个函数,接着打开文件提取信息编码后用send函数返回给客户端。
接着就是虚拟主机的问题,基于端口的虚拟主机很简单,利用端口的不同指定不同的根路径就行。但是基于主机名的虚拟主机就显得有些麻烦,先在/etc下的hosts文件中指定一些主机名,然后我们就要抓取请求信息头部中的host内容,然后进行一一判断,再指定不同的根路径。这样听起来很麻烦,其实利用配置文件的话,很快就能实现,给每一个虚拟主机下指定IP和端口及一个根路径,并且读取到字典里,根据字典内容进行判断就行。


实现了一些基本的小功能后,就要考虑一些负载的问题,毕竟我们做实验的话并没有什么访问量,但是一旦到了生产环境当中,就要面对巨大的客流量还要保证服务器不会崩塌的问题。
因为我目前的技术还比较辣鸡,所以我只想到了最小连接数的负载均衡。
因为用自己电脑做的,所以没有额外的服务器,所以我利用了requests的get方法,从别的网站抓取数据来用(当然,一些大公司的网站由于安全问题是抓不出来的,所以我这里只能抓获百度和豆瓣的主页)。接着又到了配置文件,将需要跳转的后台网页写在里面,读在字典里,然后重点来了,我将这些需要跳转的域名或者地址单独放进一个字典里,V值初始化为0,每当跳转一次就给V值+1,然后利用sorted函数对该字典的V值进行排序,再将次数最小的域名或者地址提出来进行跳转,这样算是简单地实现了该功能吧。(虽然字典的items函数抓取出来的是什么items类型,但是可以在sorted函数中利用 key=lambda x:x[1] 来对V值进行排序,但是将items函数的对象单独打出来时就不能用[0]或者[1]来输出,我想可能是在sorted内部一边遍历字典一边排序所以可以这样吧)
再一个功能就是重定向功能,其实这个我比较水,因为不会html,所以直接copy了一部分html的代码,然后自己添加一些参数就实现了。
最后一个就是访问控制功能,就是对一些指定目录拒绝访问,这个也比较好实现,又是利用配置文件,再对其字典进行比对,对应上了返回一个错误页面就OK了。
下面附上代码和我的配置文件。


程序代码
import socket
import threading
import re
from httpd.logger import longer
from pathlib import Path
import requests
import time

class server:
    def __init__(self,ip,port,dic):
        self.socket = socket.socket()
        self.iport = (ip,port)
        self.serverroot=''
        self.dic=dic
        self.client={
   }
        for k,v in dic['load balancing'].items():
            self.client[v]=0
        self.domain=''
        self.string=''
        self.event = threading.Event()

    def reg(self,bytestring):
        regx = re.compile("GET (?P<url>\S+) (?P<method>\S+)\r\nHost: (?P<host>\S+)\r\n.*")
        data = {
   }
        try:
            data = regx.match(bytestring.decode("utf-8")).groupdict()
            self.domain=data['host'].split(':')
            if self.dic['default']['VHswitch']=='ON':
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值