且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Java中的多线程客户端服务器聊天应用程序

更新时间:2022-03-25 23:14:25

每个新客户端应位于服务器端单独的 Thread 上,您要分配一个 new Socket 到您的 serviceSocket ,基本上就忽略了以前连接的客户端。

Every new client should be on seperate Thread on server side, you are assigning a new Socket to your serviceSocket and by that you basically ignore previously connected clients.

您为新连接的客户端启动新服务器,而不是启动 Thread 。您应该为每个连接的客户端创建一个新套接字,并在 new线程上运行它,而不启动新服务器客户端连接后。

You start a new Server instead of starting a Thread for the client that just connected. You should create a new Socket for every client that is connected and run it on a new Thread not start a new Server after a client was connected.

更新

以下是基本的多客户端服务器的示例:

Here is an example of a basic multiple client server:

服务器代码由几类组成:

// Server.java
public class Server {

    private ServerSocket        socket;
    private ConnectionListener  connectionListener;

    // temp
    private List<Client> clientList = new ArrayList<Client>();
    // temp end

    public Server(int port) {
        try {
            socket = new ServerSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
        }

        connectionListener = new ConnectionListener(this);
    }

    public void start() throws IOException {

        connectionListener.start();

        // temp will move to a Thread later
        BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
        String input;
        while (((input = stdIn.readLine()) != null) && connectionListener.isAlive()) {
            if (input.equalsIgnoreCase("exit")) {
                break;
            } else {
                for (int i = 0; i < input.length(); i++)
                    System.out.print("\b");
                System.out.println("Admin: " + input);
                for (Client c : clientList) {
                    c.send("Admin: " + input);
                }
            }

        }
        stop();
        // temp end
    }

    public void stop() {

        connectionListener.stop();
        for (Client c : clientList) {
            c.closeSession();
        }

        System.out.println("Server terminated!");
    }

    public synchronized void addConnection(Connection connection) {

        Client c = new Client(connection, clientList);
        clientList.add(c);
        c.startSession();
        System.out.println("Client connected");
    }

    public ServerSocket getSocket() {

        return socket;
    }

    public static void main(String[] args) throws IOException {

        int port;
        if (args.length > 0)
            port = Integer.parseInt(args[0]);
        else
            port = 4444;
        Server s = new Server(port);
        s.start();
    }

}







// ConnectionListener.java
public class ConnectionListener implements Runnable {

    private Server          server;
    private ServerSocket    socket;
    private boolean         running;
    private Thread          t;

    public ConnectionListener(Server server) {
        this.server = server;
        this.socket = server.getSocket();
        running = false;
    }

    public synchronized void start() {

        if (running)
            return;

        running = true;
        t = new Thread(this);
        t.start();
    }

    public synchronized void stop() {

        if (!running)
            return;

        System.out.print("Terminating connection listener on:" + socket.getLocalSocketAddress() + "...");

        running = false;

        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("TERMINATED!");
    }

    @Override
    public void run() {

        System.out.println("Listening for connections on: " + socket.getLocalSocketAddress());

        try {
            while (running) {
                Socket request = socket.accept();
                Connection connection = new Connection(request);
                server.addConnection(connection);
            }
        } catch (IOException e) {
            //e.printStackTrace();
        }

    }

    public boolean isAlive() {

        return running;
    }

}







// Connection.java
public class Connection {

    private Socket          socket;
    private BufferedReader  in;
    private BufferedWriter  out;
    private boolean         alive;

    public Connection(Socket socket) {
        this.socket = socket;
        try {
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        alive = true;
    }

    public String read() {

        try {
            if (in.ready()) {
                return in.readLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    public void write(String data) {

        try {
            out.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void flush() {

        try {
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean close() {

        boolean result = true;
        try {
            in.close();
            out.close();
            socket.close();
            alive = false;
        } catch (IOException e) {
            e.printStackTrace();
            result = false;
        }
        return result;
    }

    public boolean isAlive() {

        return alive;
    }

}







// Client.java

/*
 * This is still server side, that is the handler for the connected clients
 */
public class Client implements Runnable {

    public static final long IDLE_TIME = 10;

    private Connection  connection;
    private boolean     alive;
    private Thread      t;

    private List<Client> clientList;

    public Client(Connection connection, List<Client> clientList) {
        this.connection = connection;
        this.clientList = clientList;
        alive = false;
    }

    public synchronized void startSession() {

        if (alive)
            return;

        alive = true;

        t = new Thread(this);
        t.start();

    }

    public synchronized void closeSession() {

        if (!alive)
            return;

        alive = false;

        try {
            connection.close();
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void run() {

        while (connection.isAlive()) {

            String in = connection.read();
            if (in != null) {
                System.out.println(in);
                for (Client c : clientList) {
                    c.send(in);
                }
            } else {
                try {
                    Thread.sleep(IDLE_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }

    }

    public void send(String msg) {

        connection.write(msg + "\n");
        connection.flush();
    }

}

客户端示例:

// Client.java
public class Client {

    public static void main(String[] args) {

        String host;
        if (args.length > 0)
            host = args[0];
        else
            host = "localhost";

        int port;
        if (args.length > 1)
            port = Integer.parseInt(args[1]);
        else
            port = 4444;

        try (Socket socket = new Socket(host, port);
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) {

            Thread input = new Thread(() -> {
                String msg;
                try {
                    while ((msg = in.readLine()) != null) {
                        System.out.println(msg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            input.start();

            String userName = "User" + ((int) (Math.random() * 200));
            String msg;
            try {
                while ((msg = stdIn.readLine()) != null) {
                    for (int i = 0; i < msg.length(); i++)
                        System.out.print("\b");
                    out.write(userName + ": " + msg + "\n");
                    out.flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

这不是***的例子,但我希望您可以使用它并根据您的需要进行调整。

It's not the best example but I hope you can work with it and tweak it to your needs.