【发布时间】:2019-01-11 22:59:25
【问题描述】:
我尝试使用 Java 套接字 API 制作基本的 Java 聊天应用程序。但是当客户端终止时,它会抛出以下异常,
java.net.SocketException: 套接字关闭
我的代码
服务器
package com.aaa.server;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class JavaChatServer {
final static int Port = 10001;
public static void main(String[] args) {
// TODO Auto-generated method stub
ServerSocket serverSocket = null;
Map<String, PrintWriter> clientMap = null;
try {
serverSocket = new ServerSocket(Port);
clientMap = new HashMap<String, PrintWriter>();
Collections.synchronizedMap(clientMap);
while(true) {
System.out.println("Waiting Connection ....");
Socket socket = serverSocket.accept();
ServerThread thread = new ServerThread(socket, clientMap);
thread.start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(!serverSocket.isClosed()) {
serverSocket.close();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
class ServerThread extends Thread {
private Socket socket = null;
private BufferedReader br = null;
private Map<String, PrintWriter> clientMap;
private String id;
public ServerThread(Socket socket, Map<String, PrintWriter> clientMap) {
this.socket = socket;
this.clientMap = clientMap;
}
@Override
public void run() {
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
id = br.readLine();
broadcast(id + " is connected");
System.out.println("Connected User Id : " + id);
clientMap.put(id, pw);
String msg = "";
while(true) {
msg = br.readLine();
if(msg.equals("/exit")) {
break;
}
broadcast(id + " : " + msg);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
clientMap.remove(id);
broadcast(id + " is disconnected!!");
if (br != null)
br.close();
if(socket != null)
socket.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
private void broadcast(String msg) throws Exception{
Collection<PrintWriter> collection = clientMap.values();
Iterator<PrintWriter> iterator = collection.iterator();
while(iterator.hasNext()) {
PrintWriter pw = iterator.next();
pw.println(msg);
pw.flush();
}
}
}
客户
package com.aaa.client;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class JavaChatClient {
final static int Port = 10001;
public static void main(String[] args) {
// TODO Auto-generated method stub
Socket socket = null;
PrintWriter pw = null;
Scanner keyboard = new Scanner(System.in);
String id = "";
try {
socket = new Socket("localhost", Port);
pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
System.out.print("Welcome to Chat Room. Pls, type your ID : ");
id = keyboard.nextLine();
pw.println(id);
pw.flush();
ClientInputThread inputThread = new ClientInputThread(socket);
inputThread.start();
String msg = "";
while (!msg.toLowerCase().equals("/exit")) {
msg = keyboard.nextLine();
if(!msg.trim().equals("")) {
pw.println(msg);
pw.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (keyboard != null)
keyboard.close();
if (pw != null)
pw.close();
if(socket != null)
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class ClientInputThread extends Thread {
private Socket socket = null;
public ClientInputThread (Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String msg = "";
while(true) {
if(socket.isClosed())
break;
msg = br.readLine(); // This line throws SocketException
System.out.println(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
当生成的客户端以“/exit”消息终止时,BufferedReader.readLine() 行会抛出如下异常
java.net.SocketException: Socket closed
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at com.aaa.client.ClientInputThread.run(JavaChatClient.java:80)
我认为即使套接字已经关闭,BufferedReader 流仍会尝试读取行消息。
但我不知道当客户端终止时何时以及如何关闭 BufferedReader Stream 和 Socket 连接。
我完全被这部分困住了。有什么想法吗?
【问题讨论】:
-
听起来不错。你还期望发生什么?至于处理它,为什么不明确地捕获它,然后自己清理(或让
finally处理程序运行)? -
感谢您的回复。当客户端终止时,我会尽力消除此异常。我想知道如何在服务器连接终止时同时关闭客户端的套接字。问题是即使服务器端的套接字关闭,客户端的流仍然存在。最好的问候。