简体   繁体   English

Java-为多个并发客户端提供服务的多线程服务器

[英]Java - Multithread Server to serve multiple concurrent clients

I've been trying to make the code below to have multiple clients communicate with the same server. 我一直在尝试使下面的代码具有多个客户端与同一台服务器进行通信。 Currently, it works one client at a time with the server but it seems to be that when the second client opens, code stops at new ObjectInputStream(connection.getInputStream()); 当前,它一次可以与一个客户端在服务器上工作,但是似乎第二个客户端打开时,代码在新的ObjectInputStream(connection.getInputStream())处停止。 in the Class 3 (client) - see below. 在第3类(客户端)中-参见下文。

I've tried making the inputstream object transient to be shared in different threads but it didn't work, nor with making runClient method synchronized. 我试图使inputstream对象瞬态在不同线程中共享,但是它不起作用,也没有使runClient方法同步。

If I were to implement Serializable in the client class using serialVersionUID, how can I make multithreading work with the same server or is there any better way..? 如果我要使用serialVersionUID在客户端类中实现Serializable,那么如何使多线程在同一服务器上工作,或者有更好的方法吗?

Class 1 - server main 第1类-服务器主

public class EchoServer {

private ServerSocket server;
private int portNum;
public static final int DEFAULT_PORT = 8081;

public EchoServer(int portNum) {
    this.portNum = portNum;
} 

public void runServer() {
    System.out.println("Echo Server started...");

    try {
        server = new ServerSocket(portNum);
        Socket connection = server.accept();
        new Thread(new ClientHandler(connection)).run();
    } catch(IOException ex) {
        System.err.println("Error encountered! Port is likely already in use! Exiting program...");
        ex.printStackTrace();
    }
}

public static void main(String[] args) {
    if (args.length > 0) {
        (new EchoServer(Integer.parseInt(args[0]))).runServer();

    } else {
        (new EchoServer(DEFAULT_PORT)).runServer(); 
    }
  } 
}

Class 2 2级

public class ClientHandler implements Runnable {

private ObjectOutputStream output;
private ObjectInputStream input;
private String message;

/** Integer to hold the message number. */
private int messagenum;
private Socket connection;

public ClientHandler(Socket connection) {
    this.connection = connection;
}

@Override
public void run() {
    do{
        handleRequest();
    } while (true);
}

public void handleRequest() {
    try {
        output = new ObjectOutputStream(this.connection.getOutputStream());
        input = new ObjectInputStream(this.connection.getInputStream());
        do { 
            try {
                message = (String) input.readObject();
                System.out.println(messagenum +" Output> " +message);
            } catch (EOFException | SocketException e) {
                message = null;
            }

            if (message != null) {
                output.writeObject(messagenum +" FromServer> " +message);
                output.flush();
                ++messagenum;
            }
        } while (message != null);
        input.close();
        output.close();
        this.connection.close();

    }  catch (IOException | ClassNotFoundException ex) {
        System.err.println("Error encountered! Exiting program...");
        ex.printStackTrace();           
    }
  }
}

Class 3 - client main 第3类-客户主

public class EchoClient implements Serializable {
   private static final long serialVersionUID = 1L;
   private Socket connection;
   private ObjectOutputStream output;
   private transient ObjectInputStream input;
   private String message = "";
   private static String serverName;
   public static final String DEFAULT_SERVER_NAME = "localhost";
   private static int portNum;
   BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));

public EchoClient(String serverName, int portNum) {
    this.serverName = serverName;
    this.portNum = portNum;
}


public synchronized void runClient() {
    try {           
        connection = new Socket(InetAddress.getByName(serverName), portNum);
        output = new ObjectOutputStream(connection.getOutputStream());
        input = new ObjectInputStream(connection.getInputStream());

        do {
            System.out.print("Input> ");
            message = keyboard.readLine();

            if (message != null){
                output.writeObject(message);    
                output.flush();
                message = (String) input.readObject();
                System.out.println(message);
            }
        } while (message != null);
        input.close();
        output.close();
        connection.close();
    } catch (IOException ioException) {
        ioException.printStackTrace();
    } catch (ClassNotFoundException exception) {
        exception.printStackTrace();
    }
} 


public static void main(String[] args) {
    switch (args.length) {
    case 2:
        (new EchoClient(args[0], Integer.parseInt(args[1]))).runClient();
        break;
    case 1:
        (new EchoClient(DEFAULT_SERVER_NAME, Integer.parseInt(args[0]))).runClient();
        break;
    default:
        (new EchoClient(DEFAULT_SERVER_NAME, server.EchoServer.DEFAULT_PORT)).runClient();
    }
  } 
} 

run server needs to wait for connections in a loop otherwise it will connect once and that is it. 运行服务器需要循环等待连接,否则它将连接一次。 It needs to close its connections too. 它也需要关闭其连接。 Clean up its threads. 清理其线程。 that's just in server main. 那只是在服务器主服务器上。 I'm pretty sure this is a duplicate. 我很确定这是重复的。 So keep on researching 所以继续研究

Call server.accept() in the loop to accept multiple client connections as mentioned in the other answers. 如其他答案中所述,在循环中调用server.accept()以接受多个客户端连接。 Start a new thread with the Thread.start method instead of Thread.run - What's the difference between Thread start() and Runnable run() . 使用Thread.start方法而不是Thread.run启动新线程Thread.run start()和Runnable run()有什么区别

volatile boolean isRunning = true;
public void runServer() {
    System.out.println("Echo Server started...");

    try {
        server = new ServerSocket(portNum);
        while(isRunning) {
           Socket connection = server.accept();
           new Thread(new ClientHandler(connection)).start();
        }
    } catch(IOException ex) {
        System.err.println("Error encountered! Port is likely already in use! Exiting program...");
        ex.printStackTrace();
    }
}

As said by efekctive, you need your server.accept() in a loop, else it will accept the first client and exit the program. 如efekctive所说,您需要在循环中使用server.accept() ,否则它将接受第一个客户端并退出程序。 So put these two lines in runServer() in a loop like this: 因此,将这两行放在runServer()中,如下所示:

boolean isRunning = true;
while(isRunning){
    Socket connection = server.accept();
    new Thread(new ClientHandler(connection)).run();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM