下面是一个先前我用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);