粗糙的C#版HTTP代理.docx
《粗糙的C#版HTTP代理.docx》由会员分享,可在线阅读,更多相关《粗糙的C#版HTTP代理.docx(22页珍藏版)》请在冰豆网上搜索。
![粗糙的C#版HTTP代理.docx](https://file1.bdocx.com/fileroot1/2023-1/27/0068a518-299c-4ef7-98cf-edb8917a7cbf/0068a518-299c-4ef7-98cf-edb8917a7cbf1.gif)
粗糙的C#版HTTP代理
粗糙的C#版HTTP代理
2008-8-50:
38:
21
粗糙的C#版HTTP代理
说说这段代码的问题吧。
首先是字符串切割的问题,要将客户端提交过来的GET,POST等原始请求切割,分离出主机名,端口,URL等数据。
这里用正则匹配是最好的,遗憾的是我不擅长此道,所以使用了手动切割的办法,很笨重繁琐,但是毕竟它工作得很好。
第二个问题是Keep-Alive的问题,这里我没有处理好。
最开始我在httpproxy里面修改客户端请求,强行将keep-alive修改为close,但是发现在某些站点的时候会出错。
于是使用了类似select的方法读取数据,直到超时关闭两端的连接。
我猜测,这里如果解析content-length会更好,但是略微繁琐了点,还是等我仔细阅读下RFC再看怎么修改吧。
第三个是CONNECT方法的问题,这个到很简单,转发数据就行了,因此是这个代码中写得最好的一部分,用来登陆QQ还是不错的。
说实话,我不喜欢HTTP这种太宽松的协议,感觉灵活得让我难以把握。
直接看代码吧,我加了很多debug信息,真的要用就去掉好了。
调用这个类很简单,看main函数的实现就好了。
为了方便贴代码,我写的时候就把三个类写到一个文件里面去了。
顺便要说的是,虽然有类,但是没有任何面向对象的东西——这也再次证明,其实我算不上一个程序员,最多是个代码爱好者。
usingSystem;
usingSystem.Net;
usingSystem.Net.Sockets;
usingSystem.Text;
usingSystem.IO;
usingSystem.Threading;
usingSystem.Collections;
namespaceHttpProxy
{
publicclassHttpProxy
{
intProxyPort;
///
///代理服务器入口类构造函数
///
///HttpProxy监听的端口
publicHttpProxy(intPort)
{
ProxyPort=Port;
}
///
///启动Http代理服务器
///
publicvoidStart()
{
TcpListenertcplistener=null;
try
{
//开始监听端口
tcplistener=newTcpListener(Dns.GetHostAddresses(Dns.GetHostName())[0],ProxyPort);
tcplistener.Start();
Console.WriteLine("侦听端口号:
"+ProxyPort.ToString());
}
catch(Exceptione)
{
Console.WriteLine("启动代理服务器失败:
"+e.Message);
}
while(true)
{
try
{
//接受客户端连接
Socketsocket=tcplistener.AcceptSocket();
HttpSessionSession=newHttpSession(socket);
//启动新线程,处理连接
Threadthread=newThread(newThreadStart(Session.Start));
thread.Start();
}
catch(Exceptione)
{
Console.WriteLine("接受客户端连接异常:
"+e.Message);
}
}
}
}
publicclassHttpSession
{
//客户端socket
SocketClientSocket;
//设定编码
EncodingASCII=Encoding.ASCII;
///
///构造函数
///
///客户端socket
publicHttpSession(Socketsocket)
{
this.ClientSocket=socket;
}
publicvoidStart()
{
//客户端缓冲区,读取客户端命令
Byte[]ReadBuff=newbyte[1024*10];
try
{
intLength=ClientSocket.Receive(ReadBuff);
//没有读到数据
if(0==Length)
{
Console.WriteLine("从客户端读取命令错误");
ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Close();
return;
}
}
//读取出现异常
catch(Exceptione)
{
Console.WriteLine("读取客户端异常:
"+e.Message);
}
//来自客户端的HTTP请求字符串
stringClientMsg=ASCII.GetString(ReadBuff);
//根据rnrn截取请求行
stringLine=ClientMsg.Substring(0,ClientMsg.IndexOf("rn"));
string[]CmdArray=Line.Split('');
//GET
:
80/index.phpHTTP/1
//CONNECT:
443HTTP/1
stringCmd=CmdArray[0];
stringRawUrl=CmdArray[1];
Console.WriteLine("原始请求:
",Line);
//CONNECT请求
if(Cmd=="CONNECT")
{
DoConnect(RawUrl);
}
//GET,POST和其他
else
{
DoOther(RawUrl,ClientMsg);
}
}
///
///处理CONNECT命令,此处作用是支持QQ,MSN,以及多级代理串联等
///
///
privatevoidDoConnect(stringRawUrl)
{
string[]Args=RawUrl.Split(':
');
stringHost=Args[0];
intPort=int.Parse(Args[1]);
SocketServerSocket=null;
try
{
IPAddress[]IpList=Dns.GetHostEntry(Host).AddressList;
Console.WriteLine("尝试连接:
",IpList[0],Port);
ServerSocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
ServerSocket.Connect(IpList[0],Port);
}
catch(Exceptione)
{
Console.WriteLine("连接真实服务器异常:
"+e.Message);
}
//连接真实服务器成功
if(ServerSocket.Connected)
{
ClientSocket.Send(ASCII.GetBytes("HTTP/0200Connectionestablishedrnrn"));
}
else
{
ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Close();
}
//开始转发数据
ForwardTcpData(ClientSocket,ServerSocket);
}
///
///处理GET,POST等命令。
使用了POLL,在代理服务器中强制去掉了Keep-Alive能力
///
///
///
publicvoidDoOther(stringRawUrl,stringClientMsg)
{
RawUrl=RawUrl.Substring(0+"http:
//".Length);
intPort;
stringHost;
stringUrl;
//下面是分割处理请求,此处应该用正则匹配,不过我不擅长,因此手动切割,—_—!
intindex1=RawUrl.IndexOf(':
');
//没有端口
if(index1==-1)
{
Port=80;
intindex2=RawUrl.IndexOf('/');
//没有目录
if(index2==-1)
{
Host=RawUrl;
Url="/";
}
else
{
Host=RawUrl.Substring(0,index2);
Url=RawUrl.Substring(index2);
}
}
else
{
intindex2=RawUrl.IndexOf('/');
//没有目录
if(index2==-1)
{
Host=RawUrl.Substring(0,index1);
Port=IntParse(RawUrl.Substring(index1+1));
Url="/";
}
else
{
///出现在:
之前,则说明:
后面的不是端口
if(index2{
Host=RawUrl.Substring(0,index2);
Port=80;
}
else
{
Host=RawUrl.Substring(0,index1);
Port=IntParse(RawUrl.Substring(index1+1,index2-index1-1));
}
Url=RawUrl.Substring(index2);
}
}
Console.WriteLine("Hostis:
Portis:
Urlis:
",Host,Port,Url);
IPAddress[]address=null;
try
{
IPHostEntryIPHost=Dns.GetHostEntry(Host);
address=IPHost.AddressList;
Console.WriteLine("Web服务器IP地址:
"+address[0]);
}
catch(Exceptione)
{
Console.WriteLine("解析服务器地址异常:
"+e.Message);
}
SocketIPsocket=null;
try
{
//连接到真实WEB服务器
IPEndPointipEndpoint=newIPEndPoint(address[0],Port);
IPsocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPsocket.Connect(ipEndpoint);
//对WEB服务器端传送HTTP请求命令,将原始HTTP请求中HTTPPROXY部分包装去掉
stringReqData=ClientMsg;
//改写头中的URL,
ReqData=ReqData.Replace("http:
//"+RawUrl,Url);
//按照rn切分HTTP头
string[]ReqArray=ReqData.Split(newstring[1]{"rn"},StringSplitOptions.None);
ReqData="";
//改写Keep-Alive等字段
for(intindex=0;index{
/*
if(ReqArray[index].StartsWith("Accept-Encoding:
"))
{
ReqArray[index]="Accept-Encoding:
deflate";
}
*/
if(ReqArray[index].StartsWith("Proxy-Connection:
"))
{
ReqArray[index]=ReqArray[index].Replace("Proxy-Connection:
","Connection:
");
//ReqArray[index]="Connection:
close";
}
/*
elseif(ReqArray[index].StartsWith("Keep-Alive:
"))
{
ReqArray[index]="";
}
*/
//修改后的字段组合成请求
if(ReqArray[index]!
="")
{
ReqData=ReqData+ReqArray[index]+"rn";
}
}
ReqData=ReqData.Trim();
byte[]SendBuff=ASCII.GetBytes(ReqData);
IPsocket.Send(SendBuff);
}
catch(Exceptione)
{
Console.WriteLine("发送请求到服务器异常:
"+e.Message);
}
//使用Poll来判断完成,某些站点会出问题
while(true)
{
Byte[]RecvBuff=newbyte[1024*20];
try
{
if(!
IPsocket.Poll(15*1000*1000,SelectMode.SelectRead))
{
Console.WriteLine("HTTP超时,关闭连接");
break;
}
}
catch(Exceptione)
{
Console.WriteLine("Poll:
"+e.Message);
break;
}
intLength=0;
try
{
Length=IPsocket.Receive(RecvBuff);
if(0==Length)
{
Console.WriteLine("服务端关闭");
break;
}
Console.WriteLine("从服务端收到字节",Length);
}
catch(Exceptione)
{
Console.WriteLine("Recv:
"+e.Message);
break;
}
try
{
Length=ClientSocket.Send(RecvBuff,Length,0);
Console.WriteLine("发送字节到客户端",Length);
}
catch(Exceptione)
{
Console.WriteLine("Send:
"+e.Message);
}
}
/*
//根据接收字节数来判断完成,某些站点会出问题
try
{
while(true)
{
Byte[]RecvBuff=newbyte[1024*10];
intLength=IPsocket.Receive(RecvBuff);
if(Length<=0)
{
Console.WriteLine("从服务端接收数据完成");
break;
}
Console.WriteLine("从服务端收到字节",Length);
Length=ClientSocket.Send(RecvBuff,Length,0);
Console.WriteLine("发送字节到客户端",Length);
}
}
catch(Exceptione)
{
Console.WriteLine(e.Message);
}
*/
try
{
ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Close();
IPsocket.Shutdown(SocketShutdown.Both);
IPsocket.Close();
}
catch(Exceptione)
{
//Console.WriteLine(e.Message);
}
}
///
///在客户端和服务器之间中转数据
///
///客户端socket
///服务端socket
privatevoidForwardTcpData(Socketclient,Socketserver)
{
ArrayListReadList=newArrayList
(2);
while(true)
{
ReadList.Clear();
ReadList.Add(client);
ReadList.Add(server);
try
{
Socket.Select(ReadList,null,null,1*1000*1000);
}
catch(SocketExceptione)
{
Console.WriteLine("Selecterror:
"+e.Message);
break;
}
//超时
if(ReadList.Count==0)
{
//Console.WriteLine("Timeout");
continue;
}
//客户端可读
if(ReadList.Contains(client))
{
byte[]Recv=newbyte[1024*10];
intLength=0;
try
{
Length=client.Receive(Recv,Recv.Length,0);
if(Length==0)
{
Console.WriteLine("Clientisdisconnect.");
break;
}
Console.WriteLine("Recvbytesfromclient",Length);
}
catch(Exceptione)
{
Console.WriteLine("Readfromclienterror:
"+e.Message);
break;
}
try
{
Length=server.Send(Recv,Length,0);
Console.WriteLine("Writebytestoser