最近、私の学校では http プロキシ クラスに関するプロジェクトがあります。その目的は、ブラウザで url を入力すると、リクエストがプロキシに送信され、ホストを抽出した後、新しいリクエストと宛先サーバーへのリクエストを再作成し、宛先サーバーからデータを受信してブラウザに送り返すことです。ページをレンダリングします。
非同期 HTTP プロキシ サーバー クラスを作成します。StateObject クラスには 2 つのソケットがあります。1 つはブラウザからの新しいリクエストを処理するための workSocket で、もう 1 つは宛先ソケットを処理するための destinationSocket です。
ブラウザーから宛先サーバーに新しい要求を送信する前に、destinationSocket とハンドラー ソケットを StateObject オブジェクトに格納します。そうすることで、AsynCallBack ReceiveFromDestinationServer 関数で、destinationSocket を取得して宛先サーバーからデータを受信し、workSocket を取得して受信したデータをブラウザに送り返すことができます。そして受信したデータが終わるまでBeginReceiveを再度実行します。
この例外は、コールバック ReceiveFromDestinationServer メソッドの Socket の Send メソッドで発生します。
修正を手伝ってください。読んでくれてありがとう。
これは私のコードです:
public class ServerListerner
{
private const int TCPPort = 80;
private const string EOF = "\r\n";
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 9000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
// Bind the socket to the local endpoint and listen for incoming connections.
try {
listener.Bind(localEndPoint);
listener.Listen(100);
while (true) {
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
} catch (Exception e) {
MessageBox.Show(e.ToString());
}
}
private void AcceptCallback(IAsyncResult ar) {
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
// And begin receive data from client
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
private void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
Thread.Sleep(10);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer));
content = state.sb.ToString();
if(content != "")
{
// All the data has been read from the client.
// Change data to string array to easy access.
string[] requestLines = Regex.Split(content, EOF);
// Get remote host
string remoteHost = requestLines[0].Split(' ')[1].Replace("http://", "").Split('/')[0];
// Create a destination socket and connect to remote host at TCP port
Socket destinationSocket= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
destinationSocket.Connect(remoteHost, TCPPort);
// Send the data to destination socket.
state.workSocket = handler;
state.destinationSocket = destinationSocket;
destinationSocket.Send(state.buffer);
destinationSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveFromDestinationServer), state);
} else {
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
private void ReceiveFromDestinationServer(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket destinationSocket = state.destinationServer;
Socket client = state.workSocket;
int bytesRead = destinationSocket.EndReceive(ar);
if (bytesRead > 0)
{
client.Send(state.buffer, bytesRead, SocketFlags.None);
destinationSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveFromDestinationServer), state);
}
else
{
// Exception here
destinationSocket.Shutdown(SocketShutdown.Both);
destinationSocket.Close();
client.Close();
}
}
}
更新: ReceiveFromDestinationServer 関数 bytesRead の後に Thread.Sleep(10) を追加しました。スリープは重要だと思います。set が 10 の場合、一部のサイトはすばやく読み込みます。一部のサイトは一部の情報のみを読み込みます。set が 100 の場合、サイトの読み込み後、アプリケーションは自動的に終了します。しかし、例外はまだ存在します。