JAVA多线程服务器套接字

3
以下是接受客户端套接字连接并为每个连接分配一个线程的代码(JAVA):
 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();
 }

假设有5个客户端连接,因此会运行5个线程。
client 1: threadId 11
client 2: threadId 12
client 3 :threadId 13
client 4 :threadId 14
client 5 :threadId 15

假设客户端之一发送了消息“kill-client1”,我希望结束客户端1的连接并终止线程Id为11的进程,类似以下代码:
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();
 }
 }

我该如何实现这个目标?

所以你基本上希望客户端能够杀死其他客户端 :) - Antoniossss
@Antoniossss 是的先生。 - Danish Bin Sofwan
4个回答

2

只需跟踪所有客户端套接字和/或处理线程即可。

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();
 }

然后,如果您只是这样做:

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

这将关闭给定的套接字,导致处理线程中的in.readLine()被中断,从而结束线程。

如果您跟踪线程,可以设置"interrupt"标志,并在while条件中进行探测,以便您的处理线程能够优雅地完成工作。


看起来这会让我更接近,让我试一下。谢谢!如果这有效,我会接受答案的。 - Danish Bin Sofwan
我决定采用你的回答逻辑和@Nicolas Filotto的回答。谢谢! - Danish Bin Sofwan

1
你可以通过将Threads存储到一个线程安全的映射表中(因为它将被多个线程同时访问),使用线程ID作为键来实现此目的。
// 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();

然后当一个 kill 被启动时

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

然后在主类中,你的方法应该是这样的:
public void interrupt(long threadId) {
    // Remove the thread from the map
    ClientServiceThread cliThread = threads.remove(threadId);
    if (cliThread != null) {
        // Interrupt the thread
        cliThread.interrupt();
    }
}

最后,您需要使您的类ClientServiceThread对中断敏感。

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

我决定使用你的回答逻辑和@Antoniossss的回答的组合。谢谢! - Danish Bin Sofwan

0

要停止当前线程,您需要关闭套接字并从run()方法返回:

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

编辑:

要关闭另一个线程,您可以执行以下操作:

  • 在线程之间共享一个线程安全的客户端ID-线程条目映射。当新客户端连接时,将为此客户端启动的线程存储在此映射中
  • 当收到Kill-client1命令时,您从映射中获取与“client1”键对应的线程,并在该线程上调用interrupt()。
  • 在每个线程(例如,client1线程)的每次循环迭代中,检查Thread.currentThread().isInterrupted()的值。如果为true,则关闭连接,从共享映射中删除线程,并从run()方法返回。

关键点是您永远不会杀死另一个线程。您始终通过中断请求线程停止,并且线程检查其中断标志的值以决定何时以及如何停止。


我不想让线程自杀,相反,我希望其他线程或者父进程根据线程ID来杀死它。 - Danish Bin Sofwan
你应该澄清你的问题,因为那并不清楚。仅凭"Kill"指令,线程怎么知道要杀死哪一个其他线程呢? - JB Nizet
是的,你说得对,请让我编辑我的问题,但请帮忙。 - Danish Bin Sofwan

0

只需终止循环:

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

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

或者:

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

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

不要忘记在finally块中关闭套接字。

我不想让线程自杀,相反,我希望其他线程或者父进程根据线程ID来杀死它。 - Danish Bin Sofwan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接