作者:mobiledu2502886077 | 来源:互联网 | 2024-11-22 23:16
本文基于Java官方文档进行了适当修改,旨在介绍如何实现一个能够同时处理多个客户端请求的服务端程序。在前文中,我们探讨了单客户端访问的服务端实现,而本篇将深入讲解多客户端环境下的服务端设计与实现。
本文内容基于Java官方文档,结合实际需求进行了适当调整和扩展。
在上一篇文章中,我们详细讨论了如何构建一个只能处理单一客户端连接的服务端。然而,在实际应用中,服务端通常需要同时响应多个客户端的请求。因此,本文将重点介绍如何通过多线程技术实现一个能够同时支持多个客户端的服务端。
首先,我们来看一下协议类的设计,这部分内容与之前的版本保持一致:
package com.dylan.socket; public class KnockKnockProtocol { private static final int WAITING = 0; private static final int SENTKNOCKKNOCK = 1; private static final int SENTCLUE = 2; private static final int ANOTHER = 3; private static final int NUMJOKES = 5; private int state = WAITING; private int currentJoke = 0; private String[] clues = { "Turnip", "Little Old Lady", "Atch", "Who", "Who" }; private String[] answers = { "Turnip the heat, it's cold in here!", "I didn't know you could yodel!", "Bless you!", "Is there an owl in here?", "Is there an echo in here?" }; public String processInput(String theInput) { String theOutput = null; if (state == WAITING) { theOutput = "Knock! Knock!"; state = SENTKNOCKKNOCK; } else if (state == SENTKNOCKKNOCK) { if (theInput.equalsIgnoreCase("Who's there?")) { theOutput = clues[currentJoke]; state = SENTCLUE; } else { theOutput = "You're supposed to say \"Who's there?\"! Try again. Knock! Knock!"; } } else if (state == SENTCLUE) { if (theInput.equalsIgnoreCase(clues[currentJoke] + " who?")) { theOutput = answers[currentJoke] + " Want another? (y/n)"; state = ANOTHER; } else { theOutput = "You're supposed to say \"" + clues[currentJoke] + " who?\" Try again. Knock! Knock!"; state = SENTKNOCKKNOCK; } } else if (state == ANOTHER) { if (theInput.equalsIgnoreCase("y")) { theOutput = "Knock! Knock!"; if (currentJoke == (NUMJOKES - 1)) currentJoke = 0; else currentJoke++; state = SENTKNOCKKNOCK; } else { theOutput = "Bye."; state = WAITING; } } return theOutput; } }
接下来是服务端的主类,该类负责监听特定端口并为每个新连接创建一个新的线程来处理客户端请求:
package com.dylan.socket; import java.io.IOException; import java.net.ServerSocket; public class KKMultiServer { private static final int PORT = 8858; public static void main(String[] args) { boolean listening = true; try (ServerSocket serverSocket = new ServerSocket(PORT)) { while (listening) { new KKMultiServerThread(serverSocket.accept()).start(); } } catch (IOException e) { System.err.println("Could not listen on port " + PORT); System.exit(-1); } } }
最后,我们来看看多线程服务类,这是整个程序的核心部分,它负责处理与客户端的交互:
package com.dylan.socket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class KKMultiServerThread extends Thread { private Socket socket = null; public KKMultiServerThread(Socket socket) { super("KKMultiServerThread"); this.socket = socket; } public void run() { try (PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));) { String inputLine, outputLine; KnockKnockProtocol kkp = new KnockKnockProtocol(); outputLine = kkp.processInput(null); out.println(outputLine); while ((inputLine = in.readLine()) != null) { outputLine = kkp.processInput(inputLine); out.println(outputLine); if (outputLine.equals("Bye.")) break; } socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
客户端代码相对简单,主要用于发送请求并接收服务端的响应:
package com.dylan.socket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class KnockKnockClient { private static final String HOST = "127.0.0.1"; private static final int PORT = 8858; public static void main(String[] args) throws IOException { try (Socket kkSocket = new Socket(HOST, PORT); PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(kkSocket.getInputStream()));) { BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String fromServer; String fromUser; while ((fromServer = in.readLine()) != null) { System.out.println("Server: " + fromServer); if (fromServer.equals("Bye.")) break; fromUser = stdIn.readLine(); if (fromUser != null) { System.out.println("Client: " + fromUser); out.println(fromUser); } } } catch (UnknownHostException e) { System.err.println("Don't know about host " + HOST); System.exit(1); } catch (IOException e) { System.err.println("Couldn't get I/O for the connection to " + HOST); System.exit(1); } } }