如何在 Java 中为断开连接的客户端终止服务器中的线程

How to Kill Threads in Server for Disconnected Clients in Java

我正在 java 中开发多线程 Server/Client 套接字。每当客户端连接到服务器时,都会为它创建一个线程。但当客户端断开连接或用户关闭其进程时,其线程仍将保留在服务器中。我怎么知道套接字已断开连接然后我可以杀死服务器中的相应线程? 顺便说一下,我在服务器中有一个检查系统,它检查客户端是否已经注册了一个 id。因此,例如,当 ID=12 的客户端连接并突然断开连接,然后又想再次连接时,服务器不会让客户端连接,因为它的服务器将其套接字信息保存在 ArrayList 中,并告诉客户端 ID=12 的客户端服务器中已经 运行。请帮我解决这个问题

这是我的服务器代码:

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

这是我的客户经理代码:

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

您的代码中有一些小问题"mistakes"。

为什么要先将接收到的数据写入缓冲区,然后再用它创建一个新字符串?

从 Socket 的 InputStream 创建一个 BufferedReaderInputStreamReader

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

使用方法bufferedReader.readLine()bufferedReader.read()立即获取字符串。

关于您的问题 - 如果客户端远程关闭连接(流结束),read()return -1readLine()return null。 - 您可以检查这些条件并停止线程 thread.interrupt().

如果远程客户端确实遵循 TCP 协议的拆卸阶段,您将在尝试从套接字 inputStream 读取 ()/readLine()/write() 时得到 SocketException - 在本例中来自bufferedReader()。 - 捕获异常并关闭线程 thread.interrupt().