尝试使用资源关闭产生的孩子的插座

时间:2014-12-01 15:02:13

标签: java multithreading sockets try-with-resources

我想编写一个简单的服务器来侦听端口并生成新线程来处理新连接。 我试图使用try-with-resources来接受新的连接但是失败了,因为子线程中的套接字似乎立即关闭,我不明白为什么。

以下是2个简化示例 a)服务器的工作示例(没有try-with-resources):

package MyTest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServerA implements Runnable  {
    private int port;
    private ServerSocket serverSocket;

    public MyServerA(Integer port)  {
        this.port = port;
    }

    @Override
    public void run() {
        try     {   
            serverSocket = new ServerSocket(port);
        } catch(IOException ioe) {
            System.err.println("error opening socket. " + ioe.getStackTrace());
        }

        while (true) {
            Socket clientSocket = null;
            try {
                clientSocket = serverSocket.accept();
                ClientServiceThread cliThread = new ClientServiceThread(clientSocket);
                cliThread.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    class ClientServiceThread extends Thread {
        private Socket s;
        boolean goOn = true;

        ClientServiceThread(Socket s) {
            this.s = s;
        }

        public void run() {
            BufferedReader in = null;
            PrintWriter out = null;

            try {
                in = new BufferedReader(new InputStreamReader(this.s.getInputStream()));
                out = new PrintWriter(new OutputStreamWriter(this.s.getOutputStream()));

                while (goOn) {
                    final String req = in.readLine();
                    if (req != null) {
                        System.out.println("got: " + req);
                        out.println("you said: " + req);
                        out.flush();

                        if (req.contains("bye")) {
                            System.out.println("closing thread");
                            goOn = false;
                        }
                    }
                }
                s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        MyServerA a = new MyServerA(30000);
        a.run();
    }
}

b)完全相同,但尝试使用资源(不起作用):

package MyTest;

import java.io.BufferedReader;

public class MyServerB implements Runnable  {
    private int port;
    private ServerSocket serverSocket;

    public MyServerB(Integer port)  {
        this.port = port;
    }

    @Override
    public void run() {
        try {   
            serverSocket = new ServerSocket(port);
        } catch(IOException ioe) {
            System.err.println("error opening socket. " + ioe.getStackTrace());
        }

        while (true) {
            try (Socket clientSocket = serverSocket.accept();) {
                ClientServiceThread cliThread = new ClientServiceThread(clientSocket);
                cliThread.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    class ClientServiceThread extends Thread {
        private Socket s;
        boolean goOn = true;

        ClientServiceThread(Socket s) {
            this.s = s;
        }

        public void run() {
            BufferedReader in = null;
            PrintWriter out = null;

            try {
                in = new BufferedReader(new InputStreamReader(this.s.getInputStream()));
                out = new PrintWriter(new OutputStreamWriter(this.s.getOutputStream()));

                while (goOn) {
                    final String req = in.readLine();
                    if (req != null) {
                        System.out.println("got: " + req);
                        out.println("you said: " + req);
                        out.flush();

                        if (req.contains("bye")) {
                            System.out.println("closing thread");
                            goOn = false;
                        }
                    }
                }
                s.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        MyServerB b = new MyServerB(30000);
        b.run();
    }
}

a)中的示例与预期的一样。 b)中的示例接受连接但立即关闭。 有人可以向我解释原因并告诉我我是如何正确地做到这一点的吗?

1 个答案:

答案 0 :(得分:5)

结构

try (resource = ...) {
} 

相当于

resource = null;
try {
   resource = ...;
}  finally {
    if (resource != null) {
        resource.close();
    }
}

那就是它。它只是一种语法糖,只是写出相同的更短的方式。因此,当您将语句Socket clientSocket = serverSocket.accept();放入try-with-resource块时,实际上在离开块后将其关闭。

当同步完成流处理时,即打开流,读取或写入并关闭它时,此结构很好。

在您的情况下,您获取流并在单独的线程中处理它,因此无法立即关闭它。客户端应决定关闭流本身。例如,当用户按下按钮"断开"或当服务器发送特殊应用程序级别命令"关闭连接"或者如果抛出IOException