Reputation: 1421
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
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();
}
}
}
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?
Upvotes: 0
Views: 1151
Reputation: 2406
This is because when you are calling readLine()
, socket is closed. You can first check the msg, if the msg is \exit
, then first stop inputThread
(use a flag or something else), then send \exit
to the server. In a short, check /exit
-> stop inputThread
-> send /exit
to server.
String msg = "";
while (!msg.toLowerCase().equals("/exit")) {
msg = keyboard.nextLine();
if (msg.toLowerCase().equals("/exit")) {
// stop inputThread.
// make sure inputThread is stopped.
}
if (!msg.trim().equals("")) {
pw.println(msg);
pw.flush();
}
}
Upvotes: 0