最近,在我的学校有一个关于http代理类的项目。所以它的目的是当你在浏览器上输入url时,请求到达你的代理,提取主机后,你重新创建一个新的请求并请求目标服务器,然后,你将从目标服务器接收数据并发送回浏览器到渲染一个页面。
我创建了一个异步 http 代理服务器类。在 StateObject 类中,我有两个套接字,一个是 workSocket 来处理来自浏览器的新请求,第二个是 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)。我认为睡眠很重要,当设置为10时,有些站点加载速度很快,有些站点只加载一些信息,当设置为100时,加载站点后,应用程序会自动退出。但例外仍然存在。