您的位置:首页 >资讯列表 > 正文
发布时间:2020-04-21 16:57
HTTP代理服务器的系统结构和工作流程

  在本章首先介绍HTTP无线宽带代理软件的设计目标,然后根据系统的设计目标得出了系统的整体设计方案,后给出了HTTP代理服务器的系统结构和工作流程。


  2.1系统的设计目标


  为了提供大规模的高速Internet接入服务,应用于3.5G无线宽带的HTTP代理服务器的实现要达到以下目标:


  1)高性能


  高性能即能为大规模的用户群提供高速接入Internet的服务,能同时接收多个并发用户的请求,并且处理这些请求或将它们转发给远程目标服务器,不因为某个客户或者服务器而使HTTP代理服务器挂起。


  2)正确性


  正确性是指HTTP代理服务器要能正确的实现几种常用的HTTP请求方法:GET、POST、HEAD、CONNECT(即支持HTTPS)(没有支持所有方法是因为现在99.9%以上的方法用的是这三种方法:GET、POST、HEAD)。


  3)安全性


  安全性是指两个方面:一个是只允许合法的用户接入Internet;另一个是提供访问控制功能,能实现对不良内容的过滤。


  4)灵活性


  灵活性是指能提供灵活的计费方式,如按流量计费和访问时间计费。


  5)经济性


  经济性是指提供缓存功能,减少整个网络的出口流量,并且缓存还能从整体上减少用户的访问延迟,提高系统的性能。


  2.2系统设计方案


  HTTP无线宽带代理软件可以在应用层实现,也可在应用层以下实现即NAT方案。从第一章分析可知只有在应用层实现的代理服务器才能实现基于内容的过滤和缓存功能。鉴于以上制定的目标,我们需要在应用层实现HTTP代理服务器。基于对系统稳定性和性价比上的考虑,本HTTP代理服务器的开发和运行平台都选用Window 2000 Advance Server,选择SQL Server 2000作为计费模块和用户认证模块的数据库平台。


  2.3软件的体系结构


  HTTP代理服务器的功能模块如图2.1:


  图2.1 HTTP代理服务器框架


  Fig 2.1 The frame of HTTP proxy server


  各个模块的主要功能为:


  1)数据转发模块:


  数据转发模块是HTTP代理服务器的核心模块,它主要负责实现在用户和缓存之间及用户和远程服务器之间快速的转发数据。


  2)缓存模块:


  数据转发模块是HTTP代理服务器的核心模块,主要负责Web对象存储、查询及管理,它由判断、存储、查询和淘汰四个子模块组成。


  3)协议解析模块


  协议解析模块主要负责从用户的请求中解析出要访问的Web对象的URL对应


  IP地址及访问的方法。


  4)用户认证模块


  用户认证模块主要负责根据用户的IP地址和用户名及口令对客户进行认证,判断用户是否是合法的用户。


  5)内存管理模块


  内存管理模块采用内存池负责对内存的申请和撤销,加速了内存的分配和释放工作,避免了内存的泄漏,可以提高内存的利用率。


  6)计费模块


  计费模块主要负责实现系统的计费功能,它提供了按流量计费和时间计费两种计费方式。


  7)内容过滤模块


  内容过滤模块主要负责对用户访问的内容进行控制,过滤一些不良的信息。它提供了两种过滤手段:一是按IP地址进行过滤,二是通过关键字匹配对返回的内容进行过滤。


  8)流量控制模块


  流量控制模块主要负责对用户的接入速度进行控制,为不同类型的用户提供不同的上网速度。


  9)日志模块


  日志模块主要负责对用户访问日志的存储。


  2.4 HTTP无线宽带代理服务器的工作流程


  “HTTP无线宽带代理软件”在局域网与Internet之间,充当一个桥梁作用。它扮演着双重角色:面对局域网内的用户,是一个服务器的角色,它接收客户机的连接;面对Internet上的远程服务器,代理服务器又是一个客户机的角色,它向Internet上相应的主机提出访问请求。工作流程如图2.2所示。用户、HTTP代理服务器和Internet上的远程服务器之间的交互过程如下:


  1)用户向代理服务器发出HTTP请求。


  2)代理服务器对用户进行合法性认证,如果是合法用户则执行3),否则断开连接。


  3)对请求进行解析,得出用户要访问的Web对象的URL和请求方法。


  4)查找用户要访问的Web对象是否在缓存中存在,如果存在则取出Web对象发送给用户,否则执行5)。


  5)向Internet上的远程服务器转发用户的请求。


  6)接收Internet上的远程服务器发回的响应。


  7)判断远程服务器返回的数据是否可以缓存,如果可以缓存,则存入系统缓存,否则直接执行8)。


  8)将远程服务器返回的数据发送给用户。


  图2.2代理服务器基本工作流程


  Fig 2.2 The basic work flow of proxy server


  2.5关键技术和模型介绍


  在本系统的设计实现中,涉及到与网络编程、I/O机制、I/O模型等相关内容,


  现在做一下简要的分析和介绍。


  2.5.1 Winsock


  HTTP无线宽带代理软件在应用层实现内外网的数据转发,为此笔者使用了


  Winsock API。Winsock是微软提供的在Windows平台上的网络编程接口,它位于TCP/IP协议栈和应用程序之间,应用程序通过Winsock可实现在应用层层次上的网络通讯,如图2.3所示。


  图2.3基于Winsock的通信模型


  Fig 2.3 Communication model based on Winsock


  Winsock编程的基本步骤如下:


  1)定义变量,获得Winsock版本;


  2)加载winsock库;


  3)初始化;


  4)创建套接字;


  5)设置套接字选项;


  6)关闭套接字;


  7)卸载Winsock库,释放所有资源。


  2.5.2 Windows的I/O机制


  在本系统的设计实现中因为实际I/O的复杂性,不能是简单的按照Winsock的简单流程进行处理,要提高系统I/O性能必须研究I/O机制,然后采用合理的模型进行I/O管理。


  Windows平台提供了两种类型的IO机制:同步IO和异步IO(即重叠IO)[5]。在同步IO中,线程启动一个IO操作然后就立即进入等待状态,直到IO操作完成后才醒来继续执行。而异步IO方式中,线程发送一个IO请求到内核,然后继续处理其他的事情,内核完成IO请求后,将会通知线程IO操作完成了[6]。如图2.4所示:


  图2.4同步I/O与异步I/O


  Fig 2.4 Synchronal I/O and Asynchronous I/O


  如果IO请求需要大量时间执行的话,异步文件IO方式可以显著提高效率,因为在线程等待的这段时间内,CPU将会调度其他线程进行执行,如果没有其他线程需要执行的话,这段时间将会浪费掉(可能会调度操作系统的零页线程)。如果IO请求操作很快,用异步IO方式反而还低效,还不如用同步IO方式。而在本系统中,由于每次发生的数据转发量较大,所以采用异步I/O可以比同步I/O方式效率更高。


  同步IO在同一时刻只允许一个IO操作,也就是说对于同一个文件句柄的IO操作是序列化的,即使使用两个线程也不能同时对同一个文件句柄同时发出读写操作。重叠IO允许一个或多个线程同时发出IO请求。


  异步IO在请求完成时,通过将文件句柄设为有信号状态来通知应用程序,或者应用程序通过GetOverlappedResult察看IO请求是否完成,也可以通过一个事件对象来通知应用程序。


  本系统中,需要处理大量并发的I/O请求,对其数据进行解析并转发。经上述分析可知,如果采用同步I/O会造成系统很低的吞吐量。因此,采用异步I/O机制,以满足系统对于性能上的要求。


  2.5.3 Winsock的I/O模型


  选定了I/O机制后,接下来就需要讨论采用什么样的方式来实现异步I/O模型。


  Winsock提供了一些I/O模型,有助于应用程序通过“异步”方式,一次对一个或多个套接字上进行的通信加以管理。这些模型包括select(选择)、WSAAsyncSelect(异步选择)、WSAEventSelect(事件选择)、Overlapped I/O(重叠I/O)以及Completion port(完成端口)。下面对这几种模型进行分析讨论,在此基础上,选择恰当的模型应用到本系统中。


  ⑴select模型


  select模型是Winsock中常见的I/O模型。之所以称其为“select模型”,是由于它主要利用select函数,实现对I/O的管理。利用select函数,我们判断套接字上是否存在数据,或者能否向一个套接字写入数据。这个函数,唯一的目的便是


  防止应用程序在套接字处于锁定模式中时,在一次I/O绑定调用(如send或recv)过程中,被迫进入“锁定”状态;同时防止在套接字处于非锁定模式中时,产生


  WSAEWOULDBLOCK错误。除非满足事先用参数规定的条件,否则select函数会在进行I/O操作时锁定。


  有很多的代理服务器软件采用此模型实现[7]。如果采用这一模型,我们需要不断的检查套接字上是否有数据需要处理,加大了不必要的系统开销。因此,这一模型并不太适合本系统的需要。


  ⑵WSAAsyncSelect


  利用这个模型,应用程序可在一个套接字上,接收以Windows消息为基础的网络事件通知[8]。具体的做法是在建好一个套接字后,调用WSAAsyncSelect函数,将该套接字以及套接字上的事件与指定的窗口句柄绑定,当指定的事件发生时,这一消息就被投递到窗口句柄指定的窗口中。该模型早出现于Winsock的1.1


  版本中,用于帮助应用程序开发者面向一些早期的16位Windows平台(如Windows for Workgroups),适应其“落后”的多任务消息环境。应用程序仍可从这种模型中得到好处,特别是它们用一个标准的Windows例程(常称为“winproc”),对窗口消息进行管理的时候。使用这种模型,在应用程序中,首先必须用CreateWindow函数创建一个窗口,再为该窗口提供一个窗口例程支持函数(Winproc)。亦可使用一个对话框,为其提供一个对话例程,而非窗口例程,因为对话框本质也是“窗口”。当相关的网络事件发生时,消息被投递到指定的窗口,方便应用程序及时进行处理。


  这一模型在对单个套接字的处理上,显得比较高效,但是它局限于windows窗口程序,适用范围受到了很大限制。本系统是一个后台程序,在代理服务器内部结构的实现中都是在后台进行,这一部分没有窗口程序,而且我们要处理的套接字是大量的,如果单个来处理会很大影响系统效率,因此这一模型不太适合本系统的实际应用。


  ⑶WSAEventSelect


  Winsock提供了另一个有用的异步I/O模型。和WSAAsyncSelect模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为基础的网络事件通知。由WSAAsyncSelect模型采用的网络事件来说,它们均可原封不动的移植到新模型。在用新模型开发的应用程序中,也能接收和处理所有那些事件。该模型


  主要的差别在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。


  此模型相对于上一模型,在适用范围上有了很大改进。但是,本系统中,由于代理服务器面对局域网内的客户机,充当的是服务器的职能,必须建立大量套接字,处理与客户机的连接。在处理大量套接字的时候,编程处理会很复杂,而且从用户的角度来管理大量的进程调度,会使系统开销很大,不利于高效的利用系统资源。因此,这一模型并不太适合应用于代理服务器的软件设计中。


  ⑷重叠模型


  在Winsock中,相比我们解释过的其他所有I/O模型,重叠I/O(Overlapped I/O)模型使应用程序能达到更佳的系统性能。重叠模型的基本设计原理便是让应用程序使用一个重叠的数据结构,一次投递一个或多个Winsock I/O请求。针对那些提


  交的请求,在它们完成之后,应用程序可为它们提供服务。该模型适用于除


  Windows CE之外的各种Windows平台。模型的总体设计以Win32重叠I/O机制为基础。


  要想在一个套接字上使用重叠I/O模型,首先必须使用


  WSA_FLAG_OVERLAPPED这个标志,创建一个套接字。成功建好一个套接字,同时将其与一个本地接口绑定到一起后,便可开始进行重叠I/O操作,方法是调用下述的Winsock函数,同时指定一个WSAOVERLAPPED结构(可选):WSASend、


  WSASendTo、WSARecv、WSARecvFrom、WSAIoctl、AcceptEx、TransmitFile。其中每个函数都与一个套接字上数据的发送、数据接收以及连接的接受有关。因


  此,这些活动可能会花极少的时间才能完成。这正是每个函数都可接受一个


  WSAOVERLAPPED结构作为参数的原因。若随一个WSAOVERLAPPED结构一起调用这些函数,函数会立即完成并返回,无论套接字是否设为锁定模式。它们依赖于I/O请求的完成:应用程序可等待“事件对象通知”,亦可通过“完成例程”,对已经完成的请求加以处理。


  事件通知机制中,重叠I/O的事件通知方法要求将Win32事件对象与


  WSAOVERLAPPED结构关联在一起。若使用一个WSAOVERLAPPED结构,发出像WSASend和WSARecv这样的I/O调用,它们会立即返回。通常,这些I/O调用会以失败告终,返回SOCKET_ERROR。使用WSAGetLastError函数,便可获得与错误状态有关的一个报告。这个错误状态意味着I/O操作正在进行。稍后的某个时间,应用程序需要等候与WSAOVERLAPPED结构对应的事件对象,了解一个重叠的I/O请求何时完成。


  完成例程是应用程序用来管理完成的重叠I/O请求的另一种方法。完成例程其实就是一些函数。开始的时候,我们将其传递给一个重叠I/O请求,在一个重叠I/O请求完成时由系统调用。它们的基本设计宗旨是通过调用者的线程,为一个已完成的I/O请求提供服务。除此之外,应用程序可通过完成例程,继续进行重叠I/O处理。在用一个完成例程提交的重叠请求,与用一个事件对象提交的重叠请求之间,存在着一项非常重要的区别。WSAOVERLAPPED结构的事件字段hEvent并未使用;也就是说,我们不可将一个事件对象同重叠请求关联到一起。用完成例程发出了一个重叠I/O调用之后,作为我们的调用线程,一旦完成,它终必须为完成例程提供服务。这样一来,便要求我们将自己的调用线程置于一种“可警告的等待状态”。并在I/O操作完成后,对完成例程加以处理。WSAWaitForMultipleEvents函数可用来将我们的线程置于一种可警告的等待状态。这样做的缺点在于,我们还必须有一个事件对象可用于WSAWaitForMultipleEvents函数。假如应用程序只用完成例程对重叠请求进行处理,便不可能有任何事件对象需要处理。


  重叠模型与前几种I/O模型相比,使应用程序能达到更佳的系统性能。但是,它只能在提交的请求完成之后,应用程序才可为它们提供服务。在本系统中,如果采用重叠模型,只有套接字上的I/O操作完成之后,才能处理。而我们需要在数据到来时能及时进行处理,而不是已经把数据接收完或者发送完才进行处理。虽


  然,重叠模型很好的采用了并行机制,但是运用的地方却不太适合本系统的实现。


  ⑸完成端口模型


  完成端口模型是迄今为止复杂的一种I/O模型。然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到佳的系统性


  能。该模型只适用于Windows NT和Windows 2000操作系统。因其设计的复杂性,只有同时管理数百乃至上千个套接字的时候,而且希望随着系统内安装的CPU数量的增多,应用程序的性能也可以线性提升,才考虑采用此模型。


  从本质上说,完成端口模型要求我们创建一个Win32完成端口对象,通过指定数量的线程,对重叠I/O请求进行管理,以便为已经完成的重叠I/O请求提供服务。要注意的是,所谓完成端口,实际是Win32、Windows NT以及Windows 2000采用的一种I/O构造机制,除套接字句柄之外,实际上还可接受其他东西。


  成功创建一个完成端口后,便可开始将套接字句柄与对象关联到一起。但在关联套接字之前,首先必须创建一个或多个“工作者线程”,以便在I/O请求投递给完成端口对象后,为完成端口提供服务。到底应该创建多少个线程,以便为完成端口提供服务,不仅取决于应用程序的总体设计情况。更重要的一点在于,调用


  CreateIoCompletionPort时指定的并发线程数量,与打算创建的工作线程数量相比,它们代表的并非同一件事情。CreateIoCompletonPort函数的


  NumberOfConcurrentThreads参数明确指示系统:在一个完成端口上,一次只允许n个工作者线程运行。但实际上,在一段较短的时间内,系统有可能超过这个值,但很快便会把它减少至事先在CreateIoCompletionPort函数中设定的值。实际创建的工作者线程数量有时要比CreateIoCompletionPort函数设定的多一些,这主要取决于应用程序的总体设计情况。假如我们的某个工作者线程调用了一个函数,比如Sleep或WaitForSingleObject,但却进入了暂停(锁定或挂起)状态,那么允许另一线程代替它的位置。换言之,我们希望随时都能执行尽可能多的线程;当然,大的线程数量是事先在CreateIoCompletionPort调用里设定好的。这样一来,假如事先预计到自己的线程有可能暂时处于停顿状态,那么好能够创建比


  CreateIoCompletionPort的NumberOfConcurrentThreads参数的值多的线程,以便到时候充分发挥系统的潜力。


  一旦在完成端口上拥有足够多的工作者线程来为I/O请求提供服务,便可着手将套接字句柄同完成端口关联到一起。这要求我们在一个现有的完成端口上,调用CreateIoCompletionPort函数,同时为前三个参数——FileHandle,


  ExistingCompletionPort和CompletionKey——提供套接字的信息。其中,FileHandle参数指定一个要同完成端口关联在一起的套接字句柄。


  经过分析可以看出,完成端口的本质是通过生成一个完成端口对象,监听多个套接字上的I/O,当某个套接字上的I/O完成时,完成端口就会通知操作系统调用事先定义好的函数进行处理。完成端口模型比较适合用于本系统中,它可以通过完成通知的方式对大量套接字上的I/O进行管理。其机制不会造成由于等待某一


  个套接字上的I/O完成而造成整个主进程阻塞,可以很理想的管理这一复杂情况。


  2.6小结


  本章首先提出了系统的设计目标,即达到高性能、正确性、安全性、灵活性、经济性。在这一设计目标前提下,对HTTP无线宽带代理服务器的工作流程作了详细分析和阐述,提出了系统的整体架构和软件功能模块划分。虽然,系统整体逻辑并不复杂,但是对于系统性能上的要求很高。针对这一具体要求,本文对系统I/O进行了分析,发现对于本系统中的I/O次数频繁,但每次I/O量并不大的情况,采用异步I/O机制可以很好处理这一情况。然后从I/O模型进行分析比较,认为采用IOCP模型可以很好的处理代理服务器系统中需要大量进行I/O和进行相关处理操作的情况。通过这一模型,很好的解决了以往的代理服务器模型中,为了处理I/O数据需要不断的查询套接字状态的情况,而且避免了等待某一个套接字上的I/O完成而使得整个主进程阻塞的情况。


上一篇 企业级代理IP都有什么作用 下一篇 HTTP代理服务器性能设计