您的位置:首页 > 理论基础 > 计算机网络

用socket实现自己的HTTP代理服务器

2015-08-31 17:44 519 查看
下面是一个先前我用socket实现HTTP代理服务器的例子,代码很简单我就不一一解析了,要注意的是:当该代理服务器收到IE发来的请求时,要将IE请求行中的webserver的域名(或者IP)剥去,再将请求转发给webserver,如果不注意这点而是直接毫无处理的把IE请求信息直接发给webserver某些网站会显示不了网页,比如新浪,pfan,这是测试时发现的,其他就没什么可以说的了。实际上能否完成这个简单的HTTP proxy server可以看出对HTTP协议的熟悉程度,只要有一定的sock编程基础并熟悉了HTTP协议的工作流程,那我想就没什么障碍了。著此文章以供初学者参考,能从里面得到一点点的帮助那我已经心满意足了,高人指点改进意见邮箱联系,下面是源代码:

#include <stdio.h>

#include <iostream>

#include <string>

#include <fstream>

#include <winsock2.h>

#include <process.h>

#include "SockInit.h"

using namespace std;

#define MAX_REQUEST_LEN 2048 // IE请求长度

char szFileName[] ="2004041155.txt"; // 日志文件

CSockInit initSock; // initalize winsock

CRITICAL_SECTION CriticalSection; // 临界区对象(global variable)

void __cdecl ServerThreadProc(void *param);

/************************************************

调试环境:Visual C++6.0 SP6+platform SDK 2003 R2

程序名称:HTTP proxy Server(HttpProxySvr.cpp)

功能 :IE通过设置代理方式上网,IE所有请求均

先发到该代理服务器,代理服务器记录IE请

求日志 ,并将请求直接转发给webserver,

从webserver读取响应后发回IE

Date: 2007/10/12

author: liqisong

eamil : liqisong611@yahoo.com.cn

**************************************************/

int main()

{

USHORT uPort=9999; // 通信端口

SOCKET sListen = socket(AF_INET,SOCK_STREAM,0);

if(sListen == INVALID_SOCKET)

{

printf("Failed socket(),error code :%d",WSAGetLastError());

return 0;

}

sockaddr_in sin;

sin.sin_addr.S_un.S_addr = INADDR_ANY;

sin.sin_family =AF_INET;

sin.sin_port = htons(uPort);

if(bind(sListen,(sockaddr*)&sin,sizeof(sin))==SOCKET_ERROR)

{

printf("Failed bind(),error code :%d",WSAGetLastError());

closesocket(sListen);

return 0;

}

int res =listen(sListen,200);

sockaddr_in addrRemote; // IE地址信息

int len =sizeof(addrRemote);

SOCKET sNew; // 新建立的连接状态套接口

InitializeCriticalSection(&CriticalSection);

while(true)

{

sNew = accept(sListen,(sockaddr*)&addrRemote,&len);

if(sNew == INVALID_SOCKET)

{

printf("Failed accept(),error code :%d",WSAGetLastError());

DeleteCriticalSection(&CriticalSection);

closesocket(sListen);

return 0;

}

printf("收到一个IE连接(IP:%s)\n",inet_ntoa(addrRemote.sin_addr));

// 创建一个线程处理该连接 (每客户单线程模式...)

stParam *pParam = new stParam;

pParam->s = sNew;

pParam->addr = addrRemote;

_beginthread(ServerThreadProc,0,(void*)pParam);

}

DeleteCriticalSection(&CriticalSection);

closesocket(sListen);

return 0;

}

void __cdecl ServerThreadProc(void *param)

{

stParam *pParam = (stParam*)param;

SOCKET sock = pParam->s; // 与浏览器连接的套接口

sockaddr_in addrIE = pParam->addr; // 与浏览器连接的套接口地址信息

delete pParam;

char request[MAX_REQUEST_LEN];

memset(request,0,MAX_REQUEST_LEN);

int res =TCPrecv(sock,request,MAX_REQUEST_LEN,0); // 接收浏览器(客户端)发来的请求

if(res==0)

{

printf("连接断开\n");

shutdown(sock,SD_RECEIVE);

closesocket(sock);

return;

}

else if(res==SOCKET_ERROR)

{

printf("Failed recv(),error code:%d\n",WSAGetLastError());

shutdown(sock,SD_RECEIVE);

closesocket(sock);

return;

}

shutdown(sock,SD_RECEIVE);

// printf("header length :%d header: %s\n",res,request);// 打印收到的请求

// 分析请求行(分离出WebServer域名)

char szAddrName[1024]={0}; // 域名

char szRequestLine[1024]={0}; // 请求行

string strHeader; // 头部

char *pdest;

int pos,count=0;

char ch =' ';

ofstream fout; // 日志文件

pdest = strchr(request, ch ); // 寻找空格第一次出现的位置

if( pdest == NULL )

{

printf( "Result:\t%c not found,error HTTP request\n" );

closesocket(sock);

return;

}

pos = pdest - request+8; // +8 <==> + strlen("http://")+1;

int i =pos;

while(request[i]!='/'&&i<res)

{

szAddrName[i-pos] = request[i];

i++;

}

szAddrName[i-pos]='\0';

printf("WebServer address: %s\n\n",szAddrName);

pos = pdest - request; // 空格第一次出现的位置

pdest = strchr(request,'\n'); // 寻找\n第一次出现的位置

count = pdest - request+1;

strncpy(szRequestLine,request,count); // 得到请求行(末尾包含了"\r\n")

strHeader=pdest+1; // 得到头部

// 做日志记录

EnterCriticalSection(&CriticalSection); // 进入临界区

fout.open(szFileName,ios::app); // 追加的方式

if(fout.fail())

{

printf("Input file(2004041155.txt) opening failed.\n");

closesocket(sock);

LeaveCriticalSection(&CriticalSection);

return;

}

SYSTEMTIME st;

GetLocalTime(&st);

fout<<"Request line:\r\n("<<inet_ntoa(addrIE.sin_addr)<<")"<<szRequestLine<<st.wYear<<"-"<<st.wMonth<<"-"<<st.wDay<<" "

<<st.wHour<<":"<<st.wMinute<<":"<<st.wSecond<<endl;

// fout.close();

// 将请求行处理一下(使用相对URI连接WebServer)

while(szRequestLine[i]!='/0'&&i<1024)

{

szRequestLine[++pos] = szRequestLine[i++];

}

szRequestLine[++pos]='\0';

strcpy(request,szRequestLine);

strcat(request,strHeader.c_str()); // 得到新请求(等于处理过后的请求行+ 头部)

// cout<<"New request:"<<request<<endl;

// 向WebServer提交请求

SOCKADDR_IN saServer;

LPHOSTENT lphostent;

SOCKET hsocket;

int nRet;

// 通过域名获得目标WebServer的IP

if(isalpha(szAddrName[0])) /* server address is a name*/

{

lphostent = gethostbyname(szAddrName);

}

else

{

unsigned long addr = inet_addr(szAddrName);

lphostent = gethostbyaddr((const char*)&addr,4,AF_INET);

}

if(lphostent==NULL)

{

printf("Cannot resolve address,error code:%d\n",WSAGetLastError());

closesocket(sock);

fout.close();

LeaveCriticalSection(&CriticalSection);

return ;

}

hsocket = socket(AF_INET,SOCK_STREAM,0);

if(hsocket==INVALID_SOCKET)

{

printf("Failed socket(),error code:%d\n",WSAGetLastError());

closesocket(sock);

fout.close();

LeaveCriticalSection(&CriticalSection);

return ;

}

saServer.sin_family = AF_INET;

saServer.sin_port = htons(80);

saServer.sin_addr= *((LPIN_ADDR)*lphostent->h_addr_list);

nRet = connect(hsocket,(sockaddr*)&saServer,sizeof(saServer));

if(nRet==SOCKET_ERROR)

{

printf("Failed connect(),error code:%d\n",WSAGetLastError());

closesocket(sock);

closesocket(hsocket);

fout.close();

LeaveCriticalSection(&CriticalSection);

return;

}

// 向webserver转发IE请求

nRet = TCPsend(hsocket,request,strlen(request),0);

char dest[1000];

nRet=1;

int senlen=0;

memset(dest,0,1000);

nRet=recv(hsocket,dest,sizeof(dest)-1,0); // 从webserver获取响应行

if(nRet==0)

{

printf("与webserver(%s)的连接关闭\n",szAddrName);

shutdown(hsocket,SD_RECEIVE); //关闭接收操作

closesocket(sock);

closesocket(hsocket);

fout.close();

LeaveCriticalSection(&CriticalSection);

return;

}

else if(nRet==SOCKET_ERROR)

{

printf("Failed recv(),error code:%d\n",WSAGetLastError());

shutdown(hsocket,SD_RECEIVE); //关闭接收操作

closesocket(sock);

closesocket(hsocket);

fout.close();

LeaveCriticalSection(&CriticalSection);

return;

}

// 取出响应行,处理之...

dest[nRet]='\0';

char szRespondLine[1000]={0};

char *pch;

pdest = strchr(dest,'\n'); //'\n'第一 次出现的位置

count = pdest - dest+1;

pdest++; //越过'\n'

pch = strchr(pdest,'\n'); // '\n'第二次出现的位置

count +=(pch -pdest+1);

strncpy(szRespondLine,dest,count);

szRespondLine[count]='\0';

cout<<szRespondLine;

// 记录响应状态日志

fout<<"Respond line:\r\n"<<szRespondLine;

fout<<"-----------------------------------\r\n";

fout.close();

LeaveCriticalSection(&CriticalSection); // 退出临界区

senlen = TCPsend(sock,dest,nRet,0); //将数据转发给IE浏览器

if(senlen==0)

{

printf("与浏览器(%s)的一个连接关闭...\n",inet_ntoa(addrIE.sin_addr));

closesocket(sock);

closesocket(hsocket);

return;

}

else if(senlen==SOCKET_ERROR)

{

printf("Failed send(),error code:%d\n",WSAGetLastError());

closesocket(sock);

closesocket(hsocket);

return;

}

// 循环接收webserver发来的数据,直至该连接关闭...

while(nRet>0)

{

memset(dest,0,1000);

nRet=recv(hsocket,dest,sizeof(dest),0); // 从webserver获取数据

if(nRet==0)

{

printf("与webserver(%s)的连接关闭\n",szAddrName);

shutdown(hsocket,SD_RECEIVE); //关闭接收操作

break;

}

else if(nRet==SOCKET_ERROR)

{

printf("Failed recv(),error code:%d\n",WSAGetLastError());

break;

}

senlen = TCPsend(sock,dest,nRet,0); //将数据转发给IE浏览器

if(senlen==0)

{

printf("与浏览器(%s)的一个连接关闭...\n",inet_ntoa(addrIE.sin_addr));

break;

}

else if(senlen==SOCKET_ERROR)

{

printf("Failed send(),error code:%d\n",WSAGetLastError());

break;

}

// printf("%s\n",dest);

} // end of while(nRet>0)

closesocket(sock);

closesocket(hsocket);

}

int TCPsend(SOCKET s,const char *buf,int len,int flags)

{

int n=0,sendCount=0;

int length =len;

if(buf==NULL)

return 0;

while(length>0)

{

n=send(s,buf+sendCount,length,flags); //发送数据,

if(n==0)

{

break;

}

if(n==SOCKET_ERROR)//网络出现异常

{

printf("Failed send(),error code:%d\n",WSAGetLastError());

break;

}

length-=n;

sendCount+=n;

}

return sendCount; // 返回已发送的字节数

}

int TCPrecv(SOCKET s,char *buf,int len,int flags)

{

int nRev=0,recvCount=0;

int length =len;

if(buf==NULL)

return 0;

// 循环接收数据

while(length>0)

{

nRev =recv(s,buf+recvCount,length,flags);

if(nRev==0)

{

break;

}

if(nRev==SOCKET_ERROR)//网络出现异常

{

printf("Failed recv(),error code:%d\n",WSAGetLastError());

break;

}

length-=nRev;

recvCount+=nRev;

}

return recvCount; //返回接收到的字节数

}

/ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /

// sockinit.h

#include <Winsock2.h>

#pragma comment(lib,"Ws2_32.lib")

class CSockInit

{

public:

CSockInit(BYTE minorVer =2,BYTE majorVer =2)

{

// 初始化Ws2_32.dll

WORD wVersionRequested;

WSADATA wsaData;

int err;

wVersionRequested = MAKEWORD( minorVer, majorVer);

err = WSAStartup( wVersionRequested, &wsaData );

if (err != 0 )

{

exit(1);

}

if( LOBYTE( wsaData.wVersion ) != majorVer ||HIBYTE( wsaData.wVersion ) != minorVer )

{

WSACleanup();

exit(1);

}

}

~CSockInit()

{

WSACleanup();

}

};

// 线程参数结构体

struct stParam

{

SOCKET s; // 连接状态的套接字

sockaddr_in addr; // 对方地址信息

};

// 自己实现TCP的收发函数

int TCPsend(SOCKET s,const char*buf,int len,int flags);

int TCPrecv(SOCKET s,char *buf,int len,int flags);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: