我想使用套接字在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()
阻挡引起的还是有点种族?也许整个方法都错了?或者它是线程的一些障碍?
P.S。我的“原生”语言是C ++。虽然我偶尔会遇到Java编程语言,但我仍然没有足够的经验来使用它的库,尤其是套接字。
PPS 我认为http代理服务器这样的东西在互联网上有多个教程和操作方法,但我发现所有内容都是单线程或不读取目标网址和只是将请求发送到下一个代理。所以这篇文章可能会帮助某人写一篇文章。如果它得到修复......
答案 0 :(得分:1)
您必须在单独的线程中处理每个接受的套接字,包括读取CONNECT命令。否则,持有读取将阻止接受线程接受新连接。