目录

一、修改并理解参考代码

1.修改错误

2.基本代理服务器原理

二、附加功能的实现

1.网站过滤:允许/不允许访问某些网站

2.用户过滤:支持/不支持某些用户访问外部网站

3.网站引导:将用户对某个网站的访问引导至一个模拟网站(钓鱼)

4.cache实现

原理

实现过程

三、实验演示结果

1.基础功能

2.Cache功能

3.屏蔽网站

4.屏蔽用户

5.钓鱼功能


一、修改并理解参考代码

1.修改错误

  • 提示#include "stdafx.h"找不到并且产生大量错误 ,比如HttpHeader有问题之类

解决方法:

本人使用VS2019,直接将这个头文件从网上下载了一份,放入VS的头文件目录下,在项目上右键打开选项,我的目录是D:\Windows Kits\10\Include\10.0.19041.0\um

另一点需要注意的是在VS中把源文件的后缀改为cpp而不是c

  • 提示 E0546    控制传输跳过的实例化:

goto语句的问题,不能在goto语句后面还增加定义,否则会认为没有初始化而报错

解决方法:

把定义语句 HttpHeader* httpHeader = new HttpHeader(); 放在goto之前的位置即可

  • 运行报错'gethostbyname': Use getaddrinfo() or GetAddrInfoW) instead or define
    _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated APl warnings

解决方法:

打开项目属性,编辑预处理器定义,增加 _WINSOCK_DEPRECATED_NO_WARNINGS,如图:

  • 运行时提示错误:LNK2019无法解析的外部符号WinMain,该符号在函数"int _cdeclinvoke_main(void)" (?invoke_main@@YAHXZ)中被引用

这个问题似乎是c语言运行时找不到适当的程序入口函数,也就是主函数和当前项目不匹配的问题。

解决方法:

将主函数int _tmain(int argc, char * argv[])

直接改为int main()

并且解决方案平台一定选择x64

  • VS2019输出控制台中文乱码

记事本里改为ANSI格式,因为VS2019控制台的编码是GBK,而文件可能是UTF-8格式

这里折腾了很久,是因为原来安过的一个拓展,每次强行把文件变为UTF-8,把拓展禁用就好了。

2.基本代理服务器原理

①首先初始化一个套接字(代码中的BOOL InitSocket()函数)

WSAStartup(wVersionRequested, &wsaData);
ProxyServer = socket(AF_INET, SOCK_STREAM, 0);  //Socket创建套接字
bind(ProxyServer, (SOCKADDR*)&ProxyServerAddr, sizeof(SOCKADDR)
listen(ProxyServer, SOMAXCONN)

利用 bind() 函数将该套接字与服务器 host 地址绑定,host 地址设为 “127.0.0.1”;

绑定端口号(例如:“10240”)

然后,利用 listen() 函数对该端口进行监听。

②通过accept() 函数,对每个报文的到来请求进行接收和相应,为了提供效率,对每个请求都创建一个新的线程来处理。代理服务器一直循环此段代码,达到不断监听的效果

acceptSocket = accept(ProxyServer, (SOCKADDR*)&acceptAddr, NULL);
lpProxyParam = new ProxyParam;
lpProxyParam->clientSocket = acceptSocket;
//创建新线程
hThread = (HANDLE)_beginthreadex(NULL, 0, &ProxyThread, (LPVOID)lpProxyParam, 0, 0);
CloseHandle(hThread);
Sleep(200);

④接下来进入线程执行函数unsigned int __stdcall ProxyThread(LPVOID lpParameter)

利用 recv() 和 send() 函数,接收来自客户端的 HTTP 请求,并通过代理服务器将该请求转发给服务器;同时,服务器也将获得的响应发给代理服务器,然后代理服务器再将该响应发送给客户端。在这里,代理服务器相当于一个中介,提供一个代理的服务,所有的请求和响应都经过它。

    /*接收客户机传来的请求 参数一:指定接收端套接字描述符;参数二:指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;参数三:指明buf的长度;参数四 :一般置为0。*/recvSize = recv(((ProxyParam*)lpParameter)->clientSocket, Buffer, MAXSIZE, 0);ParseHttpHead(CacheBuffer, httpHeader);    //HTTP报文分析函数,通过分割字符串获得url,host等信息//将客户端发送的 HTTP 数据报文直接转发给目标服务器ret = send(((ProxyParam*)lpParameter)->serverSocket, Buffer, strlen(Buffer) + 1, 0);printf("成功向目标服务器转发HTTP报文\n");//等待目标服务器返回数据recvSize = recv(((ProxyParam*)lpParameter)->serverSocket, Buffer, MAXSIZE, 0);//将目标服务器返回的数据直接转发给客户端ret = send(((ProxyParam*)lpParameter)->clientSocket, Buffer, sizeof(Buffer), 0);

④处理完成或发生错误时,进入error,代理服务器等待 200 ms 后,关闭该线程,并清理缓存,然后继续接收并处理下一个请求。

//错误处理
error:printf("关闭套接字\n");Sleep(200);closesocket(((ProxyParam*)lpParameter)->clientSocket);closesocket(((ProxyParam*)lpParameter)->serverSocket);delete lpParameter;_endthreadex(0);return 0;
}

⑤解析HTTP报文头部的函数void ParseHttpHead(char* buffer, HttpHeader* httpHeader)

函数的核心就是strtok_s()的字符串分割函数

strtok_s(buffer, delim, &ptr);

//线程安全的字符串分割函数,提取第一行,剩余的字符串在&ptr

/*首次调用时,s必须指向要分解的字符串,随后调用要把s设成NULL。
     strtok在s中查找包含在delim中的字符并用NULL('\0')来替换,直到找遍整个字符串。返回指向下一个标记串。
     当没有标记串时则返回空字符NULL。*/

二、附加功能的实现

1.网站过滤:允许/不允许访问某些网站

简单的用宏定义拦截4399网站(这样做到同时拦截多个网站比较麻烦,事实上采用char[]较为合理,后面的网站屏蔽钓鱼均用了改进的方法),如果httpHeader->url和INVALID_WEBSITE相同,说明当前访问的是被屏蔽的网站,接下来不连接目标服务器,直接goto error


#define INVALID_WEBSITE "http://www.4399.com/"  //被屏蔽的网站
//************************************
//Method : ForbidInvalidWebsite
//FullName: ForbidInvalidWebsite
//Access: public
//Return : bool true为不是屏蔽网站,false为已屏蔽
//Qualifier:网站过滤,不允许访问某些网站
//Parameter: HttpHeader* httpHeader
//************************************
bool ForbidInvalidWebsite(HttpHeader* httpHeader)
{if (!strcmp(httpHeader->url, INVALID_WEBSITE)){printf("******************************************\n");printf("此网站%s 已被屏蔽!\n", INVALID_WEBSITE);printf("******************************************\n");return false;}return true;
}

2.用户过滤:支持/不支持某些用户访问外部网站

采用了const char* InvalidIP[10] = {" "}的结构存储被屏蔽IP,这样可以屏蔽多个用户

修改accept函数的第二个参数为 (SOCKADDR*)&acceptAddr,获取用户的IP。然后通过字符串匹配,判断IP是不是在禁用IP表内,如果在,就goto error

const char* InvalidIP[10] = {""}; //被屏蔽的用户IP,以127.0.0.1为例
const int IPnum = 0;
SOCKADDR_IN acceptAddr; //自定义变量,用来获得用户的IP
//监听连接请求,创建新套接字
//获取用户IP地址:inet_ntoa(acceptAddr.sin_addr));
acceptSocket = accept(ProxyServer, (SOCKADDR*)&acceptAddr, NULL);//用户过滤:支持/不支持某些用户访问外部网站
if (ForbidInvalidUser(inet_ntoa(acceptAddr.sin_addr)))
{closesocket(acceptSocket);
}//************************************
//Method : ForbidInvalidUser
//FullName: ForbidInvalidUser
//Access: public
//Return : bool true说明已屏蔽该用户
//Qualifier:用户过滤:支持/不支持某些用户访问外部网站   禁用客户IP表是全局变量
//Parameter: char* userIP   用户IP指针
//************************************
bool ForbidInvalidUser(char* userIP)
{for (int i = 0; i < IPnum; i++){if (strcmp(userIP,InvalidIP[i])){//用户IP在禁用IP表中printf("******************************************\n");printf("此用户ID = %s 已被屏蔽!\n", userIP);printf("******************************************\n");return true;}}return false;
}

3.网站引导:将用户对某个网站的访问引导至一个模拟网站(钓鱼)

匹配URL和前两个类似。重点是,修改 httpHeader->host 和 httpHeader->url 为钓鱼的目标网站。

//************************************
//Method : GoFishing
//FullName: GoFishing
//Access: public
//Return : void
//Qualifier:网站引导:将用户对某个网站的访问引导至一个模拟网站(钓鱼)
//Parameter: HttpHeader* httpHeader
//************************************
void GoFishing(HttpHeader* httpHeader)
{for (int i = 0; i < FishingSrcNum; i++){if (strstr(httpHeader->url, FishingSrcURL[i])){//访问的url在钓鱼源网址列表中printf("******************************************\n");printf("已从源网址:%s 转到 目的网址 :%s\n", httpHeader->url,FishingDestURL[i]);printf("******************************************\n");memcpy(httpHeader->host, FISHING_WEB_HOST, strlen(FISHING_WEB_HOST) + 1);memcpy(httpHeader->url, FishingDestURL[i], strlen(FishingDestURL[i]));}}
}

4.cache实现

要求能缓存原服务器响应的对象,并能够通过修改请求报文(添加 if-modified-since头行),向原服务器确认缓存对象是否是最新版本。

原理

浏览器向代理服务器发送所有的HTTP请求

代理服务器收到客户端的HTTP请求后,检查本地Cache是否有该请求的URL

如果缓存未命中,就直接向目标服务器发送HTTP请求,获取对象,将该请求返回的响应缓存下来,存到本地的Cache下

如果缓存命中,代理服务器则向目标服务器发送一个请求,该请求需要增加 “If-Modified-Since” 字段,通过此字段,告知目标服务器缓存资源最后修改的时间,服务器通过对比最后修改时间来判断缓存是否过期。如果没过期,服务器返回状态码304,代理服务器直接将本地缓存发送给客户端;如果缓存过期,服务器返回状态码200,同时返回一个更新过的响应,代理服务器接收后,将该响应发回给客户端,并更新本地缓存

实现过程

①int ParseHttpHead_AddCache(char* buffer, HttpHeader* httpHeader) 

解析 TCP 报文中的 HTTP 头部,检验是否cache命中

相比于原来的解析报文,在更新完httpHeader后,增加了搜索url是否在cache的功能

分为缓存命中 / 缓存未命中,存入缓存 / 缓存未命中,缓存已满,覆盖开头缓存

②void ParseCache(char* buffer, char* status, char* last_modified) 

        解析 TCP 报文中的 HTTP 头部,在缓存命中的时候使用,获取status和last_modified信息

如果服务器返回状态码为304,说明数据没有被修改,将缓存的数据直接转发给客户端

如果服务器返回状态码为200,内容已经修改了,更新缓存中的内容

三、实验演示结果

1.基础功能

打开代理功能,将地址和端口设置为127.0.0.1和10240

此时未运行代理服务器程序时,无法正确加载网页

此时运行代理服务器,以本科生院为例,可以正确访问界面,并获得反馈

2.Cache功能

多刷新几次页面,会发现本科生院主页的内容不再来源于服务器,而是来自缓存

在将内容转发给客户端前设置断点,观察cache的内容,可以看到缓存了网页的内容

3.屏蔽网站

屏蔽4399

4.屏蔽用户

以本机127.0.0.1为例,加入到屏蔽用户列表后,无法访问任何网页

5.钓鱼功能

从今日哈工大钓鱼到教务处网站

计算机网络实验1:HTTP 代理服务器的设计与实现相关推荐

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

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

  2. 计算机网络实验仿真系统设计,计算机网络实验课程仿真系统平台的研究与设计...

    摘要: 随着计算机技术和网络技术不断发展,<计算机网络>课程成为高校许多工科专业的骨干必修课程.课程涉及到的知识内容主要以理论教学为基础,以实验实践为辅助教学.由于受实验室建设资金.网络环 ...

  3. 计算机网络教学仿真平台,计算机网络实验课程仿真系统平台的研究与设计

    摘要: 随着计算机技术和网络技术不断发展,<计算机网络>课程成为高校许多工科专业的骨干必修课程.课程涉及到的知识内容主要以理论教学为基础,以实验实践为辅助教学.由于受实验室建设资金,网络环 ...

  4. 计算机网络抓包设计,计算机网络实验利用wireshark抓包工具抓包

    计算机网络实验利用wireshark抓包工具抓包 计算机网络实验[利用wireshark抓包工具抓包] 一.实验名称 使用网络协议分析仪 Wireshark 二.实验目的 1.掌握安装和配置网络协议分 ...

  5. 计算机网络实验-实验四 无线网络的设计

    实验四 无线网络的设计 本次实验最应该注意的便是网关的作用 实验四 无线网络的设计 1.首先明确概念总共有两个路由器,一个是无线路由器,另一个是有线路由器.所以有线路由器这边直连交换机,交换机再连接A ...

  6. 江苏大学计算机网络设计,江苏大学计算机网络实验报告

    计算机网络实验报告 班级:网络工程1102班姓名:董永 学号:3110610055 配置一个典型的网络系统 1 实验目的 在实验中,我们将学习如何配置一个典型的网络系统,其中硬件设施使用到路由器.三层 ...

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

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

  8. 计算机虚拟网络毕业论文,计算机毕业论文——基于WEB的虚拟计算机网络实验平台.doc...

    PAGE Tianjin University of Technology and Education 毕 业 设 计 专 业: 计算机科学与技术 班级学号: 计0203班 – 11 学生姓名: 指导 ...

  9. 计算机网络技术教法改革方案,计算机网络实验论文,关于“计算机网络”教学改革相关参考文献资料-免费论文范文...

    导读:本文是一篇计算机网络实验论文范文,可作为选题参考. (西南科技大学国防科技学院) 摘 要:"计算机网络"是一门理论与实践性都很强的课程,针对该课程存在教学模式与教学方法陈旧. ...

  10. 计算机网络平台实验,计算机网络实验

    课程简介 "计算机网络实验"课程是计算机学院三年级本科生实践类必修课.本课程主要配合计算机网络课程,通过实验帮助学生学习和理解网络原理与协议,培养学生的动手能力.工程实践能力和综合 ...

最新文章

  1. MCMC笔记:蒙特卡罗方法
  2. linux提高nand速度,linux-2.6.31.1内核支持Nand Flash
  3. 【示例】Lucene查询索引库编程步骤
  4. php云点播源码,乐视云直播 点播服务端api
  5. 使用LINQ遇到的问题,请高手解答下原理
  6. 它决定支付30万美元的勒索金
  7. innoDB索引使用和优化汇总
  8. stm32F10x 看程序知识点记录
  9. gma 教程 | 气候气象 | 计算标准化降水指数(SPI)
  10. Springboot数据库配置文件明文密码加密解密
  11. windows之电脑开机出现 this product is covered by one or more of the following prtents
  12. iptables: No config file解决方法
  13. 大学数学建模大赛是用计算机,全国大学生数学建模大赛
  14. 泛型-IMPORTANT
  15. python能代替ps吗_Python中怎么像PS一样处理图像
  16. for循环打印九九乘法表
  17. Echarts折线图曲线图和三维图
  18. dnf手游服务器维护时效,DNF手游延期到2021年2月11日是真的吗 延期日期详细说明...
  19. [经济学原理|政治部分]剩余价值理论
  20. 第十三届蓝桥杯大赛软件赛省赛 Java 研究生组

热门文章

  1. 3211. 【SDOI2013】随机数生成器
  2. 真正内心强大的人是什么样子???
  3. 你是我的四月天[转自天涯]
  4. 解决问题:开启Wireshark之NPF驱动问题
  5. 星际争霸1终于可以在win10上运行了
  6. 建设工程法规专科【6】
  7. python培训价格多少钱
  8. 华为云云容器引擎CCE踩坑记
  9. 什么是AOP,AOP能干什么,有什么优点
  10. 半监督3D医学图像分割(四):SASSNet