I am working on a chat app in Java and so far everything works all right except that when a client disconnects and a message is send by other client this error pops out:
java.net.SocketException: Software caused connection abort: socket write error
at java.base/java.net.SocketOutputStream.socketWrite0(Native Method)
at java.base/java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:110)
at java.base/java.net.SocketOutputStream.write(SocketOutputStream.java:150)
at java.base/java.io.DataOutputStream.write(DataOutputStream.java:107)
at java.base/java.io.DataOutputStream.writeUTF(DataOutputStream.java:401)
at java.base/java.io.DataOutputStream.writeUTF(DataOutputStream.java:323)
at com.terkea/com.terkea.system.server.ClientThread.run(ClientThread.java:65)
at java.base/java.lang.Thread.run(Thread.java:835)
This is my server Thread:
#Override
public void run() {
try {
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
while (!socket.isClosed()) {
try {
String input = in.readUTF();
if (Message.fromJSON(input).getUserName().equals("REGISTER")) {
Message specialMessage = Message.fromJSON(input);
specialMessage.setUserName("SERVER");
Client test = Client.fromJSON(specialMessage.getMessage());
test.setIp(socket.getInetAddress().toString());
test.setListening_port(String.valueOf(socket.getPort()));
specialMessage.setMessage(Client.toJSON(test));
input = Message.toJSON(specialMessage);
}
for (ClientThread thatClient : server.getClients()) {
DataOutputStream outputParticularClient = new DataOutputStream(thatClient.getSocket().getOutputStream());
outputParticularClient.writeUTF(input);
}
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
and the Client:
public void createClient() {
try {
socket = new Socket(getHost(), portNumber);
DataInputStream in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
Message registerclient = new Message("REGISTER", Client.toJSON(getClient()));
out.writeUTF(Message.toJSON(registerclient));
new Thread(() -> {
while (!socket.isClosed()) {
try {
if (in.available() > 0) {
String input = in.readUTF();
Message inputMessage = Message.fromJSON(input);
if (inputMessage.getUserName().equals("SERVER")) {
System.err.println(Client.fromJSON(inputMessage.getMessage()));
allClientsConnected.add(Client.fromJSON(inputMessage.getMessage()));
} else {
chat.add(inputMessage);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
The error corresponds to outputParticularClient.writeUTF(input);
My goal is to get rid of this error and also if possible could anybody tell me a way to check when a client disconnects? I've found some similar questions over here and their solution was to check if (socket.getInputStream().read()!=-1)
but when I do that the whole program freezes and the GUI stops working.
You may want to look into expanding upon your special message functionality, and instead of using the username to pass "REGISTER" use something like messageType in order to do so. This way you can configure handlers based on type to do a number of things. For example things like:
MessageType { REGISTER, UNREGISTER, READ_RECEIPT, ... }
You can then have things like:
RegisterHandler {}
UnregisterHandler{}
and eventually expand them to have some features like facebook/whatsapp (/ICQ haha):
TypingHandler {} // Other user gets a message saying that I am typing to them
From here, you can implement the UNREGISTER to do what you want. Like the first comment says, you should catch the SocketException and manually unregister that client so it doesn't happen anymore. But you should also try to pre-emptively send an
{
messageType: UNREGISTER,
from: Client1
to: server|null,
data: {}
}
so that your server can remove it before the exception occurs. This would also let you handle Offline messages, if that's something you're interested in.
Related
I am developing a program that has a chat feature and I am using sockets in it.
In my case, I want to handle each of the client in a different window chat(PLEASE SEE ATTACHED IMAGE).
As of now, when 1 client is connected, there is no problem. But when 2 clients are connected, the first client will be overridden by the 2nd one and he can't receive messages from server not unless I close the connection for the latest client connected(Server still receiving messages from all client although only 1 client can receive from server).
How am I gonna do this? I am using captain casa framework
I want to manage it like what did the image below do.
IMAGE HERE
Here is my code:
Server:
public void mainserver(){
Thread server = new Thread(new Runnable() {
#Override
public void run() {
try {
serverSocket = new ServerSocket(port);
System.out.println("Server Online... \nWaiting for Connections");
} catch (IOException e) {
e.printStackTrace();
}
while (accept){
try {
socket = serverSocket.accept();
System.out.println("New Connection Estasblished!!!");
chatHandler chat = new chatHandler(socket);
chat.start();
} catch (IOException e) {
System.out.println("server not terminate all connections");
System.exit(-1);
}
}
}
});
server.start();
}
public class chatHandler extends Thread{
Socket socket;
public chatHandler(Socket socket){
this.socket = socket;
}
public void run(){
try {
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
dout.writeUTF("Hi! Thank you for reaching us! How may I help you!?");
while (!read.equals(".end")){
read = din.readUTF();
if (getServerArea()!=null){
setServerArea(getServerArea()+"\n"+read);
}else {
setServerArea(read);
}
}
System.out.println("end of chat server");
} catch (IOException e) {
e.printStackTrace();
}finally {
System.out.println("Exit");
try {
dout.close();
din.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void serverSend(javax.faces.event.ActionEvent event) { // "Send" button
write = getServerField();
try {
dout.writeUTF(write);
dout.flush();
if (getServerArea()!=null){
setServerArea(getServerArea()+"\n"+write);
setServerField("");
}else {
setServerArea(write);
setServerField("");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(write);
}
Client:
public void client(){
Thread client = new Thread(new Runnable() {
#Override
public void run() {
try {
socket = new Socket("localhost",port);
din = new DataInputStream(socket.getInputStream());
dout = new DataOutputStream(socket.getOutputStream());
while (!read.equals("bye")){
read = din.readUTF();
if (getClientArea()!=null){
setClientArea(getClientArea()+"\n"+read);
}else {
setClientArea(read);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
din.close();
dout.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
client.start();
}
public void clientSend(javax.faces.event.ActionEvent event) {
write = getClientField();
try {
dout.writeUTF(write);
dout.flush();
if (getClientArea()!=null){
setClientArea(getClientArea()+"\n"+write);
setClientField("");
}else {
setClientArea(write);
setClientField("");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(write);
}
I believe I understand the problem, and how to correct it.
You are using a unique thread (chatHandler) for each new connection.
This thread writes an automatic "Hello" upon connection, but thereafter is dedicated to reading messages (in the while loop you only read din) and updating the console accordingly. Since each thread is managing a reference to din, all incoming messages are OK.
However, it seems that writing back to a client (serverSend) is not in a thread; it is triggered by a button event. At this point, dout will be a reference to the most recent connection, and not a reference to the client intended to get the message. That is why the most recent client gets all future messages.
The correction is to choose the correct 'dout' for the intended client. When the server 'operator' chooses to write a message back (clicking the send button), somehow you need to obtain the correct 'dout' for that client.
One way to do this is to establish dout prior to creating the thread (using socket), and maintain a relationship between each client, and it's corresponding dout (i.e. in a Map).
If the problem is still not clear (that each client must have a unique reference to dout), please let me know and I will try to clarify.
I want to send an object from my client to my localhost server to add to database, and send result back whether the object was sent successfully or not. The object was sent successfully, but my server doesn't send the result back to client, and causes my client frame form hanged due to waiting for response from server. I don't know what's wrong with my code. Can you tell me some ways to fix this?
Here is the function to send the result:
public void sendResult(String result) {
try {
Socket clientSocket = myServer.accept();
System.out.println("Connected to client");
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
os.writeObject(result);
System.out.println("Result sent");
} catch (Exception ex) {
ex.printStackTrace();
}
}
Where the send result function is called:
public void service() {
try {
if (receiveStudent() != null) {
Student std = receiveStudent();
if (dao.addStudent(std)) {
System.out.println("OK");
sendResult("OK");
} else {
System.out.println("FAILED");
sendResult("FAILED");
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
In addition, in the Service function, the console printed "OK", which means the if condition was satisfied.
receive student method:
public Student receiveStudent() {
Student s = new Student();
try {
Socket clientSocket = myServer.accept();
System.out.println("Connect to client successfully");
ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
Object o = ois.readObject();
if (o instanceof Student) {
s = (Student) o;
return s;
}
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
Because of myServer.accept() in sendResult(), the server is again waiting for an incoming client connection while this already happened in receiveStudent(). Reuse that connection.
Share the client socket you've obtained in receiveStudent() by, e.g., turning it into a field.
public Student receiveStudent() {
...
try {
clientSocket = myServer.accept();
...
} catch (Exception ex) {
...
}
...
}
and then reuse that socket in sendResult() to send the result to the client.
public static void sendResult(String result) {
try {
...
ObjectOutputStream os = new ObjectOutputStream(clientSocket.getOutputStream());
...
} catch (Exception ex) {
...
}
}
If you want to send a String as object why don't you just use something like this:
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); //for sending String messages
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); //for getting String messages
... and then when you need to send you do it like this:
out.println(textToServer"); // send to server - don't forget LN in println.
out.flush(); // to clean buffer
It should do what you need to be done.
And make sure that your client class is waiting to get that InputStream you're sending, don't forget that, since maybe it's the problem in the Client side.
Maybe Client is not accepting that incoming Socket regardless if it's ObjectInputStream or BufferedReader that will accept the incoming socket object.
You could provide us a Client class so we can see if there's missing acceptance of incoming socket.
At the end of the method make sure you close your streams and sockets.
out.close();
in.close();
socket.close();
For more details check this, this and this. I hope I was helpful :)
You're calling accept() twice. This is meaningless. You need to:
Accept the connection. This returns a Socket.
Read the request and create the response.
Send the response, via the same Socket you accepted at (1).
You also want to create a new thread per accepted socket, and you also want to do all I/O in that thread, including creating the ObjectInputStream and ObjectOutputStream. Otherwise your server isn't properly multi-threaded and multi-client.
I have a problem with socket communication.
Sometimes reading from inputstream on client side stops working while the server is still sending new messages. I debugged the server so I know that is still working and sending messages to the outputstream. But on the client side read from inputstream is blocked. I can't debug this situation on client side. I only see difference in received messages on client side just before everything stops.
Example of good received message when everything works fine. Single send message in one line (I use DataInputStream.readUTF() method on client side and DataOutputStream.writeUTF(String msg) on server side. )
ADD;MB57,18-9,5,dd,10,10;
UP;MB15;20;14;20;13;1.0;
ADD;MB37,18-9,5,xx,10,10;
UP;MB13;20;14;20;13;1.0;
ADD;MB47,18-9,5,ww,10,10;
UP;MB13;20;14;20;13;1.0;
And this is happens just before my socket stop reading from input. One big mess. And everything that has been sent from the beginning in one line. It looks like the buffer overload O.o What happens?
11-07 11:36:41.978: I/System.out(17980): 11;8;10;8;0.1;��UPPOS;MB8;16;8;16;7;1.0;��PATH;MB8��UPPOS;MB20;14;9;14;10;1.0;�� ADDMOB;MB20,14-10,6,mummy,50,50;�� PATH;MB20��UPPOS;MB50;12;8;12;7;1.0;�� PATH;MB50��UPPOS;MB13;15;11;14;11;1.0;�� PATH;MB19��PATH;MB8��UPPOS;MB20;14;10;13;10;1.0;�� PATH;MB20��UPPOS;MB50;12;7;12;6;1.0;�� PATH;MB50��UPPOS;MB13;14;11;14;10;1.0;��UPPOS;MB19;13;9;14;9;1.0;�� PATH;MB19��PATH;MB8��UPPOS;MB20;13;10;13;9;1.0;��ADDMOB;MB20,13-9,6,mummy,50,50;�� PATH;MB20��UPPOS;MB50;12;6;12;7;1.0;�� PATH;MB50��UPPOS;MB13;14;10;15;9;1.0;��!ADDMOB;MB13,15-9,5,chicken,10,10;�� PATH;MB13��UPPOS;MB19;14;9;14;10;1.0;��!ADDMOB;MB19,14-10,1,goblin,37,50;�� PATH;MB19��UPPOS;NP12;10;8;9;8;0.1;��UPPOS;MB8;16;7;17;7;1.0;��PATH;MB8��UPPOS;MB20;13;9;12;9;1.0;�� PATH;MB20��UPPOS;MB50;12;7;11;7;1.0;�� PATH;MB50��UPPOS;MB13;15;9;14;9;1.0;�� PATH;MB13��UPPOS;MB19;14;10;13;9;1.0;�� ADDMOB;MB19,13-9,1,goblin,37,50;�� PATH;MB19��UPPOS;MB8;17;7;16;7;1.0;��PATH;MB8��UPPOS;MB20;12;9;12;8;1.0;��UPPOS;MB50;11;7;12;7;1.0;�� PATH;MB50��UPPOS;MB13;14;9;14;10;1.0;��"ADDMOB;MB13,14-10,5,chicken,10,10;�� PATH;MB13�� PATH;MB19��UPPOS;MB8;16;7;16;8;1.0;��PATH;MB8�� PATH;MB20�� PATH;MB50��UPPOS;MB13;14;10;15;10;1.0;�� PATH;MB13��UPPOS;MB19;13;9;14;9;1.0;�� PATH;MB19��UPPOS;NP12;9;8;9;9;0.1;��UPPOS;MB8;16;8;16;7;1.0;��PATH;MB8��UPPOS;MB20;12;8;12;9;1.0;�� PATH;MB20��UPPOS;MB50;12;7;12;6;1.0;�� PATH;MB50��UPPOS;MB13;15;10;14;10;1.0;��UPPOS;MB19;14;9;13;9;1.0;�� PATH;MB19��PATH;MB8��UPPOS;MB20;12;9;12;8;1.0;�� PATH;MB50��UPPOS;MB13;14;10;14;9;1.0;��!ADDMOB;MB13,14-9,5,chicken,10,10;�� PATH;MB13�� PATH;MB19��UPPOS;MB8;16;7;16;6;1.0;��PATH;MB8��UPPOS;MB20;12;8;12;7;1.0;�� PATH;MB20�� PATH;MB50��UPPOS;MB13;14;9;14;10;1.0;��"ADDMOB;MB13,14-10,5,chicken,10,10;�� PATH;MB13��UPPOS;MB19;13;9;13;10;1.0;��!ADDMOB;MB19,13-10,1,goblin,37,50;�� PATH;MB19��UPPOS;NP12;9;9;9;8;0.1;��PATH;MB8�� PATH;MB20��UPPOS;MB50;12;6;11;6;1.0;�� PATH;MB50��UPPOS;MB13;14;10;14;9;1.0;��!ADDMOB;MB13,14-9,5,chicken,10,10;�� PATH;MB13��UPPOS;MB19;13;10;13;9;1.0;�� ADDMOB;MB19,13-9,1,goblin,37,50;�� PATH;MB19��UPPOS;MB8;16;6;16;7;1.0;��PATH;MB8�� PATH;MB20��UPPOS;MB50;11;6;12;6;1.0;�� PATH;MB50��UPPOS;MB13;14;9;15;9;1.0;�� PATH;MB13�� PATH;MB19��PATH;MB8��UPPOS;MB20;12;7;12;8;1.0;�� PATH;MB20�� PATH;MB50��UPPOS;MB13;15;9;14;9;1.0;�� PATH;MB13��UPPOS;MB19;13;9;13;10;1.0;��!ADDMOB;MB19,13-10,1,goblin,37,50;�� PATH;MB19��UPPOS;NP12;9;8;10;8;0.1;��UPPOS;MB8;16;7;16;8;1.0;��PATH;MB8��UPPOS;MB20;12;8;12;7;1.0;�� PATH;MB20�� PATH;MB50��UPPOS;MB13;14;9;15;9;1.0;�� PATH;MB13��UPPOS;MB19;13;10;13;11;1.0;�� PATH;MB19��UPPOS;MB8;16;8;16;9;1.0;��PATH;MB8��UPPOS;MB20;12;7;11;7;1.0;�� PATH;MB20��UPPOS;MB13;15;9;14;9;1.0;�� PATH;MB50�� PATH;MB13��UPPOS;MB19;13;11;13;10;1.0;��UPPOS;MB20;11;7;12;7;1.0;�� PATH;MB20��UPPOS;MB8;16;9;16;8;1.0;�� PATH;MB50��UPPOS;MB13;14;9;15;9;1.0;�� PATH;MB13��UPPOS;MB19;13;10;14;10;1.0;��UPPOS;NP12;10;8;11;8;0.1;�� PATH;MB20��UPPOS;MB8;16;8;16;7;1.0;��PATH;MB8�� PATH;MB50��UPPOS;MB13;15;9;14;9;1.0;�� PATH;MB13��UPPOS;MB19;14;10;15;9;1.0;�� ADDMOB;MB19,15-9,1,goblin,37,50;�� PATH;MB19��UPPOS;MB20;12;7;11;7;1.0;�� PATH;MB20��UPPOS;MB8;16;7;16;6;1.0;��PATH;MB8��UPPOS;MB50;12;6;12;7;1.0;�� PATH;MB50��UPPOS;MB13;14;9;13;9;1.0;�� PATH;MB13��UPPOS;MB19;15;9;14;9;1.0;�� PATH;MB19�� PATH;MB20��UPPOS;MB8;16;6;16;7;1.0;��PATH;MB8��UPPOS;MB50;12;7;12;8;1.0;�� PATH;MB50�� PATH;MB13��UPPOS;MB19;14;9;14;10;1.0;��!ADDMOB;MB19,14-10,1,goblin,37,50;�� PATH;MB19��UPPOS;MB20;11;7;12;7;1.0;�� PATH;MB20��UPPOS;MB8;16;7;16;8;1.0;��PATH;MB8��UPPOS;MB50;12;8;12;9;1.0;�� PATH;MB50��UPPOS;MB13;13;9;14;9;1.0;�� PATH;MB13��UPPOS;MB19;14;10;15;10;1.0;�� PATH;MB19��UPPOS;MB20;12;7;11;7;1.0;�� PATH;MB20��UPPOS;MB50;12;9;12;8;1.0;�� PATH;MB50��UPPOS;MB8;16;8;16;7;1.0;��PATH;MB8��UPPOS;MB13;14;9;13;9;1.0;�� PATH;MB13��UPPOS;MB19;15;10;15;9;1.0;�� ADDMOB;MB19,15-9,1,goblin,37,50;��UPPOS;NP12;11;8;10;8;0.1;��UPPOS;MB20;11;7;12;7;1.0;��UPPOS;MB8;16;7;16;6;1.0;��PATH;MB8�� PATH;MB13��UPPOS;MB50;12;8;11;8;1.0
Client side
private DataOutputStream out;
private Socket client;
private DataInputStream in;
private Thread inputListener;
public void createConnection(){
try {
client = new Socket(serverName, port);
setOut(new DataOutputStream(client.getOutputStream()));
in = new DataInputStream(client.getInputStream());
inputListener=new Thread(){
public void run(){
try {
synchronized(in){
while(client!=null){
try{
String read = new String(in.readUTF());
/** do somethink with input msg */
} catch (java.io.UTFDataFormatException e1) {
e1.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally{
reconnect();
}
}
};
inputListener.start();
} catch (Exception e) {
e.printStackTrace();
}
}
private void reconnect() {
try {
client.close();
client=null;
inputListener.interrupt();
setOut(null);
in.close();
in=null;
} catch (IOException e) {
e.printStackTrace();
} finally{
System.out.println("RECONECT METHOD IN SOCKET");
}
}
Server side
private DataOutputStream out;
private Socket client;
public Client(Socket client) {
try {
setOut(new DataOutputStream(client.getOutputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMessage(String string) {
try {
getOut().writeUTF(string);
} catch (IOException e) {
e.printStackTrace();
disconected();
}
}
You must be writing something else to the stream. Catching and ignoring UTFDataFormatException is no solution. Once you get it, you will never get back into sync with the sender.
NB Converting the result of readUTF() to a String is futile. It already is a String.
I have a chat program. The problem is that I am trying to disallow dupe names. Essentially, whenever a name change request is sent to the server, it is checked against the list of names currently in use and if it is already taken, the person is added to my shitlist (not allowed to post) and they are sent a message that they need to change their name.
I commented the crap out of the code since there is a lot so you can understand it easily.
The problem is that the wrong person is being sent the message that the name is already in use! I have spent the last 8 hours trying to find it and It's bloody driving me mad!
The server side code is long; I'll post the relevant bits and any further will be provided on request. I'll also link to the complete program. (Not the source, the JAR.)
JAR: https://www.mediafire.com/?4t2shjdjf7blpg2
//...Irrelevant bits ommitted...//
public class Server
{
// The server object reference
static Server server;
// Declarations:
private ArrayList<ObjectOutputStream> clientOutputStreams; // out streams
private ArrayList<String> takenNames = new ArrayList<>(); // taken names
private InetAddress ip;
private final int serverPort; // the port the server is running on
private static ObjectOutputStream changer; // the last person to change names
private ArrayList<ObjectOutputStream> shitList = new ArrayList<>();
private HashMap <InetAddress, ObjectOutputStream> ipMap =
new HashMap<>(); // <ip, outputstream>
//...Irrelevant bits ommited...//
// Don't mind this non-indentation, it is supposed to be.
public void tellEveryone(Message message, InetAddress senderIP)
{
// First check some special conditions..
if(message.getType() == Message.TYPE.IN_USE)
{
try
{
changer.writeObject(message);
}
catch (IOException e)
{
e.printStackTrace();
}
}
// If someone is on my shitlist,
if(shitList.contains(ipMap.get(senderIP)))
{
// Warn them of their sins...
Message nopeMessage = new Message(Message.TYPE.SERVER,
"You may not send any messages until you change your name!",
"Server");
try
{
ipMap.get(senderIP).writeObject(nopeMessage);
}
catch(IOException e)
{
e.printStackTrace();
}
}
else
{
// Send message normally to everyone...
// Sync, just to be safe
synchronized(clientOutputStreams)
{
for(ObjectOutputStream oo : clientOutputStreams) // while more clients...
{
try
{
oo.writeObject(message);
oo.flush();
}
catch(IOException e)
{
System.out.println("IOException caught during tellEveryone()");
e.printStackTrace();
}
}
}
System.out.println(getTimeStamp() + ": Message Sent by:".
concat(" " + senderIP + "/ " + message.getSenderName()));
}
}
The server handler inner class...
public class ServerHandler implements Runnable
{
#Override
public void run()
{
// Create a list of client out streams to send stuff...
clientOutputStreams = new ArrayList<>();
try // To establish a connection with clients
{
// Create server socket...
ServerSocket serverSocket = new ServerSocket(serverPort);
while(true) // Will always run! Blocks!
{
// Assign a client socket to any new socket connections...
// (The var used here is temp, but will be passed off soon.)
Socket clientSocket = serverSocket.accept();
// Get's the ip of the client that connected...
ip = clientSocket.getInetAddress();
System.out.println(ip + " " + "connected.");
// Create ooStream to send messages to client...
ObjectOutputStream ooStream =
new ObjectOutputStream(
clientSocket.getOutputStream());
// Add the client oo stream to the list of outputs...
clientOutputStreams.add(ooStream);
// Add user IP data to map of ip's
ipMap.putIfAbsent(ip, ooStream);
// Create new thread to run inner class ClientHandler...
Thread t = new Thread(new ClientHandler(clientSocket));
// Running the thread makes it safe to overwrite the...
// ...clientsocket variable.
t.start();
}
}
catch (IOException e)
{
System.out.println("Exception in server.run()");
// TODO: Revise
e.printStackTrace();
}
}
}
The client handler inner class
public class ClientHandler implements Runnable
{
private ObjectInputStream oInStream; // The client's input stream.
private Socket socket; // Socket to the client
public ClientHandler(Socket clientSocket)
{
try // to create an input stream...
{
socket = clientSocket; // <-- The one passed in to the method
// Potential error from previous version... REMOVE WHEN TESTED
oInStream = new ObjectInputStream(socket.getInputStream());
}
catch(IOException e)
{
System.out.println("Error establishing input stream");
}
}
#Override
public void run()
{
Message message;
try // To process incoming messages...
{
while(socket.isClosed() == false) // If the socket is open...
{
// While there are more messages...
// Also assigns to the message var.
while((message = (Message)oInStream.readObject()) != null)
{
// Passes on the message and sender info.
if(message.getType() == Message.TYPE.NAME_REQUEST)
{
changer = ipMap.get(socket.getInetAddress());
System.out.println(socket.getInetAddress());
System.out.println(changer.toString());
handleNameRequests(message);
}
else
{
tellEveryone(message, ip); // TEST CHANGE- DELETED IF TEST
}
}
// TEST TEST TEST
synchronized(clientOutputStreams)
{
int index =
clientOutputStreams.indexOf(
socket.getOutputStream());
clientOutputStreams.remove(index);
System.out.println("Removed the client in sync");
}
}
// TEST TEST TEST
socket.close(); // TEST CLOSING SOCKET WHEN DONE.
System.out.println("Sock closed after while loop in ch run()");
}
catch(IOException e)
{
System.out.println("IOException caught when "
+ "reading message.");
}
catch (ClassNotFoundException e)
{
System.out.println("Some poor sap is going to have to debug"
+ "this!");
}
finally
{
// THIS WHOLE BLOCK: TEST TEST TEST
try
{
oInStream.close();
System.out.println("just closed oinStream");
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
I FINALLY FOUND IT!
For any future people encountering a similar problem, the problem was that I was assigning the ip variable in the wrong place! This essentially resulted in the list of ip's being all the same! Another bug confounded that problem, in that when I disabled the sending ability of messages when on my shitlist (aren't programmers the darndest?), I disabled ALL types of messages, including those from the server, ect! Oops!
The lesson? Bugs hide in the darndest places. Walk through everything, and doubt what you know to be true. Assume nothing, verify everything. There are never enough print statements when debugging!
i am creating a multiple-client/server app whenever any client disconnects from
my server it just hangs.
how can i set any condition that will tell me print some message whenever
any client disconnects from the server
here is my server code
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
System.out.println("server starting.......");
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("Ready to accept.......");
socket = serverSocket.accept();
System.out.println(" client Connected with ip address =" +socket.getRemoteSocketAddress().toString());
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
System.out.println("catch block");
}
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
any help will be appreciated
It's not clear whether you mean disconnect because the conversation was over (ie: everything completed successfully) or the disconnect is because of some network problems (or the client canceled the request).
If it's the first case, then it's easy: the protocol you are using (your own, or http, or whatever) is in charge of defining how to determine that a conversation was over. If that situation arises, then you just close the socket.
If it's the second case, then you'd have to have an algorithm in place to determine whether or not the connection must be closed. For instance, by implementing a timeout, or a slow-read threshold. Take a look at the Socket's javadoc for instructions on how to set a timeout.
It's also worth noting that it's fine to create your own servers when you want to practice or learn something, but you'd be better off using an existing solution, like vert.x or a slimmed down version of Wildfly, for instance. The overhead of such servers is very low, nowadays, while still providing very robust networking capabilities.