如何在 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
创建一个 BufferedReader
和 InputStreamReader
。
bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
使用方法bufferedReader.readLine()
或bufferedReader.read()
立即获取字符串。
关于您的问题 - 如果客户端远程关闭连接(流结束),read()
将 return -1
,readLine()
将 return null
。
- 您可以检查这些条件并停止线程 thread.interrupt()
.
如果远程客户端确实遵循 TCP 协议的拆卸阶段,您将在尝试从套接字 inputStream 读取 ()/readLine()/write() 时得到 SocketException
- 在本例中来自bufferedReader()
。
- 捕获异常并关闭线程 thread.interrupt()
.
我正在 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
创建一个 BufferedReader
和 InputStreamReader
。
bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
使用方法bufferedReader.readLine()
或bufferedReader.read()
立即获取字符串。
关于您的问题 - 如果客户端远程关闭连接(流结束),read()
将 return -1
,readLine()
将 return null
。
- 您可以检查这些条件并停止线程 thread.interrupt()
.
如果远程客户端确实遵循 TCP 协议的拆卸阶段,您将在尝试从套接字 inputStream 读取 ()/readLine()/write() 时得到 SocketException
- 在本例中来自bufferedReader()
。
- 捕获异常并关闭线程 thread.interrupt()
.