我想使用套接字在 Java 中编写一个简单的 http 代理服务器。我编写了一个测试原型,由我在互联网上找到的几个教程组成。这么久了,我来了:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleProxyServer
{
public static final int portNumber = 55558;
public static final int maxConnections = 100;
public static void main( String[] args )
{
SimpleProxyServer proxyServer = new SimpleProxyServer();
proxyServer.start();
}
public void start()
{
System.out.println("Starting the SimpleProxyServer ...");
try
{
ServerSocket serverSocket = new ServerSocket( portNumber, maxConnections );
byte[] buffer = new byte[10000];
boolean run = true;
while( run )
{
Socket clientSocket = serverSocket.accept();
InputStream clientInputStream = clientSocket.getInputStream();
// reading the request and put it into buffer
final int readBytesCount = clientInputStream.read( buffer );
if( readBytesCount < 0)
continue;
String browserRequest = new String( buffer, 0, readBytesCount );
System.out.println( browserRequest );
// extract the host to connect to
final int hostNameStart = browserRequest.indexOf( "Host: " ) + 6;
final int hostNameEnd = browserRequest.indexOf( '\n', hostNameStart );
final String hostName = browserRequest.substring( hostNameStart, hostNameEnd - 1 );
System.out.println( "Connecting to host " + hostName );
// forward the response from the proxy to the server
Socket hostSocket = new Socket( hostName, 80 );
OutputStream hostOutputStream = hostSocket.getOutputStream();
System.out.println( "Forwarding request to server" );
hostOutputStream.write( buffer, 0, readBytesCount );
hostOutputStream.flush();
ProxyThread thread1 = new ProxyThread( clientSocket, hostSocket );
thread1.start();
ProxyThread thread2 = new ProxyThread( hostSocket, clientSocket );
thread2.start();
}
serverSocket.close();
}
catch( IOException e )
{
System.err.println( "IO Error: " + e.getMessage() );
e.printStackTrace();
}
}
}
class ProxyThread extends Thread
{
private Socket incoming, outgoing;
ProxyThread( Socket in, Socket out )
{
incoming = in;
outgoing = out;
}
// Overwritten run() method of thread,
// does the data transfers
public void run()
{
System.out.println( "Starting proxy thread" );
try
{
OutputStream toClient = outgoing.getOutputStream();
InputStream fromClient = incoming.getInputStream();
int numberRead = 0;
byte[] buffer = new byte[10000];
do
{
numberRead = fromClient.read( buffer );
System.out.println( "Read " + numberRead + " bytes" );
System.out.println( "Buffer: " + buffer );
if( numberRead > 0 )
{
toClient.write( buffer, 0, numberRead );
System.out.println( "Sent " + numberRead + " bytes" );
}
}
while( numberRead > 0 );
System.out.println( "Closing all streams and sockets" );
toClient.flush();
incoming.close();
outgoing.close();
}
catch( IOException e )
{
System.err.println( "IO Error: " + e.getMessage() );
}
catch( ArrayIndexOutOfBoundsException e )
{
System.err.println( "Index error: " + e.getMessage() );
}
}
}
在使用浏览器(如果有帮助的话,Firefox)进行测试时,它会fromClient.read(buffer)
长时间挂起并冻结调用并返回 -1,但浏览器会更早地显示连接拒绝。它的原因是什么?它是由InputStream.read()
阻塞引起的还是有点像比赛?也许整个方法是错误的?或者它是线程的一些障碍?
PS我的“本机”语言是C++。虽然我偶尔有一些 Java 编程语言的经验,但我仍然没有足够的经验使用它的库,尤其是套接字。
PPS我认为诸如 http 代理服务器之类的东西在互联网上有多个教程和操作方法,但我发现的只是单线程或不读取目标 URL,而只是将请求传输到下一个代理。所以也许这篇文章会帮助某人写一篇自己的文章。如果它得到修复...