[英]Troubleshooting a simple proxy server
我使用同步方法和System.Net和System.Net.Sockets类在C#中编写了一个简单的代理服务器。 除一处小故障外,大多数事情都已完成。
当我从代理客户端(例如www.google.com)浏览URL时,它可以正常打开。 当我进行关键字搜索时,它也很好。 但是,当我单击搜索结果时,客户端会再次在屏幕上看到google.com主页! 但是,客户端浏览器的网址栏仍显示被单击的搜索结果网址。 也许发生这种情况是因为google结果页未提供指向结果url的直接链接,而是提供了指向google本身的链接,而且我认为代码中的中继逻辑无法处理该问题。 你能帮我吗? 我的代码如下:( ThreadHandleClient()方法是处理所有客户端请求并中继请求和响应的重要方法)
public void Start(IPAddress ip, int port)
{
try
{
TcpListener listener = new TcpListener(ip, port);
listener.Start(100);
while (!stopFlag)
{
Socket client = listener.AcceptSocket();
IPEndPoint rep = (IPEndPoint)client.RemoteEndPoint;
Thread th = new Thread(ThreadHandleClient);
th.Start(client);
}
listener.Stop();
}
catch (Exception ex)
{
Debug.Print("START: " + ex.Message);
}
}
public void Stop()
{
stopFlag = true;
}
public void ThreadHandleClient(object o)
{
try
{
Socket client = (Socket)o;
Debug.Print("lingerstate=" + client.LingerState.Enabled.ToString() + " timeout=" + client.LingerState.LingerTime.ToString());
NetworkStream ns = new NetworkStream(client);
//RECEIVE CLIENT DATA
byte[] buffer = new byte[2048];
int rec = 0, sent = 0, transferred = 0, rport = 0;
string data = "";
do
{
rec = ns.Read(buffer, 0, buffer.Length);
data += Encoding.ASCII.GetString(buffer, 0, rec);
} while (rec == buffer.Length);
//PARSE DESTINATION AND SEND REQUEST
string line = data.Replace("\r\n", "\n").Split(new string[] { "\n" }, StringSplitOptions.None)[0];
Uri uri = new Uri(line.Split(new string[] { " " }, StringSplitOptions.None)[1]);
Debug.Print("CLIENT REQUEST RECEIVED: " + uri.OriginalString);
if (uri.Scheme == "https")
{
rport = 443;
Debug.Print("HTTPS - 443");
//rq = HttpVersion + " 200 Connection established\r\nProxy-Agent: Prahlad`s Proxy Server\r\n\r\n";
//ClientSocket.BeginSend(Encoding.ASCII.GetBytes(rq), 0, rq.Length, SocketFlags.None, new AsyncCallback(this.OnOkSent), ClientSocket);
}
else
{
rport = 80;
Debug.Print("HTTP - 443");
}
IPHostEntry rh = Dns.GetHostEntry(uri.Host);
Socket webserver = new Socket(rh.AddressList[0].AddressFamily, SocketType.Stream, ProtocolType.IP);
webserver.Connect(new IPEndPoint(rh.AddressList[0], rport));
byte[] databytes = Encoding.ASCII.GetBytes(data);
webserver.Send(databytes, databytes.Length, SocketFlags.None);
Debug.Print("SENT TO SERVER. WILL NOW RELAY: " + data);
//START RELAY
buffer = new byte[2048];
bool firstTime = true;
rec = 0;
data = "";
do
{
transferred = 0;
do
{
if (webserver.Poll((firstTime ? 9000 : 2000) * 1000, SelectMode.SelectRead))
{
rec = webserver.Receive(buffer, buffer.Length, SocketFlags.None);
Debug.Print("RECEIVED FROM WEBSERVER[" + rec.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec));
firstTime = false;
sent = client.Send(buffer, rec, SocketFlags.None);
Debug.Print("SENT TO CLIENT[" + sent.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec));
transferred += rec;
}
else
{
Debug.Print("No data polled from webserver");
}
} while (rec == buffer.Length);
Debug.Print("loop-1 finished");
//if (transferred == 0)
// break;
//transferred = 0;
rec = 0;
do
{
if (client.Poll(1000 * 1000, SelectMode.SelectRead))
{
rec = client.Receive(buffer, buffer.Length, SocketFlags.None);
Debug.Print("RECEIVED FROM CLIENT: " + Encoding.ASCII.GetString(buffer, 0, rec));
sent = webserver.Send(buffer, rec, SocketFlags.None);
Debug.Print("SENT TO WEBSERVER[" + sent.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec));
transferred += rec;
}
else
{
Debug.Print("No data polled from client");
}
} while (rec == buffer.Length);
Debug.Print("loop-2 finished");
} while (transferred > 0);
Debug.Print("LOOP ENDS. EXITING THREAD");
client.Close();
webserver.Close();
}
catch (Exception ex)
{
Debug.Print("Error occured: " + ex.Message);
}
finally {
Debug.Print("Client thread closed");
}
}
经过反复试验,我找到了解决方案,因此我在回答自己的问题。 我的中继逻辑的问题在于它曾经用于两种方式中继,即从webserver-> client和client-> webserver。 我意识到中继第二部分可能会导致重定向出现问题,因为在重定向中,标头的url部分(“ GET http://debian.org HTTP / 1.1”)会突然更改,因此与网络服务器正在中继! 例如,google重定向指向debian.org,而代理仍将中继来自google.com而非debian.org的流量。 为了避免这种情况,我删除了第二个中继部分(即client-> webserver)。 如果客户端发送新请求,则最好在单独的线程中处理它,以便将其定向到正确的url主机。 因此,我要做的就是注释掉中继逻辑中的第二个内部循环:
//rec = 0;
//do
//{
// if (client.Poll(3000 * 1000, SelectMode.SelectRead))
// {
// rec = client.Receive(buffer, buffer.Length, SocketFlags.None);
// Debug.Print("RECEIVED FROM CLIENT: " + Encoding.ASCII.GetString(buffer, 0, rec));
// sent = webserver.Send(buffer, rec, SocketFlags.None);
// Debug.Print("SENT TO WEBSERVER[" + sent.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec));
// transferred += rec;
// }
// else
// {
// Debug.Print("No data polled from client");
// }
//} while (rec == buffer.Length);
//Debug.Print("loop-2 finished");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.