繁体   English   中英

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

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

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

我试图使inputstream对象瞬态在不同线程中共享,但是它不起作用,也没有使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启动新线程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();
    }
}

如efekctive所说,您需要在循环中使用server.accept() ,否则它将接受第一个客户端并退出程序。 因此,将这两行放在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