2015-01-31 103 views
0

我正在使用java創建一個簡單的Web代理應用程序。基本上,主要方法創建一個RequestReceiver對象,該對象具有監聽Web瀏覽器http請求的ServerSocket。一個新的Connection對象是從serverSocket.accept()返回的套接字創建的,並被放入一個線程池中。Java主線程不會喚醒ServerSocket接受

我遇到的問題是,並非所有的http GET請求似乎都被serverSocket拾取。例如,在我測試的一個網頁上,我可以看到代理服務器只收到了10個GET請求中的7個。這會導致網頁掛起並需要很長時間才能加載。什麼可能導致帶有serverSocket.accept()函數的線程在創建新連接時不總是優先執行?

RequestReceiver.java

public class RequestReceiver { 
    public static final int LISTENING_PORT = 4000; 
    public static final int CONNECTION_THREAD_POOL_SIZE = 30; 

    private ServerSocket serverSocket; 
    private ThreadPoolExecutor connectionThreads; 

    public RequestReceiver() throws IOException{ 
     serverSocket = new ServerSocket(LISTENING_PORT); 
     connectionThreads = new ThreadPoolExecutor(CONNECTION_THREAD_POOL_SIZE, CONNECTION_THREAD_POOL_SIZE, 
       1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); 
    } 

    public void start(){ 
     try { 
      System.out.println("Current Pool Size: " + connectionThreads.getPoolSize() 
        + " Active threads: " + connectionThreads.getActiveCount()); 
      Connection conn = new Connection(serverSocket.accept()); 
      System.out.println("Created a new connection thread. Request from " + conn.clientSocketToString()); 
      connectionThreads.execute(conn); 
     } catch (IOException e) { 
      System.err.println("Exception occured when accepting a new connection."); 
      e.printStackTrace(); 
     } 
    } 
} 

Connection.java

public class Connection implements Runnable{ 

public static final int REPLY_CHUNK_SIZE = 32768; 
public static final int DEFAULT_WEB_SERVER_PORT = 80; 
public static final int SERVER_SOCKET_TIMEOUT = 0; // milliseconds 
public static final int CLIENT_SOCKET_TIMEOUT = 0; // milliseconds 

private Socket clientSocket, serverSocket; 
private InputStream clientIS, serverIS; 
private OutputStream clientOS, serverOS; 

public Connection(Socket clientSocket){ 
    this.clientSocket = clientSocket; 
    // set client socket timeout 
    try{ 
     clientSocket.setSoTimeout(CLIENT_SOCKET_TIMEOUT); 
    }catch(SocketException soe){ 
     soe.printStackTrace(); 
    } 
} 

@Override 
public void run() { 
    String connection = ""; 
    try{ 
     // setup client streams 
     clientIS = clientSocket.getInputStream(); 
     clientOS = clientSocket.getOutputStream(); 
     // get the request from the browser 
     String request = ""; 
     String hostname = ""; 
     String[] hostAndPort = new String[2]; 
     request = browserInputStreamToString(clientIS); 
     hostname = getHostName(request); 
     hostAndPort = hostname.split(":"); 
     connection = "Connection to: " + hostname + " from " + clientSocket.getInetAddress().getHostName() 
       + ":" + clientSocket.getPort() + " Request: " + request.split(System.getProperty("line.separator"))[0]; 
     System.out.println("OPENED>> " + connection); 
     // Attempt to create socket to server 
     serverSocket = new Socket(hostAndPort[0], (hostAndPort.length > 1 ? new Integer(hostAndPort[1]):DEFAULT_WEB_SERVER_PORT)); 
     // set timeout 
     serverSocket.setSoTimeout(SERVER_SOCKET_TIMEOUT); 
     // Set up server streams 
     serverIS = serverSocket.getInputStream(); 
     serverOS = serverSocket.getOutputStream(); 
     // send client request to server 
     serverOS.write(request.getBytes()); 
     serverOS.flush(); 
     // send server response to client in chunks 
     byte[] reply = new byte[REPLY_CHUNK_SIZE]; 
     int replyLength = serverIS.read(reply); 
     while(replyLength != -1){ 
      clientOS.write(reply, 0, replyLength); 
      clientOS.flush(); 
      replyLength = serverIS.read(reply); 
     } 
     // close sockets 
     clientSocket.close(); 
     serverSocket.close(); 
    }catch(Exception e){ 
     e.printStackTrace(); 
    } finally{ 
     try { 
      if(clientSocket != null){ 
       clientSocket.close(); 
      } 
      if(serverSocket != null){ 
       serverSocket.close(); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    System.out.println("CLOSED>> " + connection); 
} 

編輯:從catch語句刪除return語句

+0

您的服務器套接字看起來像接受單個連接,然後退出。是不斷調用啓動方法的東西? – jtahlborn 2015-01-31 22:18:16

+0

@jtahlborn主類有一個連續調用start()方法的while(true)循環 – Darkphenom 2015-01-31 22:22:04

+0

不要編寫這樣的代碼。每個方法只能有一個catch(IOException)塊。依賴於'try'塊中代碼成功的代碼應該在同一個'try'塊中。並且不要在內部循環中沖洗。 – EJP 2015-01-31 23:32:41

回答

0

當你說7出10,你的意思是你測試的10倍或幾次,並得到這個速度?我問,因爲默認隊列大小是50,所以如果你測試了很多,你可能會遇到隊列問題。如果你還沒有改變隊列大小..

其他的事情,也關於隊列大小。你有幾個回報和嘗試緩存。如果發生任何事情,您將無法完成您的連接關閉。所以當隊列滿時,你會得到超時,直到當前連接關閉。其他相關問題,資源泄漏。

+0

我的意思是當瀏覽器發送10個GET請求來加載一個網站時,只有7個被serverSocket.accept()方法拾取並創建了新的Connection對象(這是以空隊列開始的)。這是一個公平的觀點,我編輯了Connection類以從catch語句中刪除返回語句。但是,問題仍然存在。 – Darkphenom 2015-01-31 23:04:31

+0

我明白了,你能在這裏更新嗎?所以我們可以嘗試用您的新版本再次幫助您;因爲你的改變消除了我的答案。 – Victor 2015-01-31 23:07:38

+0

好吧,我很抱歉,我無法幫助。我希望答案至少有幫助,因爲泄漏是真實的。任何我想到線程的方式,當連接到達時,您將放入阻塞隊列,隊列可能是延遲,執行程序正在讀取和寫入,並且連接快速到達。一個新的連接將不得不等待,直到你在這個阻塞操作後重新接受。這不應該避免隊列上的連接 - 最多隻能延遲一次。除非瀏覽器達到了自己的超時時間。如果你找到答案,請在這裏發帖,我很好奇。 – Victor 2015-02-01 00:02:27