2015-11-04 86 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以运行它。