文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

哈工大计算机网络实验一-HTTP代理服务器的设计与实现

2023-10-24 13:46

关注

一、代理服务器原理

当客户在浏览器中设置好Proxy Server后,你使用浏览器访问所有WWW站点的请求都不会直接发给目的主机,而是先发给代理服务器,代理服务器接受了客户的请求以后,由代理服务器向目的主机发出请求,并接受目的主机的数据,存于代理服务器的硬盘中,然后再由代理服务器将客户要求的数据发给客户。

代理服务器是为了减少长距离的传送而诞生的。它不仅可以代理客户端向服务器端提出请求,也可以代理服务器传给客户端所需要的数据。

当客户端对服务器端提出请求时,此请求会被送到代理服务器,然后代理服务器会检查本身是否有客户端所需要的数据。如果有,代理服务器便代替服务器将数据传给客户端。而代理服务器一般都是设置距自己传输距离较近的某台代理服务器,所以它传数据给客户端的速度会比从远程服务器传数据要快。

如果代理服务器没有客户端所请求的数据,它会去服务器获取所需的数据。在代理服务器从服务器端取得数据传给客户端时,自己保存一份,待下次如果有用户提出相同的请求时,便可以将数据直接传过去,而不需要再去服务器端获取了。可见,代理服务器改善网络数据传输阻塞的功能是显而易见的。

本实验中代理服务器的流程图:

  • 代理服务器的配置

我们在firefox设置里查找网络代理设置,然后选择手动设置代理,适用代理服务器,并设置好地址和端口号,保存。

  • 实验实现过程

首先我们设置实验中需要用到的参数

PARAMETERS = {

    'HOST': '127.0.0.1',

    'PORT': 9999,

    'MAX_LISTEN': 50,

    'MAX_LENGTH': 4096,

    'CACHE_SIZE': 1000

}

接下来我们初始化socket并且在循环中监听指定端口,当接收到客户端的请求则创建一个新线程进行处理。其中transmission函数是代理服务器的核心函数。

# 初始化socket

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 绑定IP地址和端口号

    s.bind((PARAMETERS['HOST'], PARAMETERS['PORT']))

    # socket的排队个数

    s.listen(PARAMETERS['MAX_LISTEN'])

    # 创建cache目录

    if not os.path.exists(cache_dir):

        os.mkdir(cache_dir)

    print('初始化完成.')

    print('server将一直等待连接...')

    while True:

        # 在循环中监听9999端口,接收到客户端请求则创建一个新线程处理

        sock, address = s.accept()

        threading.Thread(target=transmission, args=(sock, address)).start()

接下来接收来自客户端的http请求报文,解码报文,获取请求行并格式化,分析字符串得到url地址,并且通过传入参数获得主机IP。

# 接受来自客户端的http请求报文

    message = so.recv(PARAMETERS['MAX_LENGTH'])

    if len(message) == 0:

        return

    message = message.decode('utf-8', 'ignore')  # 对报文进行解码,忽略错误

    request_line = message.split('\r\n')[0].split()  # 获得请求行,去掉前后空格

    url = urlparse(request_line[1])  # 获得URL

    hostIP = address[0]  # 获得主机IP

四、附加功能的部分。

用户IP是否被过滤

如果用户IP被过滤,则直接输出提示信息,然后关闭套接字并返回。

    if hostIP in Blocked_User:  # 用户IP被过滤

        print('用户 '+str(hostIP)+' 被禁止访问.')

        so.close()

        return

  1. 主机名是否禁止访问

如果主机名禁止访问,则直接输出提示信息,然后关闭套接字并返回。

    if url.hostname in No_Access_url:  # 主机名被禁止访问

        print(str(url.hostname) + ' 被禁止访问.')

        so.close()

        return

是否是钓鱼网站并且如何处理。

如果是钓鱼网站,首先输出提示信息,然后根据给定的参数重构请求报文,发送到被引导到的网站服务器,从中接收数据,转发给客户端,之后关闭套接字并返回。

    if url.hostname in fishing:  # 主机名为钓鱼网站

        print('即将从 ' + str(url.hostname) + ' 跳转到 ' + str(fishing[url.hostname]))

        new_hostname = fishing[url.hostname]  # 新的目标主机名

        message = message.replace(request_line[1], 'http://'+new_hostname+'/')

        message = message.replace(url.hostname, new_hostname)  # 将报文重构

        # print(message)

        fish_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 初始化钓鱼网站的socket

        fish_socket.connect((new_hostname, 80))  # 与钓鱼网站的服务器建立连接

        fish_socket.sendall(message.encode())  # 将报文编码发送到钓鱼网站服务器

        while True:

            # 从服务器接收数据,转发给客户端

            buff = fish_socket.recv(PARAMETERS['MAX_LENGTH'])

            if not buff:

                fish_socket.close()

                break

            so.sendall(buff)

        so.close()

        fish_socket.close()

        return

五、cache功能模块。

首先确定缓存路径和文件名,并初始化标记为未修改。

接下来进行判断,如果本地已经存在该文件,此时需要查看最后一次缓存之后网站内容是否有发生变化,并更新最后一次缓存的时间。我们通过向服务器发送报文,解析返回数据的方式进行判断。

如果返回数据的响应码为304,则表示发生未变化,直接从本地文件中读取信息发送到客户端。如果响应码不为304,则表示发生了变化,直接将标记修改为已修改。

接下来进行判断,如果本地缓存中不存在该文件或者标记为已修改,则表示需要更新缓存。向服务器发送数据,获取服务器返回的数据,并且写入到缓存中,然后将数据转发给客户端,最后关闭套接字。

当本地缓存已经存在相应文件,判断网页是否被修改时的逻辑实现:

path = cache_dir + url.hostname  # 缓存路径和文件名

    modified = False  # 第一次标记为未修改

    if os.path.exists(path):  # 当已经存在该文件,需要判断服务器是否修改过此网页

        modified_time = os.stat(path).st_mtime  # 缓存文件最后修改的时间

        headers = str('If-Modified-Since: ' + time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(modified_time)))

        # 把modified-time按报文要求格式化

        message = message[:-2] + headers + '\r\n\r\n'  # 把If-Modified-Since字段加入到请求报文中

        # 向服务器发送报文

        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        server_socket.connect((url.hostname, 80))

        server_socket.sendall(message.encode())

        data = server_socket.recv(PARAMETERS['MAX_LENGTH']).decode('utf-8', 'ignore')

        # print(data)

        server_socket.close()

        if data[9:12] == '304':  # 响应码为304,表示网页未变化,从cache中读取网页

            print('网页未更新,将从缓存中读取网页.')

            with open(path, "rb") as f:

                so.sendall(f.read())

        else:  # 网页变化,标记为已修改

            modified = True

    if not os.path.exists(path) or modified:  # 如果没有该网页的缓存或者网页已被修改

        # 向服务器发送数据,才能接收到服务器发回来的数据

        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        server_socket.connect((url.hostname, 80))

        server_socket.sendall(message.encode())

        print('更新缓存.')

        f = open(path, 'wb')  # 重写缓存

        while True:

            buff = server_socket.recv(PARAMETERS['MAX_LENGTH'])

            if not buff:

                # print(buff)

                f.close()

                server_socket.close()

                break

            f.write(buff)  # 将接收到的数据写入缓存

            so.sendall(buff)  # 将接收到的数据转发给客户端

        so.close()

实验结果:

  1. 正常情况:第一次访问hituc.hit.edu.cn,由于之前从未访问过,所以更新缓存,将缓存写入cache

缓存如下:

  1. 再次访问同一网站

为防止网站实时更新,我找到了一个较为稳定的网址www.qqkk.com,进行试验

再次访问www.qqkk.com,发现响应码为304,代理服务器从缓存中读取信息。

  1. 网站过滤

    我们设置了禁止访问的网站,将注释符号删除后运行程序,发现该网站被禁止访问。

   

  1. 用户过滤
        我们设置了Blocked_User来存储需要被过滤的用户IP地址,此时所有网站均不可访问。

    

  1. 网站重定向

   我设置了钓鱼网站的字典,将需要转发的网站转发到目的网址。

 

问题讨论:

在实现功能中网站缓存时,发现不能在缓存中显示if-modified-since 语句,后来发现是将浏览器当作server,而不是主机当作server,使用sendall函数将报文发送给主机即可在缓存中显示if-modified-since语句

心得体会:

本次实验是第一次上机实现网络协议,通过本次实验,对socket编程的过程与技术有了一个初步的了解,更加深入地理解了http协议和代理服务器的基本原理,同时也掌握了代理服务器的设计与编程的基本实现。

来源地址:https://blog.csdn.net/qq_53191991/article/details/127312764

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-服务器
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯