目录
实验一 HTTP代理服务器的设计与实现 1
一、 实验目的 1
二、 实验内容 1
(3) 扩展 HTTP 代理服务器,支持如下功能: 1
三、实验过程及结果 2
1、实验原理 2
(1) Socket 编程的客户端和服务器端主要步骤 2
(2)等待客户请求到达该端口; 2
(3)请求结束后关闭通信通道并终止。 3
(1)客户与服务器进程的作用是非对称的,因此代码不同。 3
(2) HTTP 代理服务器的基本原理与流程图 3
(3) HTTP 代理服务器实验验证过程以及实验结果 5
(4)实现 HTTP 代理服务器的关键技术及解决方案 11
5.代理服务器设置cahce实现方式 12
6. 网站过滤 13
7. 用户过滤 13
8.网站引导 13
四、实验心得 13
服务器端:
其过程是首先服务器方要先启动,并根据请求提供相应服务:
(1)打开一通信通道并告知本地主机,它愿意在某一公认地址上的某端口接收客户请求;对应的操作是申请一个socket,这时的socket称为“欢迎套接字”,然后绑定(bind)本地地址信息和欢迎套接字,然后开放监听(listen)。
(2)等待客户请求到达该端口;
(3)接收到客户端的服务请求时,处理该请求并发送应答信号。在TCP实现过程中进行了三次握手操作,但是实际编写过程中通过accept函数即可实现上述操作,并建立连接,注意这个时候才真正建立起了与客户机传输数据的套接字。接收到并发服务请求,要激活一新进程来处理这个客户请求。新进程处理此客户请求,并不需要对其它请求作出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。
(4)返回第(2)步,等待另一客户请求。
(5)关闭服务器,对应的也就是关闭服务器的欢迎套接字。
客户端:
(1)打开一通信通道,即建立起要与服务器传输数据的套接字socket,通过connect连接到服务器所在主机的特定端口;
(2)向服务器发服务请求报文,等待并接收应答;继续提出请求…
(3)请求结束后关闭通信通道并终止。
从上面所描述过程可知:
(1)客户与服务器进程的作用是非对称的,因此代码不同。
(2)服务器进程一般是先启动的。只要系统运行,该服务进程一直存在,直到正常或强迫终止。
(2) HTTP 代理服务器的基本原理与流程图
代理服务器,俗称“翻墙软件”,允许一个网络终端(一般为客户端),通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。
如图 1-1 所示,为普通 Web 应用通信方式与采用代理服务器的通信方式的对比。
#pragma comment(lib,"Ws2_32.lib")
#define MAXSIZE 65507 //发送数据报文的最大长度
#define HTTP_PORT 80 //http 服务器端口
#define CACHE_MAXSIZE 100
#define DATELENGTH 40
//Http 重要头部数据
struct HttpHeader{
char method[4]; // POST 或者 GET,注意有些为 CONNECT,本实验暂不考虑
char url[1024]; // 请求的 url
char host[1024]; // 目标主机
char cookie[1024 * 10]; //cookie
HttpHeader(){
ZeroMemory(this, sizeof(HttpHeader));
}
};
//这个是高仿的htpp的头部数据,用于在cache中找到对象,但是节约了cookie的空间
struct cache_HttpHeader{
char method[4]; // POST 或者 GET,注意有些为 CONNECT,本实验暂不考虑
char url[1024]; // 请求的 url
char host[1024]; // 目标主机
cache_HttpHeader(){
ZeroMemory(this, sizeof(cache_HttpHeader));
}
};
//实现代理服务器的缓存技术
struct __CACHE{
cache_HttpHeader htphed;
char buffer[MAXSIZE];
char date[DATELENGTH];//存储的更新时间
__CACHE(){
ZeroMemory(this->buffer, MAXSIZE);
ZeroMemory(this->buffer, sizeof(date));
}
};
int __CACHE_number = 0;//标记下一个应该放缓存的位置
__CACHE cache[CACHE_MAXSIZE];//真`缓存
BOOL InitSocket();
BOOL ParseHttpHead(char *buffer, HttpHeader * httpHeader);
BOOL ConnectToServer(SOCKET *serverSocket, char *host);
unsigned int __stdcall ProxyThread(LPVOID lpParameter);
int Cache_find(__CACHE *cache, HttpHeader htp);
//代理相关参数
SOCKET ProxyServer;
sockaddr_in ProxyServerAddr;
const int ProxyPort = 10240;
//禁止访问的主机,禁用网站
char* host[10] = { "today.hit.edu.cn", "jwts.hit.edu.cn", "resource.hit.edu.cn", "www.hit.edu.cn" };
const int host_number = 4;
//网站诱导
char* host_to_another = "djangobook.py3k.cn" ;//诱导到pt.hit.edu.cn,url=http://pt.hit.edu.cn/ ,url源=http://djangobook.py3k.cn/2.0/
char* another[2] = { "pt.hit.edu.cn","http://pt.hit.edu.cn/" };//跳转到的地址
//char* host_to_another = "www.pku.edu.cn";
//char* another[2] = { "today.hit.edu.cn", "http://today.hit.edu.cn/" };
//char Cache[][];
//由于新的连接都使用新线程进行处理,对线程的频繁的创建和销毁特别浪费资源
//可以使用线程池技术提高服务器效率
//const int ProxyThreadMaxNum = 20;
//HANDLE ProxyThreadHandle[ProxyThreadMaxNum] = {0};
//DWORD ProxyThreadDW[ProxyThreadMaxNum] = {0};
struct ProxyParam{
SOCKET clientSocket;
SOCKET serverSocket;
};
int _tmain(int argc, _TCHAR* argv[])
{
printf("代理服务器正在启动\n");
printf("初始化...\n");
if (!InitSocket()){
printf("socket 初始化失败\n");
return -1;
}
printf("代理服务器正在运行,监听端口 %d\n", ProxyPort);
SOCKET acceptSocket = INVALID_SOCKET;
ProxyParam *lpProxyParam;
HANDLE hThread;
DWORD dwThreadID;
//代理服务器不断监听
sockaddr_in verAddr;
int hahaha = sizeof(SOCKADDR);
while (true){
acceptSocket = accept(ProxyServer, (SOCKADDR*)&verAddr, &(hahaha));
lpProxyParam = new ProxyParam;
if (lpProxyParam == NULL){
continue;
}
if (!strcmp("127.0.0.1", inet_ntoa(verAddr.sin_addr))){
printf("被限制的用户访问!\n");
continue;
}
lpProxyParam->clientSocket = acceptSocket;
hThread = (HANDLE)_beginthreadex(NULL, 0,
&ProxyThread, (LPVOID)lpProxyParam, 0, 0);
CloseHandle(hThread);
Sleep(200);
}
closesocket(ProxyServer);
WSACleanup();
return 0;
}