multithreading套接字通信客户/服务器

我写完了一个工作正常的Client / Server Socket通信程序。 现在我想弄清楚如何制作它,以便我可以同时与服务器建立多个客户端连接。 我环顾四周,似乎有不止两种不同的方式来做到这一点。 所以我来这里向你们寻求帮助/建议。

我的服务器:

public class Server { private ServerSocket serverSocket = null; private Socket clientSocket = null; public Server() { try { serverSocket = new ServerSocket(7003); } catch (IOException e) { System.err.println("Could not listen on port: 7003"); System.exit(1); } try { clientSocket = serverSocket.accept(); } catch (IOException e) { System.err.println("Accept failed"); System.exit(1); } } public void startServer() throws IOException { PrintWriter output = new PrintWriter(clientSocket.getOutputStream(), true); BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); String inputLine, outputLine; outputLine = "Connected to Server"; output.println(outputLine); while ((inputLine = input.readLine()) != null) { // This just determines users input and server ruturns output based on that outputLine = this.getServerOutput(inputLine); output.println(outputLine); if (outputLine.equals("Bye")) break; } output.close(); input.close(); clientSocket.close(); serverSocket.close(); } } 

我需要让我的构造函数创建线程和startServer()还是我的run方法?

您应该使用ExecutorService 。 您的客户端请求处理将是Runnablerun() ,并且在每次接受之后,您可以调用ExecutorService.submit(runnableTask)来异步服务客户端。

使用ExecutorService的示例。

 public class MyServer { private static MyServer server; private ServerSocket serverSocket; /** * This executor service has 10 threads. * So it means your server can process max 10 concurrent requests. */ private ExecutorService executorService = Executors.newFixedThreadPool(10); public static void main(String[] args) throws IOException { server = new MyServer(); server.runServer(); } private void runServer() { int serverPort = 8085; try { System.out.println("Starting Server"); serverSocket = new ServerSocket(serverPort); while(true) { System.out.println("Waiting for request"); try { Socket s = serverSocket.accept(); System.out.println("Processing request"); executorService.submit(new ServiceRequest(s)); } catch(IOException ioe) { System.out.println("Error accepting connection"); ioe.printStackTrace(); } } }catch(IOException e) { System.out.println("Error starting Server on "+serverPort); e.printStackTrace(); } } //Call the method when you want to stop your server private void stopServer() { //Stop the executor service. executorService.shutdownNow(); try { //Stop accepting requests. serverSocket.close(); } catch (IOException e) { System.out.println("Error in server shutdown"); e.printStackTrace(); } System.exit(0); } class ServiceRequest implements Runnable { private Socket socket; public ServiceRequest(Socket connection) { this.socket = connection; } public void run() { //Do your logic here. You have the `socket` available to read/write data. //Make sure to close try { socket.close(); }catch(IOException ioe) { System.out.println("Error closing client connection"); } } } } 

如何使它可以同时与服务器建立多个客户端连接

现在,您正在启动服务器并立即等待单个客户端在构造函数中进行连接。

 clientSocket = serverSocket.accept(); 

然后在startServer()方法中处理单个套接字连接。 这意味着不会处理任何其他客户端。

 public void startServer() throws IOException { PrintWriter output = new PrintWriter(clientSocket.getOutputStream(), true); ... 

通常使用这样的服务器模式,您将执行以下操作:

  1. 在构造函数中设置服务器套接字。
  2. 创建一个acceptClients()方法,该方法将循环等待客户端被接受。 这可以分叉一个线程来接受后台自己的线程中的客户端。
  3. 对于每个客户端,要么分叉一个线程来处理连接,要么将线程传递给客户端套接字。 如@basiljames所示,更好的方法是使用ExecutorService为您管理线程。

这是一些示例代码:

 public class Server { private ServerSocket serverSocket = null; public Server(int portNumber) throws IOException { serverSocket = new ServerSocket(portNumber); } // this could be run in a thread in the background public void acceptClients() throws IOException { // create an open ended thread-pool ExecutorService threadPool = Executors.newCachedThreadPool(); try { while (!Thread.currentThread().isInterrupted()) { // wait for a client to connect Socket clientSocket = serverSocket.accept(); // create a new client handler object for that socket, // and fork it in a background thread threadPool.submit(new ClientHandler(clientSocket)); } } finally { // we _have_ to shutdown the thread-pool when we are done threadPool.shutdown(); } } // if server is running in background, you stop it by killing the socket public void stop() throws IOException { serverSocket.close(); } // this class handles each client connection private static class ClientHandler implements Runnable { private final Socket clientSocket; public ClientHandler(Socket clientSocket) { this.clientSocket = clientSocket; } public void run() { // use the client socket to handle the client connection ... } } } 

对于像这样的所有Thread实现,建议使用ExecutorService线程池。 但是,如果由于某种原因您仍然坚持使用原始Thread ,则可以在acceptClients()方法中执行以下操作:

  public void acceptClients() throws IOException { while (!Thread.currentThread().isInterrupted()) { // wait for a client to connect Socket clientSocket = serverSocket.accept(); // fork a background client thread new Thread(new ClientHandler(clientSocket)).start(); } } 

更改此: public void startServer() throws IOException对此: public void startServer(Socket clientSocket) throws IOException

那么你需要做的就是:

 public Server() { try { serverSocket = new ServerSocket(7003); } catch (IOException e) { System.err.println("Could not listen on port: 7003"); System.exit(1); } try { while(true) { final Socket socket = serverSocket.accept(); new Thread(new Runnable() { public void run() { try { startServer(socket); } catch(IOException e) {e.printStackTrace();} } }).start(); } } catch(IOException e) { System.err.println("Accept failed"); System.exit(1); } } 

最后,你可以删除private Socket clientSocket = null;

那应该会让你到那里。 或者至少非常接近。