Java Socket - 如何检查ServerSocket是否已被其他客户端使用

时间:2017-09-14 16:17:30

标签: java sockets objectinputstream socketserver

我有这个客户端和服务器程序。

客户端从用户获取命令,并将其发送到服务器,服务器将结果(命令输出)返回给客户端。

我有2个类Command和CommandResult(表示命令和结果),我将它们作为json传递给ObjectInput(/ Output)Stream。

这是代码:

客户端

    Socket socket = new Socket("localhost", 1111);
    ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
    ObjectInputStream in = new ObjectInputStream(socket.getInputStream());

    while (true) {
        //get command from user
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter command:");
        String cmd = scanner.nextLine();
        Command command = new Command(cmd);

        //send the command as json
        String jsonCommand = new Gson().toJson(command);
        out.writeObject(jsonCommand);
        out.flush();

        //get and print the result
        String jsonCommandResult = (String) in.readObject();
        CommandResult commandResult = new Gson().fromJson(jsonCommandResult, CommandResult.class);
        System.out.println(commandResult.getOutput());
    }

服务器

    ServerSocket serverSocket = new ServerSocket(1111);
    Socket socket = serverSocket.accept();
    ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
    ObjectInputStream in = new ObjectInputStream(socket.getInputStream());

    while (true) {
        //read the command
        String cmd = (String) in.readObject();
        Command command = new Gson().fromJson(cmd, Command.class);

        //run() method will run the command with java Process and return the result
        CommandResult commandResult = command.run();

        //sent the result back to the client as json
        String jsonCommandResult = new Gson().toJson(commandResult);
        out.writeObject(jsonCommandResult);
        out.flush();
    }

现在,当我有一个客户端时,这工作正常。

但是如果我正在尝试运行客户端程序的第二个实例,而第一个实例仍然在循环中,它会挂起在ObjectInputStream构造函数中。 (第三行)

ObjectInputStream in = new ObjectInputStream(socket.getInputStream());

据我从文档中了解,构造函数阻塞直到创建了相应的ObjectOutputStream。

  

创建一个从指定的InputStream读取的ObjectInputStream。        从流中读取序列化流头并进行验证。        此构造函数将阻塞,直到相应的ObjectOutputStream        写了并刷了头。

在我的情况下,服务器尚未接受新客户端,因此尚未创建ObjectOutputStream。

现在,我想要的是在新客户端尝试连接而其他客户端连接到同一端口时抛出异常。 但在调用此构造函数之前,我无法弄清楚如何检查端口是否正在使用。

1 个答案:

答案 0 :(得分:-1)

正如@Kayaman在评论中提出的,我创建了一个Runnable类来处理当前客户端。

然后在服务器中,我循环serverSocket.accept()并通过为第一个客户端启动一个新线程,当时只允许一个客户端,并检查当前客户端是否完成了他的通信

这是最终的Server类。

public class Server {
    private static final int SERVER_READY = 1;
    private static final int SERVER_BUSY = 0;

    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        int port = Integer.valueOf(args[0]);
        System.out.println(String.format("Starting server on port %s", port));
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("Server is ready");

        Thread clientThread = null;
        while (true) {
            Socket clientSocket = serverSocket.accept();
            OutputStream os = clientSocket.getOutputStream();
            if (clientThread != null && clientThread.isAlive()) {
                os.write(SERVER_BUSY);
                continue;
            }
            os.write(SERVER_READY);
            System.out.println(String.format("Client connected: %s", clientSocket.getInetAddress()));
            clientThread = new Thread(new ClientWorker(clientSocket));
            clientThread.start();
        }
    }

    public static class ClientWorker implements Runnable {
        private final Socket clientSocket;

        ClientWorker(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }

        @Override
        public void run() {
            try {
                handleClient();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private void handleClient() throws IOException, ClassNotFoundException {
            try {
                ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream());
                ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
                while (true) {
                    System.out.println("Waiting for command..");
                    String cmd = (String) in.readObject();
                    System.out.println(String.format("Command received:\n %s", cmd));
                    if (cmd.equals("exit"))
                        break;
                    Command command = new Gson().fromJson(cmd, Command.class);
                    CommandResult commandResult = command.run();
                    String jsonCommandResult = new Gson().toJson(commandResult);
                    System.out.println(String.format("Sending response:\n %s", jsonCommandResult));
                    out.writeObject(jsonCommandResult);
                    out.flush();
                }
                //in case the client connection has closed, we want to end the while loop and accept a new client
            } catch (EOFException | SocketException e) {
            }
            System.out.println("Connection has been closed");
            clientSocket.close();
            System.out.println("Server is ready");
        }
    }
}

在Client类中,我检查服务器是否准备就绪。

Socket socket = new Socket(HOST, PORT);
int status = socket.getInputStream().read();
if (status != SERVER_READY)
    throw new Exception(String.format("Failed to connect to server %s:%s, Server is busy", HOST, PORT));
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
....
....