版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
简易代理服务器的设计
摘要代理服务器是介于浏览器和Web服务器之间的一台服务器,它的功能是代理网络用户去取得网络信息。它的工作原理是,接收客户机的数据连接请求,并将请求传给Web服务器;再从Web服务器接收返回的数据,最后把数据传给客户端显示。本论文讲述的是关于一个简单的代理服务器的实现,在实现中采用客户机/服务器结构模型开发应用程序,基于一般的访问浏览速度慢、效率底、安全功能不强等原因,将以简单、合理、有效为原则;为了方便分析和设计,系统设计中设置不同的状态量用于标识客户机、代理服务器及服务器间的联结状态。在保证系统基本功能的同时,使用多线程机制使得代理系统有更好的延续性。此代理系统具有简单,易用,网络化等优点,能够完成一般的HTTP访问代理服务。关键词:客户机/服务器结构;多线程;套接字;代理服务器TheDesignofSimpleProxyServerAbstractTheproxyserverisaserverwhichsituatesbetweenthebrowserandaWebserver.It’sprincipleofworkis,itreceivestheconnectionrequestfromtheclient,andhandsdowntherequestedtotheWebserver,thenreceivesdatawhichisreturnedfromtheWebserver.,finallyhandsitdownthedatatotheclient.Intherealization,itadoptsClient/Serverstructuralmodeltodevelopapplication.Becauseofbrowsespeedslow,lowefficientandnotsafeenough,ittakessimple,reasonableandeffectiveastheprinciple.Inthesystemdesign,itsetsdifferentstatestoidentifyclient,proxyserverandtheconnectivestatebetweenservers.Whenthesystem'sbasicfunctionareguaranteed,itusethemultithreadingtoenabletheproxyservertohaveabettercontinuousfeature.Thisproxysystemhasthemeritsuchassimple,easytouseandsoon,anditcancompletetheproxyofgeneralHTTPvisit.Keywords: Client/Serverarchitecture;Multithreading;Socket;ProxyServer论文总页数:20页TOC\o"1-5"\h\z\o"CurrentDocument"引言 1\o"CurrentDocument"课题背景 1\o"CurrentDocument"本课题研究的意义 1\o"CurrentDocument"本课题的研究方法 1\o"CurrentDocument"理论基础 2\o"CurrentDocument"代理服务器 2\o"CurrentDocument"目前的代理服务技术 3\o"CurrentDocument"Socket面向连接的编程模型 4\o"CurrentDocument"Winsock库 5\o"CurrentDocument"winsock的寻址方式 5\o"CurrentDocument"字节顺序 6\o"CurrentDocument"系统基本套接字调用 6\o"CurrentDocument"创建和关闭套接字一socket()和 closesocket() 6\o"CurrentDocument"指定本地地址一bind() 6\o"CurrentDocument"设置监听状态-listen() 6\o"CurrentDocument"建立套接字连接—connect()和 accept() 6\o"CurrentDocument"收发数据-send(^Precv() 7\o"CurrentDocument"设计方案 7\o"CurrentDocument"基本函数设计 7多线程流程 8\o"CurrentDocument"服务器的实现 8\o"CurrentDocument"环境创建 8功能实现 9数据变量定义 9\o"CurrentDocument"启动代理服务器 10\o"CurrentDocument"请求处理过程 11\o"CurrentDocument"请求响应 13\o"CurrentDocument"关闭服务器 15\o"CurrentDocument"控制主函数 15\o"CurrentDocument"测试结果 15结论 17参考文献 18致谢 错误!未定义书签。声 明 错误!未定义书签。商业源代码,全套计算机毕业设计免费下载更多全套设计联系QQ:1042897696最新设计大全/sf/20100915/3539.html1引言1.1课题背景普通的因特网访问是一种典型的客户机与服务器结构,而代理服务器将运行于客户机与服务器之间,它作为Internet/Intranet上常用的一种服务器,通常配置在Intranet连接Internet的出口处,主要实现代理传输服务。可以这样认为,代理是双向的。即对于内部网上的用户来说,代理服务器可看作是一个外部网的代理;对于外部网络来说,代理服务器可以看作一个要访问外部网的客户。正是由于代理服务器的这种控制方式,可以使用它提高客户访问外网的效率、节省网络带宽,增强网络安全性以及减少网络投资等。代理服务器从提出到现在,不断的经历着内容更进和技术的革新,各种代理服务器产品更是层出不穷。不难看出,代理服务器在我们信息时代的生活中扮演着越来越重要的作用。1.2本课题研究的意义随着Internet与Intranet的飞速发展,作为连接Internet与Intranet的桥梁,代理服务器在实际应用中发挥着极其重要的作用。它可用于多个目的,最基本的功能是连接;此外还包括安全性、缓存、内容过滤、访问控制管理等功能。在代理服务器的众多功能中,安全性是一个突出且敏感的功能。绝大多数企业、部门在使用代理服务器的时候,都会考虑这个问题,把它作为选购代理服务器产品的重要依据。目前市场上流行的代理服务器,像MicrosoftProxyServer、NetscapeProxyServer、WinGate等国外的产品,功能和性能等方面都还不错,我们正好可以通过借鉴它们产品的优点,开发一个具有自主产权的代理服务器产品。而且从保证安全性的角度出发,我们也很有必要开发一个自己的代理服务器。除了上面的因素外,通过一个简单的代理程序的开发,我们能从实现过程中学习到网络通信和网络编程的基础知识,加深理解和掌握我们所使用的开发语言。另外,我们也能从中学习到正确的程序开发流程,积累程序开发经验,为以后更深课题的研究打好基础。1.3本课题的研究方法此代理服务器系统将是建立在WindowsNT平台上的网络应用程序设计。由于需要服务器为其他许多称为客户的主机提供服务,而客户主机又可以随时打开和关闭,在选择网络应用程序体系结构时就采用支持这些特点的客户机/服务器结构。还将运用Windows下网络编程的标准接口WinSock,因为它允许两个或多个应用程序在相同机器上,或者是通过网络相互交流,它是真正协议无关的接口。为了便于直接使用Windows提供的网络编程接口,我们使用MicrosoftVisualC++6.0作为开发工具,利用MFC类库中提供的两个Socket类CAsyncSocket和Csocket。使用这两个Socket类,我们可以运用面向对象的方法来进行Socket编程,而且它们还分别在较低和较高层次上封装了WindowsSocketsAPI,为程序员开发Socket程序提供了便利。2理论基础2.1代理服务器代理服务器的英文全称是ProxyServer,其功能就是代理网络用户去取得网络信息。形象的说:它是网络信息的中转站。很多人不知不觉中就在用代理服务器共享上网,比如sygate,wingate,isa,ccproxy,NT系统自带的网络共享等,它们可以提供企业级的文件缓存,复制和地址过滤等服务。在一般情况下,我们使用网络浏览器直接去连接其他Internet站点取得网络信息时,须送出Request信号来得到回答,然后对方再把信息以bit方式传送回来。代理服务器是介于浏览器和Web服务器之间的一台服务器,有了它之后,浏览器不是直接到Web服务器去取回网页而是向代理服务器发出请求,Request信号会先送到代理服务器,由代理服务器来取回浏览器所需要的信息并传送给你的浏览器。而且,大部分代理服务器都具有缓冲的功能,就好像一个大的Cache,它有很大的存储空间,它不断将新取得数据储存到它本机的存储器上,如果浏览器所请求的数据在它本机的存储器上已经存在而且是最新的,那么它就不重新从Web服务器取数据,而直接将存储器上的数据传送给用户的浏览器,这样就能显著提高浏览速度和效率。更重要的是:ProxyServer(代理服务器)是Internet链路级网关所提供的一种重要的安全功能,它的工作主要在开放系统互联(OSI)模型的对话层。主要的功能有:1、 连接Internet与Intranet充当防火墙:因为所有内部网的用户通过代理服务器访问外界时,只映射为一个IP地址,所以外界不能直接访问到内部网;同时可以设置IP地址过滤,限制内部网对外部的访问权限;另外,两个没有互联的内部网,也可以通过第三方的代理服务器进行互联来交换信息。2、 节省IP开销:前面所讲,所有用户对外只占用一个IP,所以不必租用过多的IP地址,降低网络的维护成本。这样,局域局内没有与外网相连的众多机器就可以通过内网的一台代理服务器连接到外网,大大减少费用。当然也有它不利的一面,如许多网络黑客通过这种方法隐藏自己的真实IP地址,而逃过监视。3、 提高访问速度:本身带宽较小,通过带宽较大的proxy与目标主机连接。而且通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时,则直接由缓冲区中取出信息,传给用户,从而达到提高访问速度的目的。4、 防止攻击:隐藏自己的真实地址信息,还可隐藏自己的IP,防止被黑客攻击。通过分析指定IP地址,可以查询到网络用户的目前所在地。例如,大家在一些论坛上看到,论坛中明确标出了发帖用户目前所在地,这就是根据论坛会员登录时的IP地址解析的。还有平日里我们最为常用的显IP版QQ,在“发送消息”窗口中,可以查看对方的IP及解析出的地理位置。而当我们使用相应协议的代理服务器后,就可以达到隐藏自己当前所在地地址的目的了。5、 突破IP访问限制:使用它可以访问一些有IP禁止访问的服务器,因为封锁只禁止了你和目标服务器的连接,但并没有禁止你与代理服务器的连接以及代理服务器与目标服务器的连接。代理服务器有许多种,大体来说有HTTP,FTP,SOCKS代理三种,其中又分透明代理和不透明代理。其中透明代理一般是网关,是硬件,所以不讨论透明代理。当机器通过代理服务器上网时。通讯是分两次的,先是机器和代理服务器通讯,再是代理服务器和目的地址通讯。机器和代理服务器通讯时,目的IP是代理服务器的IP。代理服务器和目的地址通讯时,源IP是代理服务器的IP,当然外部的数据也是一样的。在内网中,出现的IP数据,全是内网和代理服务器的IP。因此,从IP包头是看不出任何与外面通讯的信息的。只有从数据中才能看到。2.2目前的代理服务技术代理服务技术是在一台PC机上安装一套代理软件,主要用于用户对Internet资源的访问。ICS即Internet连接共享(InternetConnectionSharing)的英文简称,是Windows系统针对家庭网络或小型的Intranet网络提供的一种Internet连接共享服务。它实际上相当于一种网络地址转换器,所谓网络地址转换器就是当数据包向前传递的过程中,可以转换数据包中的IP地址和TCP/UCP端口等地址信息。有了网络地址转换器,家庭网络或小型的办公网络中的电脑就可以使用私有地址,并且通过网络地址转换器将私有地址转换成ISP分配的单一的公用IP地址从而实现对Internet的连接°ICS方式也称之为Internet转换连接。例如有软件:Wingate,Winproxy等。NAT即网络地址转换(NetworkAddressTranslator),从广义上讲,ICS也是使用了一种NAT技术,不过我们这里讨论的NAT是指将运行Windows2000Server的计算机作为IP路由器,通过它在局域网和Internet主机间转发数据包从而实现Internet的共享。NAT方式也称之为Internet的路由连接。网络地址转换NAT通过将专用内部地址转换为公共外部地址,对外隐藏了内部管理的IP地址。这样,通过在内部使用非注册的IP地址,并将它们转换为一小部分外部注册的IP地址,从而减少了IP地址注册的费用。同时,这也隐藏了内部网络结构,从而降低了内部网络受到攻击的风险。例如有软件:WinRoute,Sygate。2.3Socket面向连接的编程模型代理服务器既然是双向的客户机/服务器模型,它工作时通常有一个公共的规则需要遵守,通信双方需要共同遵守这个规则才能保证通信的有效进行,如需要量传输大量语音信息时须采用一种无须建立连接的传输方式,在这种方式下,数据可以以较快的速度传输。而当需要确保数据准确无误地到达时,则应采用面向连接的传输方式。代理服务器就要求采用这种方式,在这种模型下,当服务器程序的套接字创建并初始化完毕时,它先进入休眠状态,直到有客户机向该服务器程序提出连接请求。这时,服务器程序被“唤醒”并开始响应客户机提出的连接请求。这时双方协商数据由谁来接收和由谁来发送,在数据传输完毕时,双方再分别关闭连接,释放因创建套接字而占用的资源,面向连接的编程模型示意图如下:图1面向连接的编程模型上面的示意图向我们显示了面向连接的服务器程序和客户程序的创建与结束过程。首先服务器端创建监听套接字,并为它关联一个本地地址(指定IP地址和端口号),然后进入监听状态准备接收客户端的连接请求。为了接受客户端的连接请求,服务器必须调用accept函数。客户端创建套接字后即可调用connect函数去试图连接服务器监听套接字。当服务器端的accept函数返回后,connect函数也返回。此时客户端使用socket函数创建的套接字,服务器端使用accept函数创建的套接字,双方就可以通信了。当数据完成交换后,客户程序和服务器程序都会分别关闭创建的套接字句柄以完成双方的对话,至此程序服务结束。2.4Winsock库Winsock是Windows下网络编程的标准接口,它允许两个或多个应用程序在相同机器上,或者是通过网络相互交流。Winsock库的装入时是对WinsockDLL版本的进行选择,每个Winsock应用程序都必须加载与之相应的版本的WinsockDLL。如果没有加载,将返回SOCKET_ERROR,加载的函数是WSAStartup,其定义如下:intWSAStartup(WORDwVersionRequested,LPWSADATAlpWSAData);它的第一个参数就是要加载的库版本,第二个参数是用来返回DLL库的详细信息的。2.4.1winsock的寻址方式因为Winsock要兼容多个协议,所以必须使用通用的寻址方式。TCP/IP使用地址和端口号来指定一个地址,但是其它协议也许采用不同的形式。如果Winsock强迫使用特定的寻址方式,添加其他协议就不大可能了。在Winsock中,应用程序员通过SOCKADDR_IN结构来指定IP地址和端口号。定义如下:Structsockaddr_in(shortsin_family;u_shortsin_port;structin_addrsin_addr;harsin_zero[8];};应用程序可以使用inet_addr函数将一个小数点分隔的十进制IP地址字符串转化成由32位二进制数表示的IP地址。inet_ntoa函数将一个网络字节顺序的32位IP地址转化字符串。注意:inet_addr返回的32位二进制数是用网络顺序存储的。2.4.2字节顺序字节顺序是长度跨越多个字节的数据被存储的顺序,分为小尾顺序和大尾顺序,TCP/IP统一规定使用大尾顺序方式传输数据,即网络字节顺序,它的字节顺序是最重要的字节首先存储。Winsock提供了一些函数来处理本地机器的字节顺序和网络字节顺序的转换,htons将主机字节顺序转化到TCP/IP网络字节顺序,ntohs将网络字节顺序转化到主机字节顺序,此外还有htonl和ntohl。这API数据都是平台无关的。使用它们可以保证程序正确运行在所有机器上。2.5系统基本套接字调用2.5.1创建和关闭套接字一socket()和closesocket()应用程序在使用套接字前,首先必须拥有一个套接字,系统调用socket()向应用程序提供创建套接字的手段,如果成功将返回套接字句柄,如果创建失败,返回INVALID_SOCKET(即-1)。当不使用此套接字时,应该用closesocket函数关闭套接字,如果没有错误发生,函数返回0,否则返回SOCKET_ERROR。2.5.2指定本地地址一bind()当一个套接字用socket()创建后,存在一个名字空间(地址族),但它没有被命名。bind()将套接字地址(包括本地主机地址和本地端口地址)与所创建的套接字号联系起来,即将名字赋予套接字,以便能够有效地标识套接字。它用在没有建立连接的套接字上,如果没有错误发生,bind()返回0。否则返回值SOCKET_ERROR。当然,客户端程序也可以在不显示绑定地址和端口号的情况下发送数据或者连接。这时系统会默认地为套接字绑定一个本地端口值。注意:地址在建立套接字通信过程中起着重要作用,程序使用中通常靠填充sockaddr_in结构来绑定套接字到本地地址。绑定到套接字上的本地名称包括主机地址、协议号和端口号3部分。2.5.3设置监听状态-listen()Listen函数设置套接字进入监听状态。为了接受连接,首先使用socket函数创建套接字,然后使用bind函数将它绑定到本地地址,再用listen函数为到达的连接指定backlog,最后使用accept函数接受请求的连接。Listen函数仅应用在支持连接的套接字上,如SOCK_STREAM类型。函数执行成功后,套接字将进入被动模式,到来的连接会通知要排队并等候接受处理。在同一时间处理多个连接请求的服务器通常使用listen函数,如果一个连接请求到达并且排队也满,客户端将接收错误。2.5.4建立套接字连接一connect()和accept()这两个系统调用用于完成一个完整相关的建立,用于客户机与网络中的服务器建立连接时,用connect()这个调用连接将请求发到侦听方。之后,服务端就会调用accept。,而在调用accept()的参数前应该先调用过listen(),Accept函数定义如下:SOCKETaccept(SOCKETsoc,structsockaddr*addr,int*addrlen);2.5.5收发数据-sendO和recv()对流套接字来说,一般使用send和recv函数来收发数据。Send函数在一个连接的套接字上发送缓冲区内的数据,返回发送数据的实际字节数。Recv函数从对方接收数据,并将其存储到指定的缓冲区。Flags参数在这两函数中通常设为0。商业源代码,全套计算机毕业设计免费下载更多全套设计联系QQ:1042897696最新设计大全/sf/20100915/3539.html3设计方案3.1基本函数设计我们根据上面讨论的代理服务器内容容易画出代理服务器的简单流程模型:图2代理服务器的流程从图中看出,我们需要设计的基本功能函数为ClientToProxy和ProxyToServer。其中,ClientToProxy用于实现收取Client数据请求并传给Server;ProxyToServer用于接收Server的数据、传给请求Cliento在处理数据请求的过程中,我们必须知道Server的地址,这是非常重要的。这需要设计一个函数来解析地址,设计过程中用ReceiveInformation函数来实现。另外,任何WindowsSocket函数对IP地址和端口号的引用和传送给WindowsSockets函数的IP地址和端口号均是按照网络顺序组织的,这也包括了sockaddr_in结构这一数据类型中的IP地址域和端口域(但不包括sin_family域)。考虑到一个应用程序通常用“时间”服务对应的端口来和服务器连接,而服务器提供某种机制来通知用户使用另一端口,因此gethostbyname()函数返回的端口号已经是网络顺序了,可以直接用来组成一个地址,而不需要进行转换。如果用户输入一个数,而且指定使用这一端口号,则应用程序必须在使用它建立地址以前,把它从主机顺序转换网络顺序(使用htons()函数)。相应地,应用程序希望显示包含于某一地址中的端口号,这一端口号就必须在被显示前从网络顺序转换到主机顺序(ntohs)。3.2多线程流程由于代理服务器和大多数服务器一样,如果要处理多个请求,它应该使用多线程。其基本规划如下:等待来自客户(Web浏览器)的请求启动一个新的线程,以处理客户连接请求读取浏览器请求的第一行(该行内容包含了请求的目标URL)分析请求的第一行内容,得到目标服务器的地址和端口打开一个通向目标服务器(或下一个代理服务器,如合适的话)的Socket把请求的第一行发送到输出Socket把请求的剩余部分发送到输出Socket把目标Web服务器返回的数据发送给发出请求的浏览器当然,如果考虑细节的话,情况会更复杂一些。实际上,这里主要有两个问题要考虑:第一,从Socket按行读取数据最适合进一步处理,但这会产生性能瓶颈;第二,两个Socket之间的连接必需高效。有几种方法可以实现这两个目标,但每一种方法都有各自的代价。例如,如果要在数据进入的时候进行过滤,这些数据最好按行读取;然而,大多数时候,当数据到达代理服务器时,立即把它转发出去更适合高效这一要求。另外,数据的发送和接收也可以使用多个独立的线程,但大量地创建和拆除线程也会带来性能问题。因此,对于每一个请求,我们将用一个线程处理数据的接收和发送,同时在数据到达代理服务器时,尽可能快速地把它转发出去。4服务器的实现4.1环境创建设计使用VisualC++6.0作为编程工具,采用WindowsXP系统平台。刚开始时运行VC++6.0开发工具,单击菜单“Tools/Options...”,弹出Options对话框,选择Directories选项卡,首先在“Showdirectoriesfor:”下拉菜单中选择Includefiles,将SDK中头文件的目录添加到:“Directories:”列表中,如图3所示:OptionsEditorTabsDebugCompatibilityBuildDirectoriesWorksPlatform:Showdirectoriesfor:OptionsEditorTabsDebugCompatibilityBuildDirectoriesWorksPlatform:Showdirectoriesfor:(Win32IncludefilesDirectories:C:\ProgramFiles\VC6SP6\VC6EN\VC98\INCLUDEC:\ProqramFiles\VC6SP6\VC6EN\VC98\MFC\INCLUDEC:\ProgramFiles\VC6SP6\VC6EN\VC98\ATL\INCLUDEC:\PmC:\ProgramFiles\VC6SP6\VC6EN\VC98\INCLUDEC:\ProqramFiles\VC6SP6\VC6EN\VC98\MFC\INCLUDEC:\ProgramFiles\VC6SP6\VC6EN\VC98\ATL\INCLUDEC:\Pm响eFilEMig衲哗四!耕f睥设置C:\ProqramFiles\Micro^rrVisua^Sfijd史“Show顷irectorieaVforW”下拉菜单中选择Libraryfiles,进行然样的设置,如图4所示。在VC主窗口中,执行主菜单“File”/“New”命令,后在“Showec建立个控制台应用程序类型的工程,工程名为“MiniProxy”;点击“OK”选择“anapplicationthatsupportsMFC”,之后一直确定,完成项目工程的建立Cancel创建工作。CancelOptionsEditorTabsDebugCompatibilityBuildDirectoriesWorks,QTEditorTabsDebugCompatibilityBuildDirectoriesWorks,QTPlatform:|Win32ShowdirectoriesforPlatform:|Win32▼| |LibraryfilesDirectories:ramFiles\MicrosoftVisualStudio\VC98\LIBC:\ProqramFiles\MicrosoftVisualStudio\VC98\MFC\L旧C:\ProgramFiles\VC6SP6\VC6EN\VC98\LIBC:\ProqramFiles\VC6SP6\VC6EN\VC98\MFC\LIB图4Libraryfiles设置4.24.2功能实现4.2.1数据变量定义定义代表http://类型协议的变量HT%定义缓冲区大小变量MAXBUFFERSIZE。运用结构体Str_BasalSocket,里面定义客户端到代理服务器及代理服务器到Server间套接字两个,以及客户端、代理服务器和Server间的连接状态变量两个;Str_ProParam结构体定义Server地址变量,指向结构体Str_BasalSocket的指针,联结Server主机的端口变量和代理服务器到Server连接状态的句柄变量,这个结构体是用来代理服务器与Server主机交换信息。4.2.2启动代理服务器这里,在运用套接字编程中由于Winsock在被调用时是动态链接库WinsockDLL形式实现的,首先需调用WSAStartup()函数对WinsockDLL进行初始化,它的第一个参数指定要加载的Winsock库的版本,高字节为次版本号,低字节为主版本号;第二个参数是用来返回DLL库的详细信息,是指向WSADATA结构的指针。实现为:WSADATAwsaData;if(::WSAStartup(0x202,&wsaData)!=0)(printf("\nErrorinStartupsession.\n");WSACleanup();return-1;}之后,创建一个代理服务器(Proxy)用于网络通信的套接字listen_socket。为了将本地地址附加到所创建的套接字上以便能够有效地标识套接字,我们需用bind函数来完成这一步:SOCKETlisten_socket;sockaddr_inlocal;定义用于保存socket信息的变量。local.sin_family=AF_INET;地址家族用于指定地址格式。local.sin_addr.s_addr=INADDR_ANY;此处将本机IP地址填入此变量。local.sin_port=htons(port);字节顺序转换函数用于将将u_short类型变量port从主机字节顺序转化到TCP/IP网络字节顺序(即:hosttoneworkshort)o再用listen_socket二socket(AF_INET,SOCK_STREAM,0)语句打开socket描述符。if(::bind(listen_socket,(sockaddr*)&local,sizeof(local))!二0)(printf("\nErrorinBindingsocket.");WSACleanup();return-3;绑定完成后,紧接着就将此套接字置入监听以准备接受客户端的连接请求,调用listen函数,::listen(listen_socket,5),最后就可以启动处理线程进行侦听。商业源代码,全套计算机毕业设计免费下载更多全套设计联系QQ:1042897696最新设计大全/sf/20100915/3539.html4.2.3请求处理过程在这一步设计函数ClientToProxy来处理收到客户请求,并将请求合理传送至Server(客户请求的数据服务器)。当客户端有请求发到代理服务器时,侦听中的Proxy就会调用函数accept来响应对主机的连接请求,同时Proxy会启动另一个侦听线程,以准备接收客户端的下一个请求。msg_socket=accept(listen_socket,(structsockaddr*)&from,&fromlen);此处接收客户端的连接请求,返回客户端的地址和端口。AfxBeginThread(ClientToProxy,pParam);启动另一侦听,用来处理客户端传来的另一个请求。如果此客户端到代理服务器的连接正确,我们就在这一socket连接上使用revc函数接收数据。SPair.StateClitoProClosed二FALSE;SPair.StateProtoSerClosed二TRUE;SPair.soc_ClitoPro=msg_socket;retval二recv(SPair.soc_ClitoPro,Buffer,sizeof(Buffer),0);如果从套接字接收数据失败,用下面代码给出提示,同时关闭socket句柄,设置客户端到服务器的状态为关闭。if(retval==SOCKET_ERROR)(printf("\nErrorReceive");if(SPair.StateClitoProClosed==FALSE)(closesocket(SPair.soc_ClitoPro);SPair.StateClitoProClosed=TRUE;}}当客户端关闭连接时,这时接收的数据为0,也需要将此时socket状态进行调整:printf("ClientCloseconnection、/);closesocket(SPair.soc_ClitoPro);SPair.StateClitoProClosed二TRUE;下面的一步,需要把这些数据信息传给Server。为此,需要解析出Server的地址,创建函数Receiveinformation来实现此功能,即声明intReceiveInformation(char*str,char*address,int*port),其中将实现:charbuf[MAXBUFFERSIZE],command[512],proto[128];由于客户端在连接时,都会和代理服务器连接,发出请求,一般为commandurl(//GET/HTTP1.1==>GET/HTTP1.1形式,定义buf用于存储接收到的请求字符串;command用于保存get,connet,user等命令,这里显然是get;proto保存协议。p=strstr(buf,HTTP);这里strstr调用用于在字符串buf中寻找http第一次出现的位置(它不会比较结束符NULL),将值赋给指针p。如果分析出请求是HTTP协议类型的,将进行如下处理,首先将字符串协议部份去掉,把地址存于address参数中,端口设为缺省的80,最终返回这些信息,成功解析出Server端的地址信息。至此,启动一个新的子线程,用于处理代理服务器和数据服务器间的数据传输。这个功能将在下面实现。在刚才的处理线程中,如果代理服务器、Server以及客户端、代理服务器端的连接没有关闭,就使用send命令发送请求数据给数据服务器(Server),成功时返回接收的字节数,错误时显示出错信息,并关闭代理服务器到Server的连接套接字,设置连接状态为关闭,直到接下来的处理不出错为止。retval二send(SPair.soc_ProtoSer,Buffer,Len,0);printf("\nsend()failed:error%d\n",WSAGetLastError());closesocket(SPair.soc_ProtoSer);SPair.StateProtoSerClosed=TRUE;同时代理继续接收客户端的请求,成功时返回接收的字节数,错误时显示出错信息,关闭客户端到代理服务器的套接字,设置连接状态为关闭。直到接下来的处理不出错为止。retval二recv(SPair.soc_ClitoPro,Buffer,sizeof(Buffer),0);如果返回的字节数为零,表示客户端关闭连接,此时也应关闭客户端到代理服务器的套接字,设置连接状态为关闭。否则返回接收信息。Len=retval;#ifdefDEBUGBuffer[Len]=0;printf("\nReceived%dbytes,data[%s]fromclient\n”,retval,Buffer);#endif4.2.4请求响应这一步中,完成ProxyToServer函数的实现。首先要做数据服务器Server主机地址信息的转换,定义一个hostent结构变量*hp来保存。Str_ProParam*pPar=(Str_ProParam*)pParam;char*server_name="localhost";structsockaddr_inserver;structhostent*hp;server_name=pPar->Address;SOCKETconn_socket;socket_type=SOCK_STREAM;将socket_type类型设定为流式套接字类型,用上面分析出的server地址传给变量server_name,这会在下面的设计中使用。如果server的地址是字母类型的,就使用gethostbyname(server_name)函数返回对应于给定主机名的主机信息(把IP地址串当作一个未知主机名同样处理);否则,应用inet_addr(server_name)把地址串转换为IP地址,再用gethostbyaddr得到hostent结构赋值给hp指针。最后,进行一下不成功的处理:if(hp==NULL)(fprintf(stderr,"Client:Cannotresolveaddress[%s]:Error%d\n",server_name,WSAGetLastError());::SetEvent(pPar->H_StateProToSvr);return0;}有了解析后的地址信息后,下一步,将这些信息拷贝给sockaddr_in结构。memset(&server,0,sizeof(server));memcpy(&(server.sin_addr),hp->h_addr,hp->h_length);server.sin_family=hp->h_addrtype;server.sin_port=htons(port);端口地址转换成网络字节顺序。conn_socket=socket(AF_INET,socket_type,0);打开一个socket,如果打开失败,显示错误信息,关闭代理服务器到服务器的连接状态,if(conn_socket<0)(fprintf(stderr,"Client:Error Opening socket:Error%d\n”,WSAGetLastError());pPar->pPair->StateProtoSerClosed二TRUE;return-1;}在成功创建套接字的连接后,现在就将接收数据服务器的数据,同样用函数recv来完成,成功时返回接收的字节数,错误时显示出错信息,关闭代理服务器到服务器的套接字,设置连接状态为关闭,如果返回的字节数为零,表示服务端关闭连接,此时也应关闭代理服务器端到服务器Server的套接字的句柄,设置连接状态为关闭。retval=recv(conn_socket,Buffer,sizeof(Buffer),0);if(retval==SOCKET_ERROR)(fprintf(stderr,"recv()failed:error%d\n”,WSAGetLastError());closesocket(conn_socket);pPar->pPair->StateProtoSerClosed二TRUE;break;}Len=retval;if(retval==0)(printf("Serverclosedconnection\n");closesocket(conn_socket);pPar->pPair->StateProtoSerClosed二TRUE;break;}最后是将这些数据信息send给客户机,使用send命令发送数据给客户端,成功时返回接收的字节数,错误时显示出错信息,并关闭代理服务器到客户端的连接套接字,设置连接状态为关闭。retval=send(pPar->pPair->soc_ClitoPro,Buffer,Len,0);fprintf(stderr,"send()failed:error%d\n”,WSAGetLastError());closesocket(pPar->pPair->soc_ClitoPro);pPar->pPair->StateClitoProClosed二TRUE;Len=retval;#ifdef_DEBUGBuffer[Len]=0;printf("Received%dbytes,data[%s]fromserver\n",retval,Buffer);#endif当完成这步这后,我们程序也就差不多设计好了,一个严谨的程序员应该做好程序的扫尾工作,需最后完成客户端、代理服务器和代理服务器、服务器的套接字关闭工作,设定它们的状态为关闭。4.2.5关闭服务器当使用完设计的代理服务器后,我们将调用系统功能函数关闭代理服务器。首先用closesocket(listen_socket)关闭套接字句柄,再用WSACleanup()来释放分配给指定应用程序的资源。注意,程序中多次用到WSACleanup(),这是因为应用程序或DLL在使用WindowsSockets服务之前必须要进行一次成功的WSAStartup()调用.当它完成了WindowsSockets的使用后,应用程序或DLL必须调用WSACleanup()将其从WindowsSockets的实现中注销,并且该实现释放为应用程序或DLL分配的任何资源.4.2.6控制主函数由于控制台应用程序本身不具备窗口应用程序中良好的界面操作性,因此主函数内只能对程序界面操作进行简单的控制。用StartProxy()启动服务后可以让程序准备接收一个字符,根据字符判断代理服务器是否要主动关闭。这之前还需要让用户输入代理服务器的端口号,提示用户最好选用系统保留端口号之外的可用端口。实现如下:cout<<〃请设置代理服务器端口号...〃<<endl<<〃Port:〃;cin>>port;if(port<1024){cout<<〃注意1~1024是保留端口号,使用有可能会引起端口冲突!〃<<endl;}StartProxy();if(getchar()=='x')break;CloseProxy();5测试结果完成程序的代码编写,通过调试,修改出现的问题后,将设计的程序通过
“Build”菜单,选择“RebuildAll”菜单项重新编译程序,再通过“Ctrl+F5”命令生成.EXE的执行程序。结果如下:DeletingintermediateFilesandoutputFilesForproject■MiniPrt Configuration;MiniProxy-Win32Debug Compilingresources Compiling...StdAfx.cppCompilingresources Compiling...StdAfx.cppCompiling MiniProxy.cpfjfLinking Creatingbrousein+FFile..C:\MiniProxv\Debug\MiniProxv.exe「请设置代理服务器端口号…-Port;图
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年标准个人鱼塘承包协议样式版B版
- 2024年煤炭供应与采购协议
- 2024年玻璃隔断施工协议详细条款
- 2024年农产品配送服务委托协议书(含绿色物流)3篇
- 2024年他项权证借款额低于原合同规定的合同修订书3篇
- 2024年度智能音响设备研发三方入股合作协议书3篇
- 2024年度影视作品授权许可协议书3篇
- 2024年简化版原油物流运输服务协议版B版
- 2024年度尿素肥料与农药联采联销合作协议范本3篇
- 幼儿曲奇饼干课程设计
- 税务管理专项测试题附答案
- 人工智能营销(第2版)课件全套 阳翼 第1-8章 迈入人工智能领域-人工智能营销的伦理与法律问题
- 2024-2025一年级上册科学教科版2.4《气味告诉我们》课件
- 语文大单元视域下的任务群教学实践
- 融入TGFU教学法的TPSR教学模式在小学篮球课程中的德育效果研究
- 医院感染管理委员会模板
- DL∕T 5028.2-2015 电力工程制图标准 第2部分 机械部分
- 预算管理一体化系统内控体系指引
- 传统地权结构及其演变 -
- 老旧小区改造工程竣工验收质量评估报告
- 2024年山东省青岛中德生态园(青岛国际经济合作区)管委会选聘52人历年(高频重点提升专题训练)共500题附带答案详解
评论
0/150
提交评论