Создание класса Server и класса Client для пользовательского чата в Java - PullRequest
0 голосов
/ 09 октября 2018

Объяснение моей программы

Я создал сервер чата с использованием Java, который состоит из 3 классов, класса сервера, класса пользователя и класса комнаты чата.Я также создал клиентский класс для взаимодействия с сервером.Сервер создает объект пользователя каждый раз, когда клиент подключается к серверу.Каждый объект пользователя отслеживает чаты, в которых находится пользователь, и запускает поток, который прослушивает вводимые пользователем данные.Серверный объект проходит через каждый чат, чтобы увидеть, использовался ли он на прошлой неделе.

Проблема

Мне интересно, как на самом деле установить соединение смой сервер с клиентским объектом.В настоящее время я открываю два случая затмения.Я запускаю свою серверную программу в одной, а свою клиентскую программу - в другой, но я ничего не получаю в консоли, что должно произойти, потому что сервер должен отправить клиенту информацию, которую клиент затем отобразит на консоли.Человек на стороне клиента мог бы затем дать информацию, которую клиент будет принимать и отправлять на сервер.

Мне интересно, почему сейчас ничего не происходит, и какие улучшения я могу сделать.


Основные файлы


Server.java

/*
 * Creates a server that can host up to 10 clients who can join chat rooms, post messages in chatrooms, and view posts made by other clients within the same chat room
 */
public class Server implements Runnable{
    protected ArrayList<User> userList; //A list of users, where each user is a client connected to the server
    protected LinkedList<Chatroom> chatRooms;   //A list of chatrooms where each client can post messages in, where messages can be seen by all clients in the chatroom
    private ServerSocket serverSocket;  //The socket for the server

    /*
     * Constructor for the server class. Initializes the server attributes,
     */
    public Server() {
        this.userList = new ArrayList<User>(10);
        this.chatRooms = new LinkedList<Chatroom>();
        try {
            this.serverSocket = new ServerSocket(5000);
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
     * Creates a new user when a client connects to the server, and starts a user thread
     */
    public void createUser() {
        try {
            Socket userSocket = serverSocket.accept();
            Thread user = new Thread(new User(userSocket, this));
            user.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
     * Creates a chatroom for clients to interact in
     * @param roomName: The name of the chat room to be created
     */
    protected Chatroom createChatRoom(String roomName) {
        Chatroom room = new Chatroom(roomName);
        return room;
    }

    /*
     * Receives messages from clients and performs actions based on the requests of the client
     * (non-Javadoc)
     * @see java.lang.Thread#run()
     */
    public void run() {
        long currentTime;
        while(true) {
            try {
                currentTime = System.currentTimeMillis() / 1000;
                //Loop through each chatroom and check if the chatroom has been used(joined or had a message sent to it) and remove that chatroom if it hasn't been used in a week
                for (int i = 0; i < chatRooms.size(); i++) {
                    if (currentTime - 604800 >= chatRooms.get(i).dateLastUsed) {
                        chatRooms.remove(i);
                        //Also remove the chatroom from clients lists of chatrooms
                    }
                }

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

    public static void main(String args[]) {
        Server server = new Server ();
        server.run();
    }
}

Client.java

public class Client extends Thread{
    private String ip = "127.0.0.1";
    private int port = 5000 ;
    private Socket socket;
    private DataInputStream iStream;
    private DataOutputStream oStream;
    private String input;

    public Client() {
        try {
            this.socket = new Socket(ip, port);
            this.iStream = new DataInputStream(socket.getInputStream());
            this.oStream = new DataOutputStream(socket.getOutputStream());
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * Sends a message to the user
     * @param message: The message to be sent to the user
     */
    protected void send (String message) {
        try {
            oStream.writeUTF(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
     * Closes the connection to the client
     */
    protected void close () {
        try {
            iStream.close();
            oStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
     * Runs a thread for the client to constantly receive the clients input(non-Javadoc)
     * @see java.lang.Thread#run()
     */
    public void run() {
        try {
            Scanner reader = new Scanner(System.in);
            input = iStream.readUTF();
            String userInput;//Check if there is input from the user
            while (input != null) {
                input = iStream.readUTF();
                System.out.println(input);
                userInput = reader.next();
                oStream.writeUTF(userInput);
            }
            reader.close();
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
        Client client = new Client();
        client.run();
    }

}

Объекты, используемые Server.java


User.java

//Each user represents a client that has connected to the server
public class User implements Runnable{
    private DataInputStream inputStream;
    private DataOutputStream outputStream;
    private Socket socket;
    private String name;
    protected LinkedList<Chatroom> chatRooms;
    private String input;
    private Server server;

    /*
     * User Constructor, create a user for each client connecting to the server
     * @socket The socket that the user will be communicated through
     * The client is prompted to create a name for themself, they are they prompted to do an action.
     */
    public User(Socket socket, Server server) {
        this.socket = socket;
        this.server = server;
        try {
            inputStream = new DataInputStream(socket.getInputStream());
            outputStream = new DataOutputStream(socket.getOutputStream());
            outputStream.writeUTF("Enter a name");
            this.name = inputStream.readUTF();
            String message = "Create a chatroom: create \nList Chat Rooms: list \n Join Chat Room: join \n Leave Chat Room: Leave";
            send(message);
        } catch (IOException e) {   
        }
    }

    /*
     * Returns the current amount of chatrooms this user is in
     */
    protected int chatRoomLength () {
        return this.chatRooms.size();
    }

    /*
     * Gets the most recent input from the user
     */
    protected String getInput() {
        return input;
    }

    /*
     * Puts a user/client in a chatroom
     * @param cRoom: The chatroom that the user will join 
     */
    protected void joinRoom (Chatroom cRoom) {
        chatRooms.add(cRoom);
    }

    /*
     * Removes a user/client from a chatroom
     */
    protected void leaveRoom (Chatroom c) {
        chatRooms.removeFirstOccurrence(c);
    }

    /*
     * Sends a message to the user
     * @param message: The message to be sent to the user
     */
    protected void send (String message) {
        try {
            outputStream.writeUTF(message);
        } catch (IOException e) {
        }
    }

    /*
     * Closes the connection to the client
     */
    protected void close () {
        try {
            inputStream.close();
            outputStream.close();
            socket.close();
        } catch (IOException e) {}
    }

    /*
     * Runs a thread for the client to constantly receive the clients input(non-Javadoc)
     * @see java.lang.Thread#run()
     */
    public void run() {
        try {
            input = inputStream.readUTF();  //Check if there is input from the user
            //if the user has disconnected from the server, remove them from the list
            if (input == null) {
                this.close();
                this.server.userList.remove(this);
            }else if (input.equals("create")){  //create a chat room
                this.send("Name the Chatroom");
                input = this.getInput();
                Chatroom c = this.server.createChatRoom(input);
                this.joinRoom(c);
            }else if (input.equals("list")) {   //List the current chatrooms
                String rooms = "";
                for (int j = 0; j< server.chatRooms.size(); j++) {
                    rooms = rooms + server.chatRooms.get(j).getName() + "\n";
                }
                this.send(rooms);
            }else if (input.equals("join")) {   //Join the user to a chat room
                int end = chatRooms.size();
                if (end == 0) {
                    this.send("There's currently no chat rooms");
                }else { 
                    this.send("Which room would you like to join");
                    input = this.getInput();
                    for (int k = 0; k < end; k++) {
                        if (chatRooms.get(k).getName().equals(input)) {
                            Chatroom joinRoom = chatRooms.get(k);
                            this.joinRoom(joinRoom);
                            String message = "Chatroom " + input + " messages. \n";
                            //Print the current messages in the chatroom to the user
                            for (int j = 0; j < joinRoom.messages.size(); j++ ) {
                                message = message + joinRoom.messages.get(j) + "\n";
                            }
                            this.send(message);
                        } else if (k == end - 1) {
                            this.send("There's no chat rooms by that name");
                        }
                    }
                }
            }else if (input.equals("leave")) {  //Remove the user from a chatroom
                int end = this.chatRoomLength();    //if the chatroom list of the user is empty
                if (end == 0) {
                    this.send("You are not in any Chat Rooms");
                }else {
                    this.send("Which room would you like to leave");
                    input = this.getInput();

                    for (int m = 0; m < end; m++) { //find the chatroom by the same name
                        if (this.chatRooms.get(m).getName().equals(input)) {
                            this.chatRooms.remove(m);
                            this.send("Great! You've been removed from" + input);
                        } else if (m == end - 1) {
                            this.send("You're not in a chatroom named" + input);
                        }
                    }
                }
            }else { //All other input is interpreted as a message to be posted in the chatrooms that the user is in
                int end = this.chatRoomLength();
                if (end == 0) {
                    this.send("You can't write to any chat rooms because you are not in any");
                }
                for (int m = 0; m < end; m++) { //Add the users message to ALL the chatrooms the user is in
                    Chatroom c = this.chatRooms.get(m);
                    c.addMessage(input);
                    //Send this added message to all the users in this chatroom
                    for (int n = 0; n < c.users.size(); n++) {
                        User u = c.users.get(n);
                        u.send("Chatroom" + c.getName() + ":" + input);
                    }
                }
            }

        }catch (IOException e) {
        }
    }
}

Chatroom.java

public class Chatroom {
    private String name;        //Name of the chatroom
    protected LinkedList<String> messages;  //List of text messages that have been sent by users to the chatroom and are displayed in the chatroom
    protected long dateLastUsed;        //The last time the chatroom was joined or had a message sent to it
    protected LinkedList<User> users;   //The clients/users that are currently in the chatroom

    /*
     * Chatroom constructor
     * @param name The name of the chatroom, as determined by the user creating it
     */
    public Chatroom(String name) {
        dateLastUsed = System.currentTimeMillis() / 1000;       //Sent the time that the chatroom was used last to the current UNIX Epoch time
        messages = new LinkedList<String>();
        this.name = name;
    }

    /* 
     * Adds a message into the chatroom
     * @param message The message to be added to the chatroom
     */
    protected void addMessage(String message) {
        messages.add(message);
        dateLastUsed = System.currentTimeMillis() / 1000;
    }

    /*
     * Returns the name of the chatroom
     * @return String equal to the name of the chatroom
     */
    protected String getName() {
        return this.name;
    }

}

1 Ответ

0 голосов
/ 25 октября 2018

Прежде всего, нет вызова createUser() с кодом для принятия подключения к сокету.

Далее этот код в функции run(),

try {
            Scanner reader = new Scanner(System.in);
            input = iStream.readUTF();
            String userInput;//Check if there is input from the user
            while (input != null) {
                input = iStream.readUTF();
                System.out.println(input);
                userInput = reader.next();
                oStream.writeUTF(userInput);
}

Как только сокет принят, сервер печатает Enter a name, который является сохраненным вводом, внутри цикла while происходит еще один вызов readUTF().

Проблема с вызовом readUTF() заключается в том, что он блокируется, т.е.если с сервера не поступил вызов writeUTF(), он ожидает данные.

Я решил проблему с помощью следующего фрагмента:

try {
            Scanner reader = new Scanner(System.in);
            String userInput;//Check if there is input from the user
            do {
                input = iStream.readUTF();
                System.out.println(input);
                userInput = reader.next();
                oStream.writeUTF(userInput);
            } while (input != null);
            reader.close();
        }

Даже это не оптимальное решение.поскольку серверу нужно было бы каждый раз что-то записывать в поток.

Другим решением было бы чтение и запись с использованием различных потоков, чтобы мы могли создавать полнодуплексный режим, такой как чат, в отличие от этого полудуплексного..

Затем были некоторые NPE из-за отсутствия инициализации chatRooms LinkedList,

Плюс некоторые логические ошибки, такие как не добавление chatRooms в свой список.

Неправильный код:

protected Chatroom createChatRoom(String roomName) {
        Chatroom room = new Chatroom(roomName);
        return room;
    }

Исправленный код:

protected Chatroom createChatRoom(String roomName) {
        Chatroom room = new Chatroom(roomName);
        this.chatRooms.add(room);
        return room;
    } 

Лучший способ устранить все ошибки - это Github и несколько участников: p

...