我想编写一个简单的服务器来侦听端口并生成新线程来处理新连接。 我试图使用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)中的示例接受连接但立即关闭。 有人可以向我解释原因并告诉我我是如何正确地做到这一点的吗?
答案 0 :(得分:5)
结构
try (resource = ...) {
}
相当于
resource = null;
try {
resource = ...;
} finally {
if (resource != null) {
resource.close();
}
}
那就是它。它只是一种语法糖,只是写出相同的更短的方式。因此,当您将语句Socket clientSocket = serverSocket.accept();
放入try-with-resource块时,实际上在离开块后将其关闭。
当同步完成流处理时,即打开流,读取或写入并关闭它时,此结构很好。
在您的情况下,您获取流并在单独的线程中处理它,因此无法立即关闭它。客户端应决定关闭流本身。例如,当用户按下按钮"断开"或当服务器发送特殊应用程序级别命令"关闭连接"或者如果抛出IOException
。