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

标签 java multithreading

我一直在尝试编写下面的代码以使多个客户端与同一服务器进行通信。 目前,它一次与服务器一起工作一个客户端,但似乎当第二个客户端打开时,代码停止在 new ObjectInputStream(connection.getInputStream()); 处。在第 3 类(客户端)中 - 见下文。

我尝试使 inputstream 对象 transient 在不同线程中共享,但它不起作用,也没有使 runClient 方法同步。

如果我要使用serialVersionUID在客户端类中实现Serializable,我怎样才能使多线程在同一服务器上工作或者有没有更好的方法..?

第 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(); 
    }
  } 
}

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();           
    }
  }
}

第 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();
    }
  } 
} 

最佳答案

在循环中调用server.accept()以接受多个客户端连接,如其他答案中所述。使用 Thread.start 方法而不是 Thread.run 启动新线程 - What's the difference between Thread start() and 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();
    }
}

关于Java - 多线程服务器为多个并发客户端提供服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42473882/

相关文章:

c++ - 避免并行递归异步算法中的递归模板实例化溢出

node.js - NodeJS中的多线程和异步有什么区别

java - 有没有办法让按钮对对象执行操作,而无需创建实现 ActionListener 的新类?

java - Maven单独构建打包和Cucumber集成测试

java - 是否有任何工作线程可以在 android 中更新 UI?

java - JAVA 中的机器人 KeyEvent.VK_AT 问题

Java Statement.executeQuery SQL 错误 ORDER BY 和/或 LIMIT - 不确定正确的格式是什么

python - 引用继承的类函数

c# - 在 C# 中执行繁重的 CPU 操作时并行文件 IO

c++ - boost asio在两个线程c++之间进行通信