粗糙的C#版HTTP代理.docx
- 文档编号:3517305
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:22
- 大小:20.06KB
粗糙的C#版HTTP代理.docx
《粗糙的C#版HTTP代理.docx》由会员分享,可在线阅读,更多相关《粗糙的C#版HTTP代理.docx(22页珍藏版)》请在冰豆网上搜索。
粗糙的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;
///
///代理服务器入口类构造函数
///
///
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;
///
///构造函数
///
///
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); } } /// ///在客户端和服务器之间中转数据 /// /// /// 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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 粗糙 C# HTTP 代理