java - Java:使用线程时发生套接字关闭错误
问题描述
我正在构建一个多线程聊天服务器。
多线程服务器(Manager
类)可以为许多客户端提供服务。它接收来自客户端的消息,并向所有客户端广播。
客户端(Peer
类)有两个线程——SendThread
用于向服务器发送消息。ReceiveThread
收听服务器广播。
但是,在运行客户端程序时,它会捕获异常并说socket closed
.
我的服务器类代码如下:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Manager {
public int port;
public ArrayList<Socket> clients;
public Manager(int port) throws IOException {
this.port = port;
this.clients = new ArrayList<>();
try (ServerSocket server = new ServerSocket(port)){
System.out.println("Waiting for client connection-");
while (true){
Socket client = server.accept();
clients.add(client);
System.out.println("Client applies for connection");
Thread t = new Thread(new serverClientThread(client));
t.start();
}
}
}
public class serverClientThread implements Runnable {
private Socket client;
public serverClientThread(Socket client){
this.client = client;
}
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(this.client.getInputStream()));
while (true){
// read
String line = reader.readLine();
if (line != null){
System.out.println("I received "+line);
// write
// broadcast
broadcast("I received " + line);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
// broadcast the message to all clients
public synchronized void broadcast(String message) throws IOException {
for (Socket client:this.clients){
if (client.isClosed()){
continue;
}
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))){
writer.write("I received " + message);
writer.newLine();
writer.flush();
}
}
}
}
客户端类的代码如下:
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Peer {
public String hostname;
public int port;
public Peer(String hostname, int port){
this.hostname = hostname;
this.port = port;
try (Socket socket = new Socket(hostname, port)){
// create writer
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Thread t1 = new Thread(new SendThread(writer));
Thread t2 = new Thread(new ReceiveThread(reader));
t1.start();
t2.start();
} catch (UnknownHostException e) {
e.printStackTrace();
System.exit(-1);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
public class SendThread implements Runnable{
private BufferedWriter writer;
public SendThread(BufferedWriter writer){
this.writer = writer;
}
@Override
public void run() {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.print("Enter a String: ");
String str = sc.nextLine();
// send to server
if (str != null){
try {
this.writer.write(str);
this.writer.newLine();
this.writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class ReceiveThread implements Runnable{
private BufferedReader reader;
public ReceiveThread(BufferedReader reader){
this.reader = reader;
}
@Override
public void run() {
while (true){
String res = null;
try {
res = this.reader.readLine();
if (res != null){
System.out.println("Server response: "+ res);
}
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
}
}
错误信息是:
java.net.SocketException: Socket closed
at java.base/java.net.SocketInputStream.socketRead0(Native Method)
at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:168)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.base/java.io.InputStreamReader.read(InputStreamReader.java:185)
at java.base/java.io.BufferedReader.fill(BufferedReader.java:161)
at java.base/java.io.BufferedReader.readLine(BufferedReader.java:326)
at java.base/java.io.BufferedReader.readLine(BufferedReader.java:392)
at Peer$ReceiveThread.run(Peer.java:86)
at java.base/java.lang.Thread.run(Thread.java:834)
它发生在ReceiveThread
Peer 类中。
感谢您提供任何帮助。谢谢!
一哥
解决方案
由于您使用的是try-with-resources,因此在您启动 t1 和 t2 后,套接字会立即自动关闭。
你可以想到
try (Socket socket = new Socket(hostname, port)){
// [...]
t1.start();
t2.start();
}
//
像这样:
Socket socket;
try {
socket = new Socket(hostname, port)
// [...]
t1.start();
t2.start();
} catch (/* [...] */) {
} finally {
if (socket != null) {
socket.close(); // <- here the socket is closed
}
}
并且由于线程在后台运行,因此t1.start()
不会等到线程 1 完成 -> 套接字已关闭。
没有资源尝试:
public class Peer {
private Socket socket;
// [...]
public Peer(String hostname, int port) {
// [...]
try {
this.socket = new Socket(hostname, port);
// [...]
} catch (UnknownHostException | IOException ex) {
ex.printStackTrace();
System.exit(-1);
}
}
// Call this method when your program exits
public void close() {
if (this.socket != null) {
this.socket.close();
}
}
}
推荐阅读
- mysql - 如何轻松地将 CSV 文件转换为 SQL 文件?
- xcode - 您的帐户无权创建 Developer ID 应用程序证书
- redirect - 如何在不更改 web.config 文件中的 URL 的情况下重定向域?
- gamesparks - GameSparks 从 GameSparks 活动中获得高分
- html - 使用 vanilla css 的响应式应用程序
- ios - iOS 位置权限无法由 Objective-C 显示
- python - 将日期格式解析为日期时间
- azure - Azure 信息保护 | 如何解密来自 EWS API 的 .EML?
- python-3.x - 将字符串 (f. E. 6,6) 更改为浮动
- javascript - 在选择中搜索数据