2015-11-04 135 views
0

我對Stack Overflow有點新,所以如果我做了任何不正確的事情,請隨時告訴我。我還沒有發現另一篇文章,以一種對我有意義的方式來解決這個問題。多線程Java代理服務器

所以我的最終目標是用Java編寫一個多線程HTTP代理服務器,但作爲第一步,我只是試圖將通過瀏覽器建立的連接的輸入流寫入窗口。

這裏是我的代碼:

private static ServerSocket welcomeSocket; 
private static Socket connectionSocket; 

private static Socket clientSocket; 

private static OutputStream clientOutput; 
private static InputStream proxyInput; 

private static BufferedReader reader; 

private static InetSocketAddress clientStream; 

public static void main(String[] args) throws IOException, URISyntaxException { 

    // Create socket, port 12345, for incoming request 
    welcomeSocket = new ServerSocket(12345); 
    while(true){ 
     try(Socket clientSocket = welcomeSocket.accept()){ 
     BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
     BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())); 

     Thread t = new Thread(){ 
      public void run(){ 
       System.out.println("running\n"); 
       try{ 
        System.out.println("trying\n"); 
        String lineIn; 
        while((lineIn = reader.readLine()) != null){ 
         System.out.println("writing\n"); 
         writer.write(lineIn); 
         writer.newLine(); 
        } 
       } 
       catch(IOException i){ 
        try {        
         Logger.getLogger(EECS325_Project1.class.getName()).log(Level.SEVERE, null, i); 
         throw i; 
        } catch (IOException ex) { 
         Logger.getLogger(EECS325_Project1.class.getName()).log(Level.SEVERE, null, ex); 
        } 
       } 
      } 
     }; 
     t.start(); 
     } 
    } 

} 

然而,當我去到本地主機:12345在我的瀏覽器,我得到以下異常:

 Nov 04, 2015 9:53:44 AM eecs325_project1.EECS325_Project1$1 run 
    SEVERE: null 
    java.net.SocketException: socket closed 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) 
    at java.net.SocketInputStream.read(SocketInputStream.java:170) 
    at java.net.SocketInputStream.read(SocketInputStream.java:141) 
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) 
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) 
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) 
    at java.io.InputStreamReader.read(InputStreamReader.java:184) 
    at java.io.BufferedReader.fill(BufferedReader.java:161) 
    at java.io.BufferedReader.readLine(BufferedReader.java:324) 
    at java.io.BufferedReader.readLine(BufferedReader.java:389) 
    at eecs325_project1.EECS325_Project1$1.run(EECS325_Project1.java:46) 

大部分帖子說,出現這種異常時關閉讀寫器,有效關閉插座。但是,我絕不會關閉閱讀器,書寫器或套接字。

任何幫助將不勝感激!

+1

「但是,我從來沒有關閉過讀卡器,寫卡器或插座。」你這樣做,當try-with-resources完成時:'try(Socket clientSocket = welcomeSocket.accept()){'。 –

+0

@AndyTurner謝謝!我現在看到了這個問題,但我不確定解決問題的恰當方法。我添加了一個finally關閉套接字的語句,如果它不爲null,但它似乎在此之前關閉。有什麼想法嗎? – Haley

+1

您需要將套接字「切換」到線程。在成功調用start之後,將對套接字的本地引用設置爲null,以便它不再在finally外部塊中關閉。由於線程現在擁有套接字,因此您需要確保_thread_關閉finally塊中的套接字。 – jtahlborn

回答

1

Try-with-resources塊會在線程執行前關閉客戶端套接字 - 這意味着readerwriter在線程嘗試使用它們時引用已關閉的基礎數據流。

對此的解決方案,以試戴與資源塊移動到線程內:

final Socket clientSocket = welcomeSocket.accept(); 
Thread t = new Thread(){ 
    @Override public void run(){ 
    // BufferedReader/Writer close the underlying stream when they 
    // are closed, so the socket will be closed when this 
    // try-with-resources block finishes. 
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))); 
     BufferedWriter writer = ...) { 
     // Do whatever. 
    } catch (IOException e) { 
     // Handle the exception. 
    } 
    } 
}; 
t.start(); 

這意味着不會發生關閉,直到線程運行,更具體你後過用readerwriter完成了處理。

注意:您必須注意確保套接字始終爲 closed:如果在創建線程或創建BufferedReader時出現異常,則不會發生這種情況。這些情況有點困難,並且涉及一些額外的try/catch/finally塊;我寧願不將這些添加到答案中,因爲我認爲他們只是模糊了主要想法。

0
rivate static ServerSocket welcomeSocket; 
private static Socket connectionSocket; 

private static Socket clientSocket; 

private static OutputStream clientOutput; 
private static InputStream proxyInput; 

private static BufferedReader reader; 

private static InetSocketAddress clientStream; 

不這些數據項應是靜態的,並且涉及一個特定的客戶端(接受插座,其上游插座,和它們的流)的那些中的一個應該是在一個單獨的Runnable連接處理程序類,它是爲每個接受的套接字實例化並創建一個Thread以運行它。