I try to make basic Java Chatting Application with java socket APIs. But when the client is terminated, it throws the following Exception,
java.net.SocketException: Socket closed
My code
Server
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();
}
}
}
Client
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();
}
}
}
When the generated clients is terminated with "/exit" message, the BufferedReader.readLine() line throws the exception like below
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)
I think the BufferedReader stream still try to read line message even though the socket is already closed.
But I hava no idea when and how to close the BufferedReader Stream and Socket connection when the clients is terminated.
I am totally stuck on this part. Any ideas?
finallyhandler run)?