一个代理程序的简单实现流程为:
代理服务器创建socket--->绑定socket--->监听socket--->accept--->成功时再创建一新的socket与http服务器端进行连接请求(connect)--->与服务器端连接成功后调用select函数查看socket状态,如过与客户端连接的socket有数据读,则读出该数据并向服务器端转发该报文,同理如果与服务器端连接的socket有数据读,则读出该数据向客户端转发。
相关程序如下:该程序可以实现在服务器端和客户端转发包的功能,
#include "stdafx.h"
#include <stdio.h>
#include <Winsock2.h>
#include <signal.h>
#include <iostream.h>
#include <Windows.h>
#include <io.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
int main(int argc, char* argv[])
{
struct sockaddr_in address,address1;
int i,j,s,s1,tn[4]={0};
int err;
int new_s,n1;
int n=0;
int ret;
struct timeval t2;
char buf[1000],buftem[1000];
int optLen = sizeof(int);
fd_set r, w, e;
WORD wVer;
WSADATA wsaData;
wVer=MAKEWORD(1,1);
err=WSAStartup(wVer,&wsaData);//判断Windows sockets dll版本,初始化
if(err!=0)
return(0);
s = socket (AF_INET, SOCK_STREAM, 0);//创建socket
if (s == -1)
{j=WSAGetLastError();
return -1;
}
i = 1;
address.sin_family = AF_INET;
address.sin_port = htons (8000);//监听端口8000
address.sin_addr.s_addr = INADDR_ANY;
if (bind (s, (struct sockaddr *)&address, sizeof (address)) == -1)
{
return -1;
}
if (listen (s, 1) == -1)//监听,设置监听队列为1,为了简化程序
{
return -1;
}
printf("正在等待请求,请稍后。。。。。。/n");
new_s=accept(s,NULL,NULL);//accept客户端连接,new_s是用于代理和客户端的连接
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//创建新连接,用于连接http服务器
address.sin_family=AF_INET;
address.sin_addr.s_addr = inet_addr( "127.0.0.1" );//http服务器ip地址
address.sin_port = htons( 80 );
if (ConnectSocket!=INVALID_SOCKET)
{
printf("socket创建/n");
int nn=connect( ConnectSocket, (SOCKADDR*) &address, sizeof(address) );}//进行连接
while(1)//循环处理
{
FD_ZERO (&r);
FD_ZERO (&w);
FD_ZERO (&e);
FD_SET(new_s,&r);
FD_SET(new_s,&w);
FD_SET(new_s,&e);
FD_SET(ConnectSocket,&r);
FD_SET(ConnectSocket,&w);
FD_SET(ConnectSocket,&e);
t2.tv_sec=5;
t2.tv_usec=5*1000;
ret=select(new_s+1,&r,&w,&e,NULL);//查看socket状态
if(FD_ISSET(new_s,&r))//如果客户端发送数据包,则接收并转发服务器端
{
n = recv(new_s, buf, strlen(buf),0);
if(n!=-1)
{
tn[0]++;
printf("这是从客户端收到的第%d包,内容是:%s,/n报文长度:%d./n",tn[0],buf,n);//打印相关信息用于调试
n1=send(ConnectSocket,buf,n,0);
if(n1!=-1)
{
tn[1]++;
printf("向服务器端转发报文数%d,转发报文长度%d/n",tn[1],n1);
}
}
}
if(FD_ISSET(ConnectSocket,&r))//如果服务器端发送数据包,接收并转发客户端
{
n1=recv(ConnectSocket,buftem,strlen(buftem),0);
if(n1!=-1)
{
tn[2]++;
printf("这是从服务器端收到的第%d包,内容是:%s,报文长度是:%d./n",tn[2],buftem,n1);
if(FD_ISSET(new_s,&w))
//strcat(buftem,"#13#10");
{n = send(new_s, buftem,n1,0);
if(n!=-1)
{
tn[3]++;
printf("向客户端转发报文数%d,转发报文长度%d./n",tn[3],n);
//if(tn[3]==50)///此处因为程序会无限循环发报,所以设置一最大转发包进行控制
//{break;}
}
}
//Sleep(200);
}
}
}
}
程序可以在vc环境中直接执行(新建工程的时候选择控制台),运行时如将break语句去掉则能在浏览器中打开所需网页,但此刻服务器一直在重发最后一包数据(此时客户端已收到最后一包数据,转发中间包时没有这个问题),请问这是为什么?另当数据包转发完毕后如何将连接保持keep alive?如一直保持while循环则很耗资源反之若终止while循环则连接关闭,浏览器将显示无法打开网页。我查看了一些tcp连接发现还有个timewait状态,这是怎么实现的?希望各位高手能给个建议或解决的方法,谢谢了!我的QQ是264116549,如有需要可以和我QQ.