Danish Bin Sofwan
Danish Bin Sofwan

Reputation: 476

JAVA multithreaded server sockets

Following is the code (JAVA) that accepts a client socket connection and assigns a thread to each connection.

 ServerSocket m_ServerSocket = new ServerSocket();

 while (true) {
            java.util.Date today = Calendar.getInstance().getTime();
            System.out.println(today+" - Listening to new connections...");

           Socket clientSocket = m_ServerSocket.accept();
           ClientServiceThread cliThread = new ClientServiceThread( clientSocket);
           cliThread.start();
 }

Suppose 5 clients are connected, hence 5 threads are running.

client 1: threadId 11
client 2: threadId 12
client 3 :threadId 13
client 4 :threadId 14
client 5 :threadId 15

Suppose one of the clients sends a message "kill-client1" , I to wish end client 1's connection and kill the thread with Id 11, something like this :

public void run() {
  try {
   BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
   PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()));

   while (running) {
    String clientCommand = in .readLine();

    if (clientCommand.equalsIgnoreCase("Kill-client1")) {
       // end the connection for client 1 & kill it's corresponding thread 11
    }
   }
 } catch (Exception e) {
  e.printStackTrace();
 }
 }

How can I achieve this ?

Upvotes: 3

Views: 1910

Answers (4)

Nicolas Filotto
Nicolas Filotto

Reputation: 45005

You could do that by storing your Threads into a thread-safe map (as it will be accessed by several threads concurrently) using the thread id as key

// Map that will contain all my threads
Map<Long, ClientServiceThread> threads = new ConcurrentHashMap<>();

// Add to the constructor the instance of the class that manage the threads
ClientServiceThread cliThread = new ClientServiceThread(this, clientSocket);
// Add my new thread 
threads.put(cliThread.getId(), cliThread);
cliThread.start();

Then when a kill is launched

String clientCommand = in.readLine().toLowerCase();
if (clientCommand.startsWith("kill")) {
    main.interrupt(Long.valueOf(clientCommand.substring(4).trim()));
}

Then in the main class your method would look like:

public void interrupt(long threadId) {
    // Remove the thread from the map
    ClientServiceThread cliThread = threads.remove(threadId);
    if (cliThread != null) {
        // Interrupt the thread
        cliThread.interrupt();
    }
}

Finally you will need to make your class ClientServiceThread sensitive to interruptions

try {
    ...
    while (!Thread.currentThread().isInterrupted()) {
        // My code here
    }
} finally {
    clientSocket.close();
}

Upvotes: 1

JB Nizet
JB Nizet

Reputation: 692231

To stop the current thread, you close the socket, and return from the run() method:

if (clientCommand.equalsIgnoreCase("Kill")) {
   clientSocket.close();
   return;
}

EDIT:

To close another thread, you can, for example

  • share a thread-safe map of clientID-Thread entries between threads. When a new client connects, you store the Thread started for this client in this map
  • when a Kill-client1 command comes in, you get the Thread corresponging the "client1" key from the map, and call ìnterrupt() on this thread.
  • in each thread (for example, the client1 thread), at each iteration of the loop, you check what the value of Thread.currentThread().isInterrupted(). If it's true, then you close the connection, remove the thread from the shared map, and return from the run() method.

The key point is that you never kill another thread. You always request a thread to stop by interrupting it, and the thread checks the value of its interrupt flag to decide when and how it must stop.

Upvotes: 0

Antoniossss
Antoniossss

Reputation: 32550

Just keep track of all client sockets and/or handling threads.

Map<Integer,Socket> clients=new HashMap<>();

 while (true) {
            java.util.Date today = Calendar.getInstance().getTime();
            System.out.println(today+" - Listening to new connections...");

           Socket clientSocket = m_ServerSocket.accept();
           clients.put(generateNewClientId(),clientSocket);
           ClientServiceThread cliThread = new ClientServiceThread( clientSocket);
           cliThread.start();
 }

And then if you simply do

{
    if (clientCommand.equalsIgnoreCase("Kill")) {
       Socket socket=clients.get(idToShutDown);// get required id somehow (from request??)
       socket.close();
    }
}

This will close given socket resulting in breaking in.readLine() in handling thread thus finishing thread.

If you keep track of threads, you can set "interrupt" flag and probe it in while condition so your handling thread will be able to finish work gracefully.

Upvotes: 2

Boris Schegolev
Boris Schegolev

Reputation: 3711

Just terminate the loop:

   while (running) {
    String clientCommand = in .readLine();

    if (clientCommand.equalsIgnoreCase("Kill")) {
       running = false;
    }
   }

or:

   while (running) {
    String clientCommand = in .readLine();

    if (clientCommand.equalsIgnoreCase("Kill")) {
       break;
    }
   }

And don't forget to close the socket in finally block.

Upvotes: 0

Related Questions