IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 哈工大计算机网络实验一-HTTP代理服务器的设计与实现 -> 正文阅读

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

一、代理服务器原理

当客户在浏览器中设置好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

四、附加功能的部分。

1. 用户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

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

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

??? 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协议和代理服务器的基本原理,同时也掌握了代理服务器的设计与编程的基本实现。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 21:53:47  更:2022-10-22 21:54:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:53:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码