-1

I was Developing a Multi threaded Server/Client Socket in java. Whenever a client Connects to the Server, a Thread for it will be created. but when a client got disconnected or its process closed by user, its thread will still remain in Server. how can I know a socket is disconnected then I can kill the corresponding thread in server? by the way, I have a checking system in Server which checks if the client is already registered with an id or not. so for example when a client with ID=12 connects and suddenly disconnects then wants to connect again, the server will not let the client get connected because it's server keeps its socket information in an ArrayList and tells the client that a client with ID=12 is already running in the server. please help me how to fix this

Here is my Server Code:

import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(9898);
            System.out.println("Server Created!");
            while (true) {
                Socket socket = serverSocket.accept();
                Thread t = new Thread(() -> ClientManager.getInstance().run(socket));
                t.start();
                System.out.println("Thread for Socket " + socket.getPort() + " Created");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

and this is my Client Manager Code:

import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;

public class  ClientManager {

    private ArrayList<SocketHub> socketHubs = new ArrayList<>();
    private ArrayList<SocketPhone> socketPhones = new ArrayList<>();

    private static ClientManager instance;

    public static ClientManager getInstance() {
        if (instance == null) {
            instance = new ClientManager();
        }
        return instance;
    }

    public void run(Socket socket) {
        String identity = null;
        String id = null;

        try {
            boolean receiveData = false;
            while (!receiveData) {
                int i = socket.getInputStream().available();
                while (i > 0) {
                    byte[] buffer = new byte[i];
                    socket.getInputStream().read(buffer);
                    identity = new String(buffer);
                    String[] idAndIdendity = identity.split("\\s");
                    identity = idAndIdendity[0];
                    id = idAndIdendity[1];
                    System.out.println("Identity & ID Received: " + identity + " " + id);
                    receiveData = true;
                    break;
                }
            }
            if (identity.toLowerCase().equals("hub")) {
                if (findSocket(id) != null) {
                    System.out.println("The Hub is Already Registered!");
                    socket.getOutputStream().write("You are already Registered!".getBytes());
                }
                else {
                    SocketHub socketHub = new SocketHub(socket, id);
                    socketHubs.add(socketHub);
                    new Thread(socketHub).start();
                    System.out.println("Hub Socket " + id + " Created!");
                }
            }
            else if (identity.toLowerCase().equals("phone")) {
                SocketHub socketHub = findSocket(id);
                SocketPhone socketPhone = new SocketPhone(socket, socketHub);
                socketHub.setSocketPhone(socketPhone);
                Thread t = new Thread(socketPhone);
                socketPhones.add(socketPhone);
                t.start();
                System.out.println("Phone Socket " + id + " Created!");
                System.out.println(socketPhone.getSocketPhone() + " is Connected to "+ socketHub.getSocketHub());
            }
            System.out.println("=====================================");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private SocketHub findSocket(String id) {
        for (SocketHub socket : socketHubs) {
            if (socket.getId().equals(id))
                return socket;
        }
        return null;
    }
}
  • It would be a good idea to partially show your server codes. It's hard to help without sufficient data. – Elyas Hadizadeh Jul 22 '19 at 10:22
  • thanks, code just added now – Masoud Khodadadi Jul 22 '19 at 18:28
  • Use a read timeout, and close the socket and exit the thread if you get it. NB You are misusing `available()`. Just block in the read. – user207421 Jul 22 '19 at 21:51
  • @MasoudKhodadadi Technically server of TCP/IP knows nothing about the current state of the connection, so you need to check whether a client is accessible or not. check this https://stackoverflow.com/a/10241044/3881354 – Elyas Hadizadeh Jul 22 '19 at 22:07
  • @MasoudKhodadadi For killing a thread do not use stop or any other old-fashioned approaches. It is far better to use `Thread.interrupt()` method. Check this simple example https://www.geeksforgeeks.org/killing-threads-in-java/ – Elyas Hadizadeh Jul 22 '19 at 22:09
  • 1
    @ElyasHadizadeh The whole point of that answer, which wrote, is that you *can't* 'check accessibiltiy of the client', for the reason you gave yourself. The main defence is to use a read timeout, as the answer says, and as I also said above here – user207421 Jul 22 '19 at 22:12
  • @user207421 I see, thank you for clarifying. – Elyas Hadizadeh Jul 22 '19 at 22:18
  • @OP One of problems with your use of `available()` is that your code cannot detect end of stream. Possibly this the only real problem you have? – user207421 Jul 22 '19 at 23:10

1 Answers1

0

There are a few minor "mistakes" in your code.

Why would you write received data in a buffer first to only create a new string with it?

Create a BufferedReader with the InputStreamReader from the InputStream of the Socket.

bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));

Use the method bufferedReader.readLine() or bufferedReader.read() to get the string right away.

To your question - read() will return -1, readLine() will return null if the connection was closed remotely by the client (the stream ended). - You can just check those conditions and stop the thread thread.interrupt().

If the remote client does follow the teardown phase of the TCP protocol you will get a SocketException when trying to read()/readLine()/write() from the sockets inputStream - in this example from the bufferedReader(). - Catch the exception and close the thread thread.interrupt().

Marco Zielbauer
  • 576
  • 1
  • 7
  • 18
  • It's a server program which reads input of client socket and write it to another client's output. i also used read()==-1 but it causes to one byte to be missed from input. I don't know how to implement read()==-1 without causing effect in output. – Masoud Khodadadi Jul 23 '19 at 05:20
  • I gave you the answer - do not use byte array but read() directly. – Marco Zielbauer Jul 23 '19 at 06:18
  • There is no such method as `Socket.readLine()`. The only `SocketException` you can get when reading a socket is 'socket closed', which has nothing to do with the peer. 'Do not use byte array but `read()` directly' is meaningless, and `read()` does not 'get the string right away'. – user207421 Jul 24 '19 at 04:32
  • Yes my bad I mixed it with the input stream. I am almost certain that he knows that I was refering to the inout stream – Marco Zielbauer Jul 24 '19 at 05:55
  • There is no such method as `InputStream.readLine()` either. You haven't addressed my other comments in any way. – user207421 Jul 24 '19 at 10:29
  • I will go to my computer now and look the code up, apparently coding on the paper might lead to errors for me. - I will update the answer and look through your comment! – Marco Zielbauer Jul 24 '19 at 12:28