学校のプロジェクトでは、1.1 ではなく http 1.0 に準拠する必要があるマルチクライアント プロキシを作成しています (これにより簡単になります)。先生からは、完全に非同期にしたほうがいいと言われました。そこで、完全に非同期のプロキシを作成しました。問題は 1 つだけです。スレッドスリープを入れた場合にのみ機能しますが、これで高速になるわけではありませんが、機能させる唯一の方法です。解決策を見つけるのを手伝ってください。おそらく誰かがそれを機能させるためにスレッドスリープが必要な理由を知っていますか?
教師は毎年この問題に直面しており、見つかった唯一の解決策はスレッドスリープであるため、教師は実際の解決策を見つけていません。
まず、フォームの簡単なコードです。フォームには、開始ボタンと、リクエストを表示するためのテキスト ボックス、および応答を表示するためのテキスト ボックスがあります。フォームの後にプロキシのコードが続きます。ところで、Internet Explorer では http 1.0 モードに切り替えることができるので、これがテストする最良の方法です。また、ブラウザがプロキシサーバー (コードにリストされています) をリッスンするようにする必要があります。
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; }
}
}
}