简单的http代理服务器
一、实验说明及介绍 1. 实验简介 对于经常穿越长城的同学而言,对HTTP代理应该是很熟悉的了,有常用的goagent,**门等等,我们都会使用到代理。 代理服务器是介于浏览器和Web服务器之间的一台服务器,有了它之后,浏览器不是直接到Web服务器去取回网页而是向代理服务器发出请求,Request信号会先送到代理服务器,由代理服务器来取回浏览器所需要的信息并传送给你的浏览器。而且,大部分代理服务器都具有缓冲的功能,就好象一个大的Cache,它有很大的存储空间,它不断将新取得数据储存到它本机的存储器上,如果浏览器所请求的数据在它本机的存储器上已经存在而且是最新的,那么它就不重新从Web服务器取数据,而直接将存储器上的数据传送给用户的浏览器,这样就能显著提高浏览速度和效率。 However,我们今天实现的HTTP代理是很简单的,没有上述的大部分功能,甚至不考虑效率,我们只是将浏览器的数据请求发送到HTTP代理服务器上,然后代理服务器会将请求发送出去并将结果返回到浏览器。 2. 所需知识 我们将基于Python实现这个简单的HTTP代理服务器。以下是 Python 相关的课程,如果您不了解,建议先学习以下课程。 Python快速教程 Python编程语言 项目完整代码下载: git clone http://git.shiyanlou.com/shiyanlou/proxy 3. 知识点 本节实验将学习并实践下列知识点: Python基本语法 Socket编程 HTTP协议原理 二、 客户端 在这里就是浏览器了。当我们访问每个网站的时候,我们的浏览器都会向服务器发送请求,服务器根据我们的请求返回我们需要的数据,最后,浏览器对返回值(比如:html,css,js)做渲染,将多姿多彩的网络世界展示在我们的面前。浏览器就是最典型的网络客户端。 在使用代理前,我们可以看看浏览器发送些什么东西。 proxy-1.png 这就是HTTP header,注意在Connection: keep-alive下面是有一个空行的,用于告诉服务器请求的结束。仅仅分析这个HTTP header的内容,我们看看我们的浏览器发送了什么东西: GET:告诉了服务器的动作是什么 / :告诉服务器需要什么东西 HTTP/1.1:使用的HTTP协议版本 HOST:需要的东西在哪里获得 User-Agent:浏览器的特征 Accept:浏览器接受什么样的东西 Accept-Language:浏览器就受哪些人类语言 Accept-Encoding:浏览器能处理的压缩或编码方式 Cookie:HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 Connection: 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) HTTP Header 详解 三、服务器端 proxy-2.png 服务器返回了这些信息: 服务器端用什么版本的什么话通信(HTTP/1.1) 浏览器请求的资源是否可获得(200 OK) 还有其它细节用来表示时间,它的情况,浏览器应该怎么做,传送的消息是什么等等。 这就是HTTP响应头。一个空行之后是实际传送的数据。这里就是浏览器喜欢的html文本文件。浏览器接收后会将其解析渲染或执行对应操作。 四、建立连接 建立连接不得不提到socket。基本上,Socket 是任何一种计算机网络通讯中最基础的内容。例如当你在浏览器地址栏中输入网站地址时,你会打开一个套接字,然后连接到该网站并读取响应的页面然后然后显示出来。而其他一些聊天客户端也是大致如此。任何网络通讯都是通过 Socket 来完成的。 我们先实现一个简单的客户端和一个简单的服务器端,当这两个脚本运行起来后,我们可以在客户端输入shell命令让服务器端去执行并返回结果: 客户端: proxy-3.png 服务器端: proxy-4.png 服务器端代码: #!/usr/bin/python import socket? ?#socket模块 import commands? ?#执行系统命令模块 HOST='10.0.0.245' PORT=50007 s= socket.socket(socket.AF_INET,socket.SOCK_STREAM)? ?#定义socket类型,网络通信,TCP s.bind((HOST,PORT))? ?#套接字绑定的IP与端口 s.listen(1)? ? ? ? ?#开始TCP监听 while 1: ? ? conn,addr=s.accept()? ?#接受TCP连接,并返回新的套接字与IP地址 ? ? print'Connected by',addr? ? #输出客户端的IP地址 ? ? while 1: ? ? ? ? data=conn.recv(1024)? ? #把接收的数据实例化 #commands.getstatusoutput执行系统命令(即shell命令),返回两个结果,第一个是状态,成功则为0,第二个是执行成功或失败的输出信息 ? ? ? ? cmd_status,cmd_result=commands.getstatusoutput(data) #如果输出结果长度为0,则告诉客户端完成。此用法针对于创建文件或目录,创建成功不会有输出信息 ? ? ? ? if len(cmd_result.strip()) ==0:? ? ? ? ? ? ? ? conn.sendall('Done.') ? ? ? ? else: ? ? ? ? ? ? conn.sendall(cmd_result)? ?#否则就把结果发给对端(即客户端) conn.close()? ? ?#关闭连接 客户端代码: #!/usr/bin/python import socket HOST='10.0.0.245' PORT=50007 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)? ? ? #定义socket类型,网络通信,TCP s.connect((HOST,PORT))? ? ? ?#要连接的IP与端口 while 1: ? ? cmd=raw_input("Please input cmd:")? ? ? ?#与人交互,输入命令 ? ? s.sendall(cmd)? ? ? #把命令发送给对端 ? ? data=s.recv(1024)? ? ?#把接收的数据定义为变量 ? ? print data? ? ? ? ?#输出变量 s.close()? ?#关闭连接 先执行服务器端代码,再执行客户端代码。 五、实现 设置代理后的请求: proxy-6.png 未设置代理的请求: proxy-7.png 当我们设置代理后,请注意第一行GET后面的东西,资源路径改变了有木有! 浏览器上设置代理后,发送的请求把整个url都作为资源路径了,所以我们要把域名删掉,然后代理服务器再把修改后的请求发送给目标。 1. 对于代理服务器而言 对于代理服务器而言,它既是服务器(相对浏览器),又是客户端(相对baidu的服务器),所以代码的组织结构相对简单: 代理监听本地某个端口,设置浏览器代理设置,将浏览器的所有请求绑定到代理监听端口。(服务器端) 代理获取请求的所有数据,稍作处理后就能转发出去。(客户端) 代理接收服务器的response,并转发给浏览器。 请看代码proxy.py: 函数proxy中: sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 我们在编写的过程中,肯定是要不断的测试的,但是一个端口被使用后,我们就不能使用它了,直到系统自动释放掉(一般是几分钟),上面的设置可以,将处于TIME_WAIT状态的端口复用。 这篇文章中有详细的描述: Python 的 Socket 编程教程 函数get_header只是用于获取浏览器过来的http数据(包括http头) 函数header_parse将http头进行划分,以便更改资源路径 详细请看: 用python写一个http代(和谐)理 2. 启动代理 将opene浏览器的代理改为127.0.0.1:33333 运行脚本proxy.py 六、作业和思考 考虑如何提高代理服务器运行效率有哪些方法。 七、参考文档 本课参考以下博客文章: 用python写一个http代(和谐)理 python socket编程详细介绍 Python 中的 socket 编程 Python 的 Socket 编程教程 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |