这个单线程回声服务器工作得很好。
public class Server {
public static void main(String[] args) throws IOException {
try (ServerSocket sc = new ServerSocket(1111)) {
while (true) {
try (Socket dataSocket = sc.accept();
BufferedReader is = new BufferedReader(
new InputStreamReader(
dataSocket.getInputStream()));
PrintWriter out = new PrintWriter(
dataSocket.getOutputStream());) {
String line;
while ((line = is.readLine()) != null) {
System.out.println(line);
out.println(line);
out.flush();
if (line.equals("Bye."))
break;
}
}
}
}
}
}
但是为什么这个多线程版本不工作?它只是传递输入和输出流来构造一个TestServer1线程并启动它。没什么特别的。但是当客户端连接到该服务器时,在run()
中抛出"Stream close"
异常并打印"error in run"
。
public class TestServer1 extends Thread{
BufferedReader in;
PrintWriter out;
public TestServer1(BufferedReader in, PrintWriter out){
this.in=in;
this.out=out;
}
@Override
public void run(){
String line;
try{
while ((line = in.readLine()) != null) {
System.out.println(line);
out.println(line);
out.flush();
if (line.equals("Bye."))
break;
}
} catch (IOException e){
System.out.println("error in run");
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
try (ServerSocket sc = new ServerSocket(1111)) {
while (true) {
try (Socket dataSocket = sc.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(
dataSocket.getInputStream()));
PrintWriter out = new PrintWriter(
dataSocket.getOutputStream());) {
TestServer1 ts1=new TestServer1(in, out);
ts1.start();
}
}
}
}
}
下面是stacktrace
error in run
java.io.IOException: Stream closed
at java.io.BufferedReader.ensureOpen(BufferedReader.java:115)
at java.io.BufferedReader.readLine(BufferedReader.java:310)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at server.TestServer1.run(TestServer1.java:22)
Java 7: Try with resources
使用Java 7,您可以在尝试中创建一个或多个"资源"声明。"资源"是实现java.lang.AutoCloseable接口。这个资源是自动关闭并结束try块。
- 查看更多信息:http://www.vineetmanohar.com/2011/03/java-7-try-with-auto-closable-resources/#sthash.cnvRzGIZ.dpuf
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
在本例中,try-with-resources语句中声明的资源是一个BufferedReader。声明语句出现在try关键字后面的圆括号内。在Java SE 7及更高版本中,BufferedReader类实现了Java .lang. autocloseable接口。因为BufferedReader实例是在try-with-resource语句中声明的,所以无论try语句是正常完成还是突然完成(由于BufferedReader方法),它都将关闭。
链接:http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
所以这可能是原因,当它超出作用域时,你的流会自动关闭。
try()是原因。流将在try(.....)块之后关闭。请测试此代码:
while (true) {
try {
Socket dataSocket = sc.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(
dataSocket.getInputStream()));
PrintWriter out = new PrintWriter(
dataSocket.getOutputStream());
TestServer1 ts1 = new TestServer1 (in, out);
ts1.start();
} catch (Exception e) {
e.printStackTrace();
}
}
p。S:你需要在线程run()方法中关闭流
试试下面这个版本——它没有经过测试。但是正如我在评论中所说的,我认为您在TryWithResources
中过早地关闭了输出流。public class TestServer1 extends Thread{
Socket connection;
public TestServer1(Socket connection){
this.connection = connection;
}
@Override
public void run(){
try (BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
PrintWriter out = new PrintWriter(connection.getOutputStream());) {
String line;
try {
while ((line = in.readLine()) != null) {
System.out.println(line);
out.println(line);
out.flush();
if (line.equals("Bye."))
break;
} catch (IOException e){
System.out.print("error in run");
}
}
}
public static void main(String[] args) throws IOException {
try (ServerSocket sc = new ServerSocket(1111)) {
while (true) {
try (Socket dataSocket = sc.accept()) {
TestServer1 ts1=new TestServer1(dataSocket);
ts1.start();
}
}
}
}
}
根据@Amir, @LFF和@Abhijeet的回答,我把下面的版本放在一起,它可以工作。主要的结论是:"Socket dataSocket = sc.accept()"不应该作为资源放入"try()"中;否则,主线程将关闭它。它应该由"run()"中的子线程关闭。
谢谢大家的帮助。
public class ThreadedServer extends Thread {
private Socket dataSocket;
public ThreadedServer(Socket dataSocket) throws IOException {
this.dataSocket = dataSocket;
}
@Override
public void run() {
String line;
try (BufferedReader in = new BufferedReader(new InputStreamReader(
dataSocket.getInputStream()));
PrintWriter out = new PrintWriter(dataSocket.getOutputStream());) {
while ((line = in.readLine()) != null) {
System.out.println(line);
out.println(line);
out.flush();
if (line.equals("Bye."))
break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
dataSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
try (ServerSocket sc = new ServerSocket(1111)) {
while (true) {
try {
Socket dataSocket = sc.accept();
ThreadedServer ts = new ThreadedServer(dataSocket);
ts.start();
} finally {
}
}
}
}