一、计算机网络之HTTP代理服务器

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

代理服务器,俗称 “翻墙软件” ,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。如图所示,为普通 Web 应用通信方式与采用代理服务器的通信方式的对比。

实现的是多用户代理服务器,实现线程的并行执行。 首先,代理服务器创建 HTTP 代理服务的 TCP 主套接字,通过该主套接字监听等待客户端的连接请求。当客户端连接之后,创建一个子线程,由子线程执行上述一对一的代理过程,服务结束之后子线程终止。与此同时,主线程继续接受下一个客户的代理服务。

实验环境配置

打开IE(windows)-> 工具 -> Internet选项 -> 连接 -> 局域网设置 -> 代理服务器 
如下设置地址和端口号(端口号和程序中保持一致即可(最好使用较大的,低端口一般被占用))

基本的HTTP代理服务器,实现简单,不用处理直接转发接收到目的服务器的报文即可。因此不作介绍,主要讲解实现的扩展功能。

1网站过滤的实现
基本思想:通过解析客户端请求的buffer,获取请求的URL,然后设置关键字,再次使用c++中的一个函数strstr,判断关键字是否在其子串中

bool ForbiddenToConnect(char *httpheader)
{char * forbiddernUrl = ".edu.cn"; //屏蔽的含有关键字的网址if (strstr(httpheader, forbiddernUrl)!=NULL) //是否含有屏蔽的关键字{return false;}else return true;
}

2用户过滤的实现
基本思想:通过客户端请求,获取请求用户的IP,然后在程序运行时,设置一个IP禁止表,在IP禁止表中存入一些IP地址,在请求之后就去查询是否在IP禁止表中,如果是,则关闭socket即可,等待下一次的请求。

char client_IP[16];
//设置禁用IP,可以在此添加更多
memcpy(ForbiddenIP[IPnum++], "127.0.0.1", 16);
//设置访问哪些网站会被重定向到钓鱼网站
memcpy(fishUrl[fishUrlnum++], "http://www.asus.com.cn/",23);
memcpy(fishUrl[fishUrlnum++],"http://pku.edu.cn/",18);
while (true) {int ff;ff = sizeof(acceptAddr);acceptSocket = accept(ProxyServer, (SOCKADDR*)&acceptAddr,&(ff));printf("获取用户IP地址:%s\n",inet_ntoa(acceptAddr.sin_addr));memcpy(client_IP, inet_ntoa(acceptAddr.sin_addr),16);//用户IP保存//禁用用户IP访问if (UserIsForbidden(client_IP)){printf("IP被禁用\n");closesocket(acceptSocket);//system("pause");//break;}

重点是
c++ acceptSocket = accept(ProxyServer, (SOCKADDR*)&acceptAddr,&(ff)); 
获取请求IP的方法。如果最后一个参数设置的是0,则返回的IP一直是204.204.204.204,显然不是请求的IP地址,因此需要作上述处理,先获取acceptAddr的大小,然后其地址作为accept函数的地址

3钓鱼网站的实现(钓鱼网站)
基本思想:设置一个钓鱼网站的URL表,如果请求的URL在此URL表中,则丢弃其的请求报文,转成302报文发送,在302报文中定位到钓鱼网站的网址,从而实现访问请求网站自动重定向到钓鱼网站

//网站引导  访问pku.edu.cn  asus.com 重定向到 today.hit.edu.cn
if (GotoFalseWebsite(httpHeader->url))
{   //302报文 对客户端的请求直接截断重定向到其他页面//数据内容主要的就两条://"HTTP/1.1 302 Moved Temporarily"//"Location: 路径"//生成302报文,直接发送给客户端char* pr;  int fishing_len = strlen("HTTP/1.1 302 Moved Temporarily\r\n"); //302报文memcpy(FishBuffer, "HTTP/1.1 302 Moved Temporarily\r\n", fishing_len);pr = FishBuffer + fishing_len;//重定向到今日哈工大fishing_len = strlen("Location: http://today.hit.edu.cn/\r\n\r\n");  //定向的网址memcpy(pr, "Location: http://today.hit.edu.cn/\r\n\r\n", fishing_len);//将302报文返回给客户端ret = send(((ProxyParam*)lpParameter)->clientSocket, FishBuffer, sizeof(FishBuffer), 0);goto error;
}

4cache的实现
基本思想:cache作为代理服务器的缓存管理。首先,客户端请求报文,需要在cache中查询,如果命中,则进行访问目标服务器,缓存是否过期,未过期则直接将缓存的报文转发给客户端,过期则将目标服务器返回的报文进行更新cache;未命中,则直接请求目标服务器,将目标服务器的返回报文更新到cache中,并发送给客户端。

//cache 实现if (Have_cache) //请求有缓存{char cached_buffer[MAXSIZE];//缓存bufferZeroMemory(cached_buffer, MAXSIZE);memcpy(cached_buffer, Buffer, recvSize);//构造缓存的报文头char* pr = cached_buffer + recvSize;memcpy(pr, "If-modified-since: ", 19);pr += 19;int lenth = strlen(Cache[last_cache].last_modified);memcpy(pr, Cache[last_cache].last_modified, lenth);pr += lenth;//将客户端发送的 HTTP 数据报文直接转发给目标服务器ret = send(((ProxyParam *)lpParameter)->serverSocket, cached_buffer, strlen(cached_buffer) + 1, 0);//等待目标服务器返回数据recvSize = recv(((ProxyParam *)lpParameter)->serverSocket, cached_buffer, MAXSIZE, 0);if (recvSize <= 0) {goto error;}//解析包含缓存信息的HTTP报文头CacheBuffer = new char[recvSize + 1];ZeroMemory(CacheBuffer, recvSize + 1);memcpy(CacheBuffer, cached_buffer, recvSize);char last_status[4];//用于记录主机返回的状态字char last_modified[30];//用于记录记住返回的页面修改的时间ParseCache(CacheBuffer, last_status, last_modified);delete CacheBuffer;//分析cache的状态字if (strcmp(last_status, "304") == 0) {//没有被修改printf("页面没有修改过,缓存的url为:%s\n", Cache[last_cache].url);//将缓存的数据直接转发给客户端ret = send(((ProxyParam*)lpParameter)->clientSocket, Cache[last_cache].buffer, sizeof(Cache[last_cache].buffer), 0);if (ret != SOCKET_ERROR){printf("来自缓存++++++++++++++\n");}}else if (strcmp(last_status, "200") == 0) {//已经修改了//修改缓存中的内容printf("页面已经被修改过,缓存的url为:%s\n", Cache[last_cache].url);memcpy(Cache[last_cache].buffer, cached_buffer, strlen(cached_buffer));//新的buffer 存在缓存中memcpy(Cache[last_cache].last_modified, last_modified, strlen(last_modified)); //修改时间存入缓存//将目标服务器返回的数据直接转发给客户端ret = send(((ProxyParam*)lpParameter)->clientSocket, cached_buffer, sizeof(cached_buffer), 0);if (ret != SOCKET_ERROR){printf("来自修改过的缓存-----------\n");}}}else //没有缓存过这个页面{//将客户端发送的 HTTP 数据报文直接转发给目标服务器ret = send(((ProxyParam *)lpParameter)->serverSocket, Buffer, strlen(Buffer) + 1, 0);if (ret != SOCKET_ERROR){printf("成功发送给目标服务器的报文buffer \n \n");}//等待目标服务器返回数据recvSize = recv(((ProxyParam *)lpParameter)->serverSocket, Buffer, MAXSIZE, 0);if (recvSize == SOCKET_ERROR){printf("目标服务器未返回数据\n");goto error;}//将目标服务器返回的数据直接转发给客户端ret = send(((ProxyParam*)lpParameter)->clientSocket, Buffer, sizeof(Buffer), 0);if (ret != SOCKET_ERROR){printf("来自服务器************\n成功发送给客户端的报文(目标服务器返回的)buffer ret = %d \n", ret);}}//错误处理
error:printf("关闭套接字\n");Sleep(200);closesocket(((ProxyParam*)lpParameter)->clientSocket);closesocket(((ProxyParam*)lpParameter)->serverSocket);delete lpParameter;_endthreadex(0);

cache的报文头解析

//*************************
//Method: ParseHttpHead0
//FullName: ParseHttpHead0
//Access: public
//Returns: void
//Qualifier: 解析 TCP 报文中的 HTTP 头部
//Parameter: char *buffer
//Parameter: HttpHeader *httpHeader
//*************************int ParseHttpHead0(char *buffer, HttpHeader *httpHeader) {int flag = 0;//用于表示Cache是否命中,命中为1,不命中为0char *p;char *ptr;const char *delim = "\r\n";//回车换行符                           p = strtok_s(buffer, delim, &ptr);if (p[0] == 'G') {  //GET方式memcpy(httpHeader->method, "GET", 3);memcpy(httpHeader->url, &p[4], strlen(p) - 13);printf("url:%s\n", httpHeader->url);//url                                       for (int i = 0; i < 1024; i++) {//搜索cache,看当前访问的url是否已经存在cache中了if (strcmp(Cache[i].url, httpHeader->url) == 0) {//说明url在cache中已经存在flag = 1;   //只要存在,flag标识变量置为1break;}}if (!flag && cached_number != 1023) {//说明url没有在cache且cache没有满, 把这个url直接存进去memcpy(Cache[cached_number].url, &p[4], strlen(p) - 13);last_cache = cached_number;}else if (!flag && cached_number == 1023) {//说明url没有在cache且cache满了//为了简单,替换第一个memcpy(Cache[0].url, &p[4], strlen(p) - 13);last_cache = 0;}}else if (p[0] == 'P') { //POST方式memcpy(httpHeader->method, "POST", 4);memcpy(httpHeader->url, &p[5], strlen(p) - 14);for (int i = 0; i < 1024; i++) {if (strcmp(Cache[i].url, httpHeader->url) == 0) { //同上flag = 1;break;}}if (!flag && cached_number != 1023) {memcpy(Cache[cached_number].url, &p[5], strlen(p) - 14);last_cache = cached_number;}else if (!flag && cached_number == 1023) {memcpy(Cache[0].url, &p[4], strlen(p) - 13);last_cache = 0;}}p = strtok_s(NULL, delim, &ptr);while (p) {switch (p[0]) {case 'H'://HOSTmemcpy(httpHeader->host, &p[6], strlen(p) - 6);if (!flag && cached_number != 1023) {memcpy(Cache[last_cache].host, &p[6], strlen(p) - 6);cached_number++;}else if (!flag && cached_number == 1023) {memcpy(Cache[last_cache].host, &p[6], strlen(p) - 6);}break;case 'C'://Cookieif (strlen(p) > 8) {char header[8];ZeroMemory(header, sizeof(header));memcpy(header, p, 6);if (!strcmp(header, "Cookie")) {memcpy(httpHeader->cookie, &p[8], strlen(p) - 8);}}break;//case '':default:break;}p = strtok_s(NULL, delim, &ptr);}return flag;
}

重复一遍,源码地址

计算机网络之HTTP代理服务器相关推荐

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

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

  2. Android平台Chromium net中的代理配置信息获取

    在计算机网络中,代理服务器 扮演着发起请求的客户端与服务器之间的中间人的角色.客户端连接到代理服务器,请求一些服务,比如文件,网页,或其它可以从服务器获得的资源,代理服务器以简化和控制复杂度的形式获取 ...

  3. kali定位目标地理位置

    一.GPS简介及分布 物理位置定位:根据IP的定位不准确,容易被欺骗,网上有很多IP伪造技术,所以定位肯定也不准确. GPS全球定位系统: GPS是英文Global Positioning Syste ...

  4. kali精准定位地理位置

    目录 一.GPS简介 二.定位工具:seeker 三.反向代理:ngrok 四.实战:获取目标地理位置 一.GPS简介 物理位置定位:根据IP的定位不准确,容易被欺骗,网上有很多IP伪造技术,所以定位 ...

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

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

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

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

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

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

  8. 哈工大计算机网络实验一:HTTP代理服务器(Java语言实现)

    目录 1 总体思路 1.1 基本理论简述 1.2 具体实现的思路 1.3 环境及项目结构 2 主函数部分(ProxyServer) 2.1 主循环 2.1.1 读取并解析http请求首部 2.1.2 ...

  9. 计算机网络-HTTP代理服务器

    啥也不说,上代码 把项目目录组织成这个样子 package main; import constants.ProxyConstants; import thread.ProxyThread; impo ...

最新文章

  1. PHP数组用处_PHP 数组函数妙用
  2. java写大文件_java实现超大文件的读写功能
  3. 珠宝条码打印扫描解决方案
  4. 【转】HTML - embed 与 object 之争
  5. 程序员修神之路--打通Docker镜像发布容器运行流程
  6. css3实现的精美菜单
  7. PAT乙级(1037 在霍格沃茨找零钱 )
  8. linux 物理内存不知道怎么占用,Linux系统下如何查看物理内存占用率
  9. “整洁代码根本就是个骗局!”
  10. 有关语音识别技术的一些信息点
  11. SWS_BICUBIC未声明的标识符解决方法
  12. 2016年美团校园招聘数据开发工程师笔试编程题
  13. 思科2960交换机telnet连接配置
  14. 每日必读DZone news - 2022年2月十大DZone文章
  15. python 按键精灵脚本_按键精灵的脚本 - 对于重复动作(含键盘鼠标)太好用了
  16. Salesforce市值3000亿美元,中国CRM企业能复制成功吗?
  17. [每天读一点英文:那些给我勇气的句子] alone but not lonely
  18. 离心机 TFN A17CH 微量高速冷冻离心机 17800r/min 触摸屏 轻型便捷微量高速
  19. 蹭WiFi掉黑客陷进怎么破
  20. 【应用多元统计分析】上机四五——主成分分析因子分析

热门文章

  1. 【正点原子Linux连载】第七章 系统信息与系统资源-摘自【正点原子】I.MX6U嵌入式Linux C应用编程指南V1.1
  2. AI-支持向量机分类预测
  3. 为什么学习使我快乐?
  4. 最高效的学习法:一遍学习法
  5. 相对位姿误差(RPE)和绝对轨迹误差(ATE)
  6. setTimeout实现setInterval
  7. setbkcolor
  8. 手把手叫教你设置无线路由器桥接模式
  9. Clickhouse 数据字典dictionary引擎
  10. 影音服务器 Linux,centos7安装plex影音媒体服务器