写在前面

花了好几天才把计算机网络的实验一搞定,在此记录一下这个实验的流程。

本实验的要求也是比较简单明了的:

(1) 设计并实现一个基本 HTTP 代理服务器。要求在指定端口(例如 8080)接收来自客户的 HTTP 请求并且根据其中的 URL 地址访问该地址 所指向的 HTTP 服务器(原服务器),接收 HTTP 服务器的响应报文,并 将响应报文转发给对应的客户进行浏览。
(2) 设计并实现一个支持 Cache 功能的 HTTP 代理服务器。要求能缓 存原服务器响应的对象,并能够通过修改请求报文(添加 if-modified-since 头行),向原服务器确认缓存对象是否是最新版本。(选作内容,加分项 目,可以当堂完成或课下完成)
(3) 扩展 HTTP 代理服务器,支持如下功能: (选作内容,加分项目, 可以当堂完成或课下完成)
a) 网站过滤:允许/不允许访问某些网站;
b) 用户过滤:支持/不支持某些用户访问外部网站;
c) 网站引导:将用户对某个网站的访问引导至一个模拟网站(钓 鱼)。

而且实验指导书上还给出了 200 来行的代码作为参考,可以说是很贴心了。但关键问题不是不知道原理,而是对 socket 编程是相当地陌生,还好代码大部分都能看懂,看不懂的查询一下也能搞定。本实验基本功能还是很好做的,主要就是 cache 的实现,我大部分时间就在搞这个,最后东拼西凑的,也算是搞出来了(虽然外部存储有时会乱码)。

实验代码在我 github 上,想参考的话,可以点击这里 ,欢迎来提各种建议,虽然我也不一定会去改,但还是希望这个代码会越来越好。

实验配置问题

首先要说的就是环境问题,由于我是使用的 CodeBlocks 进行编译的,因此,有时候会出现一些莫名的问题。这里简单介绍一下。

  1. 最大的问题就是静态链接问题,也就是这段代码 #pragma comment(lib,"Ws2_32.lib") ,在 VS 里可以很好地运行,但是在 CodeBlocks 中就失去作用了。这段代码也很简单,就是说要链接一个库,但是Codeblocks 使用的是 MingGW 来编译,MingGW不支持 #pragma comment(lib,"Ws2_32.lib") 的写法
    解决方法也是很简单,由于该命令是静态链接 Ws2_32.lib 库,因此可以在设置里,加上 -lws2_32 或 -lwsock32,具体怎么加,这里就不讲了。

  2. 第二个问题也是编译器的问题,由于版本问题,这里并不支持 int _tmain(int argc, _TCHAR* argv[]) 的写法,需要改成 int main(int argc, char* argv[]) 或者直接写成 int main() ,其实没有什么区别。具体原因,参考 main()和_tmain(int argc, _TCHAR* argv[]) 的详细区别 和 c/c++ int _tmain(int argc, _TCHAR* argv[])

  3. 再就是 goto 语句的问题了,代码一直报 goto 语句的问题,不常用这个,我也是很懵啊,不过,还好前辈们有经验分享,具体原因可以参考这个: g++编译goto语句出现:[error:jump to label XXX],简单地说,就是你的 goto 语句之后不能再定义新的变量

  4. 再就是关于strtok_s的问题了,可以参考这篇 stackoverflow :关于strtok_s的问题,就是说,只要改成 strtok() 这个函数就可以了。再去掉最后一个参数,因为这个函数只需要俩参数。虽然这个函数并不安全,但它可以用啊。

  5. 大点的问题就这些,还有一些小的问题,比如 VS 里专用的 #include "stdafx.h" ,要去掉,可以参考 为什么要加#include “stdafx.h” ,剩下的,大都没有详细说的必要了

好了,bug 就算是修复完了,现在就可以正常访问网站了:

运行程序 --> 打开浏览器 --> 设置代理 --> 设置 127.0.0.1 和端口号 1240

这样就实现了一个基本的代理服务器,其实现在就已经完成第一个要求了。但你还不知道它的原理是什么,所以,下面看一下它的原理。

实现一个基本的代理服务器

在继续往下看之前,你最好对这几个函数有一定的了解:

  • bind() : 将一本地地址与一套接字捆绑,在 connect() 或 listen() 调用前使用
  • listen() : 监听套接字的连接请求,将套接字设为监听模式
  • connect() : 用于建立与指定 socket 的连接
  • accept() : 在一个套接字处,接受一个连接
  • send() : 发送数据(客户端向服务器发送请求,服务器端向客户端发送应答)
  • recv() : 接收数据

更详细的可以自行去百度查找,这里就不多介绍了。先来看代理服务器的原理

  1. 首先初始化一个套接字,利用 blind() 函数将该套接字与服务器 host 地址绑定,地址设为 “127.0.0.1”;同时,也要绑定端口号,这里就按照指导书上的要求设置为 “10240”。然后,利用 listen() 函数对该端口进行监听。
  2. 通过设置 accept() 函数,对每个到来的请求进行接收和相应,为了提供效率,对每个请求都创建一个新的线程来处理。
  3. 利用 recv() 和 send() 函数,接收来自客户端的 HTTP 请求,并通过这个代理服务器将该请求转发给服务器;同时,服务器也将获得的响应发给代理服务器,然后代理服务器再将该响应发送给客户端。在这里,代理服务器相当于一个中介,提供一个代理的服务,所有的请求和响应都经过它
  4. 处理完成后,等待 200 ms 后,关闭该线程,并清理缓存,然后继续接收并处理下一个请求。对于客户端而言,它只要将正常发送的请求发给代理服务器,就可以接收到对应的响应。

流程图可以表示为:

我个人觉得,这张流程图非常容易理解,基本上就是这段代码的逻辑,对于理解这段代码很有帮助。

扩展功能

对于这三个扩展功能,只要看懂了代码是如何解析并存储的 HTTP 头部信息,写这三个功能还是很简单的。不需要增加多少代码,只需进行 if 判断即可。

屏蔽网站

对请求过来的 HTTP 报文头部进行检测,提取出其中的访问地址 url ,检测其是否为要被屏蔽的网址,如果是,则直接跳转到代码中的 erro 部分,即关闭套接字,断开此次连接。代码片段如下:

if (strcmp (httpHeader->url, INVILID_WEBSITE) == 0) {printf("\n=====================================\n\n");printf("-------------Sorry!!!该网站已被屏蔽----------------\n");goto error;
}

屏蔽用户

更改套接字绑定的主机地址,这样的话,只要不是从该地址访问代理服务器的客户端,都会被该代理服务器屏蔽,部分代码如下:

//屏蔽用户
//ProxyServerAddr.sin_addr.S_un.S_addr = INADDR_ANY;
ProxyServerAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//仅本机用户可访问服务器
//ProxyServerAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.2");  //屏蔽用户

其实,就是更改套接字绑定的代理服务器的 IP 地址,这样的话,就会屏蔽掉从其他接口进行访问客户端,从而实现用户屏蔽。

钓鱼

检测请求过来的 HTTP 报文头部,如果发现访问的网址是要被钓鱼的网址,则将该网址引导到其他网站(钓鱼网址),通过更改 HTTP 头部字段的 url (访问网址)和 host 主机名来实现,部分代码如下:

if (strstr(httpHeader->url, FISHING_WEB_SRC) != NULL) {printf("\n=====================================\n\n");printf("-------------已从源网址:%s 转到 目的网址 :%s ----------------\n", FISHING_WEB_SRC,FISHING_WEB_DEST);memcpy(httpHeader->host, FISHING_WEB_HOST, strlen(FISHING_WEB_HOST) + 1);memcpy(httpHeader->url, FISHING_WEB_DEST, strlen(FISHING_WEB_DEST));
}

cache 实现

cache 可以说是这个实验最精髓的地方了,原理很简单,比较容易理解,但代码写起来还是比较长的,起码比前几个实现起来要复杂。我也是参考了很多前辈们的代码才写出来的,这里就简单介绍一下原理吧,代码自己去看我的实现吧,前面已经给了链接,这里再补充一下:实验一

基本原理

  1. 客户端第一次请求服务器中的数据时,代理服务器将该请求返回的响应缓存下来,存到本地的文件下。
  2. 当客户端第二次访问该数据时,代理服务器检查本地是否有该请求的响应,如果没有,则继续缓存;如果有,则向服务器发送一个请求,该请求需要增加 “If-Modified-Since” 字段,通过此字段,告知服务器缓存资源最后修改的时间(可以将 “Date” 字段进行解析),服务器通过对比最后修改时间来判断缓存是否过期,如果没过期,服务器返回状态码304,代理服务器直接将本地缓存发送给客户端;如果缓存过期,服务器返回状态码200,同时返回一个更新过的响应,代理服务器接收后,将该响应发回给客户端,并更新本地缓存

这一部分的代码虽然代码稍微多一些,但其实也没多少,而且原理很简单,不需要害怕,大胆去写就好了。

总结

这次实验对理解 HTTP 代理服务器还是很有帮助的,真正体会到了代理服务器的作用。虽然调试的时候会出来一堆莫名的 bug, 但是改好后的感觉还是相当不错的。

HTTP 代理服务器的设计与实现相关推荐

  1. 计算机网络课程设计之网络代理服务器的设计与实现

    前言 本实验因为时间有限,写的比较草率... 白嫖容易,创作不易,本文原创,转载请注明!!! 源码和可运行程序: 链接:https://pan.baidu.com/s/1A9KctmpP2JJgyW2 ...

  2. 7、网络代理服务器的设计与实现

    一.设计题目 7.网络代理服务器的设计与实现 二.设计内容 实现一个简易的 proxy 程序.proxy 程序的功能:能够做"二传手"的工作.它自身处在能同时连通外界目标服务器和我 ...

  3. HTTP代理服务器的设计与实现

    一.前言 这个实验挺麻烦的,本来就只有一周时间,等我开始着手准备的时候,也就剩两三天了,也没什么心情自己重头开打代码,于是就找了大佬的代码借鉴了一下,在验收之前处理完了所有的bug.不过,我觉得这个实 ...

  4. 网络代理服务器的设计与实现

    功能需求 实现一个简易的 proxy 程序.proxy 程序的功能:能够做"二传手"的工作.它自身处在能同时连通外界目标服务器和我的机器的位置上.我的机器把请求发送给它,它接受请求 ...

  5. 计算机网络实验1:HTTP 代理服务器的设计与实现

    目录 一.修改并理解参考代码 1.修改错误 2.基本代理服务器原理 二.附加功能的实现 1.网站过滤:允许/不允许访问某些网站 2.用户过滤:支持/不支持某些用户访问外部网站 3.网站引导:将用户对某 ...

  6. 计算机网络--http代理服务器的设计与实现

    一.Socket编程的客户端和服务端的主要步骤: Java Socket编程:对于http传输协议 客户端: 1.创建新的socket,绑定服务器host和端口号 2.Socket创建成功后获得相应的 ...

  7. (计网实验1)HTTP 代理服务器的设计与实现

    目录 教训 参考知识 代理服务器定义 代理服务器原理 单用户代理服务器 多用户代理服务器 实验目的 实验内容 实验过程 设置浏览器代理 实现一个基本的HTTP代理服务器 Cache功能 实现扩展功能 ...

  8. 计算机网络课程设计之简单 Web Server 程序的设计与实现

    前言 本实验是实现一个简易的webserver,我们一直在访问网站,甚至还做过Web课程设计,部署过Tomcat等等,所以说这次实验能更深入的了解其原理 白嫖容易,创作不易,本文原创,转载请注明!!! ...

  9. 计算机网络课程设计之TELNET 终端设计与实现

    前言 Telnet设计是一个比较麻烦的东东,因为Telnet服务器需要部署,而且网络上的资料比较少,最后通过在云服务器CentOS上安装Telnet服务器然后自己的程序作为一个Telnet客户端测试成 ...

  10. 计算机网络课程设计之电子邮件客户端程序设计与实现

    前言 本实验主要是用smtp协议发邮件,收邮件要用到POP3,时间有限,只实现了发邮件,实现过程放在总体设计中 白嫖容易,创作不易,本文原创,转载请注明!!! 源码和可运行程序: 链接:https:/ ...

最新文章

  1. whereis php,Linux命令教程之比较搜索命令whereis与which的区别
  2. Spring Security原理之springSecurityFilterChain
  3. 巴塞尔新资本协议_《巴塞尔公约》修订!进口再生颗粒或对中国产生巨大冲击...
  4. minio下载及安装:win linux平台
  5. 每天一道LeetCode----从数组中选择若干不连续元素使得总和最大
  6. mysql8.0.19.0_分享MySql8.0.19 安装采坑记录
  7. 【DICOMDIR专题】DICOMDIR基础知识及常见问题汇总
  8. Centos 7 安装 memcached
  9. java工程开发之图形化界面之(第六课)
  10. ActiveMQ的消息的(含附件)发送和接收使用
  11. 计算机基础远程教育答案,浙大远程教育2013年计算机作业答案-1-计算机基础知识题.docx...
  12. Servlet做Controller,实现一个类处理多个请求
  13. oracle 7天密码过期,oracle密码过期ORA-28002: 7天之后口令将过期的解决方法
  14. 车辆路径问题的基本操作
  15. 计算机视觉项目实战-驾驶员疲劳检测
  16. atv320说明书_施耐德变频器参数设置ATV320学习资料
  17. html+抽奖游戏,九宫格抽奖HTML+JS版
  18. 2013中国互联网公司、全球互联网公司最新市值排名(2013.04.20)
  19. JAVAEE工程师入门技术之第1课day01_Java基础语法HelloWorld
  20. iOS Masonry详解mas_makeConstraints() 添加约束 mas_remakeConstraints() 移除之前的约束,重新添加新的约束 mas_updateConst

热门文章

  1. Apple(苹果)忘记安全问题答案怎么办?
  2. 科学计算与Matlab笔记:第4章:Matlab绘图
  3. 现场总线CANopen设计与应用
  4. JAVA中apply方法的原理_关于学习java函数式接口Function中的apply方法的一些感悟
  5. Redis 源码解析(8) AOF持久化
  6. WOFF2与icon字体化
  7. linux下使用opengL Glad + EGL问题记录
  8. 悄咪咪后台定时截图工具
  9. 机器学习-GB、GBDT、XGboost、Adaboost
  10. 极限存在准则,两个重要极限