更新:非常感谢Antoniossss和Peter Lawrey!
我创建了一个多线程服务器 - 客户端通信。
我有3个类:Server,Client,RequestHandler。
服务器打开ServerSocket,然后通过accept()开始侦听客户端,如果客户端连接,则将客户端的任务(某些String)引用到RequestHandler。
对我来说重要的命令是“关闭”。 如果RequestHandler找到此命令,则调用服务器中的方法来关闭。
此方法基于Executor Service的用法示例: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html(如果您不想点击该链接,请参阅该方法的 FAT 文字)
您不必阅读下面提供的代码,但如果有人对此感兴趣,我会提供
使用方法示例:
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
public class MulServer_v1 {
protected static int portNumber = 8540;
protected static int max_Clients = 3;
protected static boolean shutdownFlag = false;
private static ServerSocket serverSocket;
protected ExecutorService executor;
protected static ArrayList<Socket> socketList = new ArrayList<>();
public MulServer_v1(int portNumber, int poolSize) {
}
public void runServer() {
try {
serverSocket = new ServerSocket(portNumber);
executor = Executors.newFixedThreadPool(max_Clients);
} catch (IOException e) {
System.out.println("Could not create server on specific port");
e.printStackTrace();
}
while (!shutdownFlag) {
try {
Socket clientSocket = serverSocket.accept();
socketList.add(clientSocket);
executor.submit(new RequestHandler_v1(clientSocket));
} catch (IOException e) {
System.out.println("Couldn't accept on the Socket");
executor.shutdown();
e.printStackTrace();
}
}
shutdownAndAwaitTermination();
}
public void shutdownAndAwaitTermination() {
System.out.println("Shutting down..");
executor.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
executor.shutdownNow();
// Cancel currently executing tasks
System.out.println("komme ich hierhin?");
// Wait a while for tasks to respond to being cancelled
if (!executor.awaitTermination(10, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
executor.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
try {
serverSocket.close();
} catch (IOException e) {
System.out.println("Serversocket konnte nicht geschlossen werden");
e.printStackTrace();
}
System.out.println("I got here!");
for (Socket s : socketList) {
if (s != null) {
try {
s.close();
} catch (IOException e) {
System.out.println("Couldn't close the socket");
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
MulServer_v1 server = new MulServer_v1(portNumber, max_Clients);
server.runServer();
}
}
public class Client_v1 {
public static final String HOSTNAME = "localhost";
public static final int PORTNUMBER = 8540;
private static boolean clientClose = false;
public static void main(String[] args) throws IOException {
System.out.println("Client started");
try (Socket socket = new Socket(HOSTNAME, PORTNUMBER);
PrintWriter out = new PrintWriter(socket.getOutputStream(),
true);
// InputStream test = echoSocket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in))) {
String userInput;
while ((userInput = stdIn.readLine()) != null && !clientClose) {
out.println(userInput);
System.out.println("echo: " + in.readLine());
// if (userInput.equals("BYE")) {
// break;
// }
}
} catch (UnknownHostException e) {
System.err.println("Don't know about host " + HOSTNAME);
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to "
+ HOSTNAME);
System.exit(1);
}
}
protected static void closeClient() {
clientClose = true;
}
}
public class RequestHandler_v1 implements Runnable {
// private final String password = "passwort";
private final Socket client;
private boolean closeFlag = false;
public RequestHandler_v1(Socket client) {
this.client = client;
}
@Override
public void run() {
try (BufferedReader in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(client.getOutputStream()));) {
System.out.println("Thread started with name:"
+ Thread.currentThread().getName());
String userInput;
String serverResponse;
while ((userInput = in.readLine()) != null) {
serverResponse = processInput(userInput);
System.out.println("Received message from "
+ Thread.currentThread().getName() + " : " + userInput);
writer.write("Sever Response : " + serverResponse);
writer.newLine();
writer.flush();
if (closeFlag) {
Client_v1.closeClient();
MulServer_v1.socketList.remove(client);
client.close();
}
}
} catch (IOException e) {
System.out.println("I/O exception: " + e);
} catch (Exception ex) {
System.out.println("Exception in Thread Run. Exception : " + ex);
}
}
public String processInput(String input) {
boolean commandFound = false;
String output = "";
try {
if (input.getBytes("UTF-8").length > 255)
output = "Max string length exceeded";
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Pattern allPattern = Pattern
.compile("(?<lower>^LOWERCASE\\s.+)|(?<upper>^UPPERCASE\\s.+)|(?<reverse>^REVERSE\\s.+)|(?<bye>^BYE)|(?<shutdown>^SHUTDOWN passwort)");
Matcher allMatcher = allPattern.matcher(input);
if (allMatcher.find()) {
String lower = allMatcher.group("lower");
String upper = allMatcher.group("upper");
String reverse = allMatcher.group("reverse");
String bye = allMatcher.group("bye");
String shutdown = allMatcher.group("shutdown");
commandFound = true;
if (lower != null) {
output = lower.substring(10).toLowerCase();
}
if (upper != null) {
output = upper.substring(10).toUpperCase();
}
if (reverse != null) {
output = new StringBuilder(reverse.substring(8)).reverse()
.toString();
}
if (bye != null) {
output = "BYE";
closeFlag = true;
}
if (shutdown != null) {
output = "SHUTDOWN";
MulServer_v1.shutdownFlag = true;
closeFlag = true;
}
} else {
commandFound = false;
output = "UNKNOWN COMMAND";
}
if (commandFound) {
output = "OK ".concat(output);
} else {
output = "ERROR ".concat(output);
}
return output;
}
}
现在关闭工作正常,但新客户端可以在关机后连接。怎么可能? 这是我曾经查过的Sysout:
关闭..
线程以name:pool-1-thread-3
开头从pool-1-thread-3收到消息:。 //&lt; - 这个(发送消息)//应该不会发生,因为executor.shutdown();已被召唤。
答案 0 :(得分:1)
问题是你的信号被破坏了:
while (!shutdownFlag) {
try {
Socket clientSocket = serverSocket.accept();
executor.execute(new RequestHandler_v1(clientSocket));
} catch (IOException e) {
accept()
阻塞操作 - 阻塞直到新连接正常?这是culrpit。发送“shutdown”命令后,当前线程将在accept()
上取消阻止,提交,通过while条件和再次阻止。在此之后,正确的执行程序将标志设置为false,但服务器仍为accepting
,因此池永远不会关闭。
另一次连接尝试应该唤醒服务器并尊重shutdownFlag
突破循环并导致所有处理程序在10秒后死亡。
此外:
while ((userInput = in.readLine()) != null) {
是一个阻止操作 - 它阻止你的任务完成,因此池会更新关闭。如果流将以自然或异常结束,将返回null
。你没有在两边都没有结束流。所以它会阻止。
ExecutorsService#shutdownNow()并不意味着来自池的线程将被终止 - 它们被发出信号以终止,并且线程将像使用Thread.isTerminated()标志所提到的@PeterLawrey一样正常终止。
答案 1 :(得分:1)
关闭套接字的概念证明将从阻塞的IO操作中断: public class Buffers { private static Socket client;
static class ServerThread extends Thread {
@Override
public void run() {
try {
ServerSocket serverS = new ServerSocket(1099);
client = serverS.accept();
client.getOutputStream().write('a');
client.getOutputStream().flush();
Thread.sleep(2000);
client.close();
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
static class ClientThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(500);
Socket socket = new Socket("127.0.0.1", 1099);
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("Will try to read");
String line=null;
while ((line = input.readLine()) != null) { // block here
System.out.println("Read " + line); // will never come here
}
} catch (Exception e) {
System.out.println("Server closed the connection!");
}
super.run();
}
}
public static void main(String[] args) throws InterruptedException {
new ServerThread().start();
ClientThread t = new ClientThread();
t.start();
t.join();
}
如果您发表评论client.close();
应用将永远不会像您的情况那样结束。