对于一个学校项目,我正在制作一个必须符合 http 1.0 而不是 1.1 的多客户端代理(这样更容易)。老师告诉我最好让它完全异步。所以我做了一个完全异步的代理,只有一个问题。它仅在我将 threadleep 放入其中时才有效,但这并不能使它更快,但这是让它工作的唯一方法。请帮我找到一个解决方案,也许有人知道为什么它需要线程睡眠才能让它工作?
老师每年都会看到这个问题,唯一找到的解决方案就是threadsleep,所以老师还没有找到真正的解决方案。
首先是表单的简单代码。该表单有一个开始按钮和一个用于查看请求的文本框和一个用于查看响应的文本框。在表单之后是代理的代码。顺便说一句,在 Internet Explorer 中,您可以切换到 http 1.0 模式,这是最好的测试方式,您还需要让浏览器监听代理服务器(在 de 代码中列出)。
using System;
using System.Windows.Forms;
using System.Threading;
namespace Proxy
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void startProxy_Click(object sender, EventArgs e)
{
var proxy = new Proxy(requestView, respondsView);
var thread = new Thread(new ThreadStart(proxy.StartProxy));
thread.IsBackground = true;
thread.Start();
startProxy.Enabled = false;
}
}
}
现在存在问题的代理...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace Proxy
{
class Proxy
{
private TextBox requestView;
private TextBox respondsView;
private delegate void UpdateLogCallback(string strMessage, TextBox txtView);
public const int PROXY_PORT = 5008;
public const int WEB_PROXY_PORT = 80;
public const int BACKLOG = 20;
public const int TIMEOUT = 4000;
public Proxy(TextBox _requestView, TextBox _respondsView)
{
requestView = _requestView;
respondsView = _respondsView;
}
public void StartProxy()
{
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Unspecified);
clientSocket.Bind(new IPEndPoint(IPAddress.Any, PROXY_PORT));
clientSocket.Listen(BACKLOG);
clientSocket.BeginAccept(HandleConnection, clientSocket);
}
private void HandleConnection(IAsyncResult iar)
{
Socket clientSocket = iar.AsyncState as Socket;
Socket client = clientSocket.EndAccept(iar);
clientSocket.BeginAccept(HandleConnection, clientSocket);
SocketData data = new SocketData() { SocketToClient = client };
client.BeginReceive(data.buffer, 0, SocketData.BUFFER_SIZE, SocketFlags.None, OnDataArrived, data);
}
private void OnDataArrived(IAsyncResult iar)
{
SocketData socketdata = iar.AsyncState as SocketData;
int bytesreceived = 0;
UpdateLogCallback uLC = new UpdateLogCallback(ReceiveMessages);
socketdata.SocketToClient.ReceiveTimeout = TIMEOUT;
try
{
bytesreceived = socketdata.SocketToClient.EndReceive(iar);
if (bytesreceived == SocketData.BUFFER_SIZE)
{
socketdata.sb.Append(ASCIIEncoding.ASCII.GetString(socketdata.buffer, 0, bytesreceived));
socketdata.SocketToClient.BeginReceive(socketdata.buffer, 0, SocketData.BUFFER_SIZE, SocketFlags.None, OnDataArrived, socketdata);
}
else
{
socketdata.sb.Append(ASCIIEncoding.ASCII.GetString(socketdata.buffer, 0, bytesreceived));
string strContent = socketdata.sb.ToString();
string[] testing = strContent.Split(' ');
if (testing[0] == "CONNECT")
{
//this is to prevent weird request to microsoft servers(???) also prevents ssl request...
}
else
{
IPEndPoint ip = new IPEndPoint(Dns.GetHostEntry(GetHostnameFromRequest(strContent)).AddressList[0], WEB_PROXY_PORT);
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Unspecified);
server.Connect(ip);
requestView.Invoke(new UpdateLogCallback(uLC), new object[] { strContent, requestView });
server.Send(System.Text.ASCIIEncoding.ASCII.GetBytes(strContent));
socketdata.SocketToServer = server;
server.BeginReceive(socketdata.buffer2, 0, SocketData.BUFFER_SIZE, SocketFlags.None, OnWebsiteDataArrived, socketdata);
}
}
}
catch
{
socketdata.SocketToClient.Close();
}
}
private void OnWebsiteDataArrived(IAsyncResult iar)
{
SocketData socketdata = iar.AsyncState as SocketData;
int bytesreceived = 0;
UpdateLogCallback uLC = new UpdateLogCallback(ReceiveMessages);
socketdata.SocketToServer.ReceiveTimeout = TIMEOUT;
try
{
bytesreceived = socketdata.SocketToServer.EndReceive(iar);
Thread.Sleep(10);
if (bytesreceived == SocketData.BUFFER_SIZE)
{
socketdata.sb2.Append(ASCIIEncoding.ASCII.GetString(socketdata.buffer2, 0, bytesreceived));
socketdata.SocketToClient.Send(socketdata.buffer2, 0, SocketData.BUFFER_SIZE, SocketFlags.None);
socketdata.SocketToServer.BeginReceive(socketdata.buffer2, 0, SocketData.BUFFER_SIZE, SocketFlags.None, OnWebsiteDataArrived, socketdata);
}
else
{
socketdata.sb2.Append(ASCIIEncoding.ASCII.GetString(socketdata.buffer2, 0, bytesreceived));
respondsView.Invoke(new UpdateLogCallback(uLC), new object[] { socketdata.sb2.ToString(), respondsView });
socketdata.SocketToClient.Send(socketdata.buffer2, 0, bytesreceived, SocketFlags.None);
socketdata.SocketToClient.Close();
socketdata.SocketToServer.Close();
}
}
catch
{
socketdata.SocketToClient.Close();
}
}
private static string GetHostnameFromRequest(string strContent)
{
string[] host = strContent.Split(new string[] { "\r\n", ": " }, StringSplitOptions.RemoveEmptyEntries);
int check = Array.IndexOf(host, "Host");
return host[check + 1];
}
public void ReceiveMessages(string receiveMessages, TextBox txtView)
{
if (txtView.InvokeRequired)
{
UpdateLogCallback uLC = new UpdateLogCallback(ReceiveMessages);
txtView.Invoke(new UpdateLogCallback(uLC), new object[] { receiveMessages, txtView });
}
else
{
txtView.AppendText(receiveMessages);
}
}
public class SocketData
{
public SocketData()
{
this.packetlenght = 0;
}
public Socket SocketToClient { get; set; }
public Socket SocketToServer { get; set; }
public StringBuilder sb = new StringBuilder();
public StringBuilder sb2 = new StringBuilder();
public const int BUFFER_SIZE = 128;
public byte[] buffer = new byte[BUFFER_SIZE];
public byte[] buffer2 = new byte[BUFFER_SIZE];
public int packetlenght { get; set; }
}
}
}