0

我想使用套接字在 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,而只是将请求传输到下一个代理。所以也许这篇文章会帮助某人写一篇自己的文章。如果它得到修复...

4

1 回答 1

1

您必须在单独的线程中处理每个接受的套接字,这包括读取 CONNECT 命令。否则,读取它将阻止接受线程接受新连接。

于 2013-02-04T22:17:53.167 回答