JAVA多线程服务器套接字

时间:2016-10-05 10:38:52

标签: java websocket serversocket java-threads

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

我如何实现这一目标?

4 个答案:

答案 0 :(得分:1)

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

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()从而完成线程。

如果你跟踪线程,你可以设置“中断”标志并在while条件下探测它,这样你的处理线程就能够优雅地完成工作。

答案 1 :(得分: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();

然后发起杀戮

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

答案 2 :(得分:0)

要停止当前线程,请close the socket,然后从run()方法返回:

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

编辑:

要关闭另一个帖子,您可以,例如

  • 在线程之间共享clientID-Thread条目的线程安全映射。当新客户端连接时,您将在此映射中存储为此客户端启动的线程
  • 当一个Kill-client1命令进来时,你从地图中得到了与“client1”键相对应的线程,并在这个线程上调用“中断()”。
  • 在每个线程(例如,client1线程)中,在循环的每次迭代中,检查Thread.currentThread()。isInterrupted()的值。如果是,则关闭连接,从共享映射中删除线程,然后从run()方法返回。

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

答案 3 :(得分: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块中的套接字。