第一次写关于技术的,可能看的人不多,骂烂的也不在少数,但是还是写一点,可能对一些人有帮助,也提高自己的写作水平,以后可以写出更好的东西来。当然我在blog里面会坚持写自己做过的东西,这起码不会误人子弟(高手直接跳过)。
是什么?
首先吹下水,告诉你什么是代理服务器(proxy)。代理服务器(Proxy),是一种特殊的网络服务,允许客户端通过它与另一个网络服务进行非直接的连接。具体过程为:客户端首先与代理服务器建立连接,接着发出一个对另外的目标服务器的文件或其它资源的连接请求,代理服务器通过与目标服务器连接或从缓存中取得请求的资源,并返回给客户端。通常在这个过程中,代理服务器可能改变客户端请求或服务器端响应的一些内容以满足各种代理需要。
为什么需要?
当我们知道什么是代理服务器之后我们就会想代理服务器能干什么?总结如下:
1、提高访问速度:代理服务器通过设置一个较大的缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
2、控制对内部资源的访问:如大学FTP,使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。暂时我还没有找到我们学校内部的代理服务器。
3、过滤内容:例如限制对特定计算机的访问,将一种语言的数据翻译成另一种语言,或是防御代理服务器两边的攻击性访问。我们很多东西都被和谐掉了,不知道代理服务器是神是鬼。
4隐藏真实IP:上网者也可以通过代理服务器隐藏自己的IP,免受攻击。当然黑客可能用这项功能来隐藏自己,让你很难找到。
5、突破内容过滤机制,访问个别过滤的网站。如果Google以后不能访问的话看来我要找个代理服务器了。现在都很多优秀的网站我都访问不了了。
怎么去做?
当我们搞清楚是什么和为什么需要时,我们就开始想怎么去做一个出来(当然有人觉得没什么意思,也就没有兴致考虑怎么去做了)。
首先我们需要知道代理服务器是怎么去完成工作的。其实很简单:
1>
获得客户端的请求
2>
转发客户端的请求
3>
获得目标服务器的响应
4>
返回target的响应
当然刚开始我们不要去考虑太多复杂的内容,我们先要将上面的功能实现了。
接着我就来代码了:
int main(int argc, char** argv)
{
cout<<"Demo HTTP Proxy Server ver. 0.1.0.0"<<endl;
cout<<"Developed by:Like Zhang"<<endl;
RunServer();
return 0;
}
主函数什么事情都没有做,就是RunServer,将服务启动。那开始看下server是怎么工作的:
文字描述(代码太多,伪码描述比较合适):
1> 准备服务器套接字,绑定套接字,让套接字在一个端口上监听
2> 然后申请N多的线程(就叫做<threadArray>),放到数组中
3> 然后就等待客户端连接到服务器上(也就是accept了),一直等……
4> 如果等到有客户端连接,那就将accept到的套接字放到响应队列(就叫做<socketBuffer>吧)中,当然由于这个队列是一个共享资源,使用互斥体保证它的安全---先加共享锁,然后将套接字放入队列,然后再释放共享锁。
5> <threadArray>里面的线程是怎样工作的呢?接下来介绍线程函数
文字描述线程函数:
1>
首先加共享锁,接着看下socketBuffer有没有东西,如果没有东西(也就是有没有客户来连接服务器)释放共享锁接着循环,如果有东西,那就将套接字弹出(记住释放共享锁),用这个套接字做事情。
2>
做什么事情呢?其实很简单,就是将客户端的请求拿过来,然后转发出去。
3>
转发出去之后接收目标服务器的响应,请求完了,转发也完了,就将套接字关掉,线程函数返回。
但是这里遇到了一些问题:怎么去找到目标服务器?怎么去接受目标服务器的响应(性能考虑)?
熟悉HTTP协议的人都是知道的,在HTTP请求中就带有请求的URL。所以我们只要解释一下客户端的请求就知道了。
而接受目标服务器的响应我们使用IO复用就行了。
讲解完毕!
看下代码:windows版本的是Like Zhang实现的,版权归他所有。这里只做交流使用,如果Like Zhang需要撤下我会撤下。
Linux版本是我实现的,没有实现IO复用,也没有Windows的快(Linux开50个线程直接卡住)。
http-proxy
功能是实现了,但是还是有很多的不足,我从以下几点描述:
1>性能:测试结果表明性能不高,特别是当客户端也是多线程实现的时候,某个意义上说这个代理服务器没有任何的性能提高和需要的价值。所以还要优化性能,主要是:内存、线程的复用IO上做优化。
2>提供的功能:就算是性能提高了,但是没有提供吸引人的功能时也没有存在的意义,所以还要提供一些实质上的功能:页面缓存、过滤信息和安全保护机制。
3>设计:如果看过代码可能知道这个东西的代码很差,如果要扩展这个东西设计还是很重要的,比如我们要加入更多的功能,将这些功能差分开再进行编码会爽很多。
性能改进建议:
1>
内存:要想实现一个高效的并发的服务器程序是需要很多的努力,在内存的管理上不能忽略,还有比如缓存页面需要大量的内存使用,如果能对内存使用上做一些努力能获得很高的性能提升。
2>
线程池:这个很重要,在线程的管理上一点都不能马虎,动态的线程管理是很有必要的,当连接少时要申请少量的线程,当用户增多,为了服务的质量要动态地去增加线程。
3>
缓存页面,前面也提到要缓存页面,可以想想如果在一点时间段很多人要访问Google的网站(比如50个)我们缓存了Google的页面我们就只要下载一次。当然加入这个功能的时候要深入的去了解下HTTP协议,比如怎么去替换掉缓存的页面,如果目标的页面更改了,我们还是要重新下载一次的。