Java параметры личного сообщения мультиклиентного сервера чата - PullRequest
2 голосов
/ 29 мая 2020

Я новичок в stackoverflow, и мне очень жаль, если подобный вопрос задают раньше, но я провел быстрый поиск и не смог найти ни одного заголовка, подобного моему. Я работаю над мультиклиентским приложением чата на Java. Я следил за обучающими материалами и могу отправлять сообщения, которые видит каждый пользователь в приложении. Но мне интересно, как создать и отправить личное сообщение пользователю spesifi c в чат.

import java.io.*;
import java.net.*;
import java.util.HashSet;
import java.util.Set;

public class ChatServer {
    private int port;

    private Set<String> userNames = new HashSet<>();
    private Set<UserThread> userThreads = new HashSet<>();

    public ChatServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) {
        new ChatServer(9999).execute();
    }

    private void execute() {
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("Server is running");
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("New user connected");
                UserThread newUser = new UserThread(socket, this);
                userThreads.add(newUser);
                newUser.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void addUserName(String s) {
        this.userNames.add(s);
    }

    public void broadcast(String serverMessage, UserThread excludeUser) {
        for (UserThread aUser : userThreads) {
            if (aUser != excludeUser)
                aUser.sendMessage(serverMessage);
        }
    }
}

Приведенный выше код - это мой серверный код.

public void run() {
    Console console = System.console();
    String userName = console.readLine("Enter your username : ");
    writer.println(userName);
    String text;
    do {
        text = console.readLine("[" + userName + "]: ");
        if (text.startsWith("[")) {
            isTargeted = true;
            this.aimUserName = text.substring(text.indexOf("[") + 1, text.indexOf("]"));
            //System.out.println("Private Message to: " + aimUserName);
        } else {
            isTargeted = false;
        }
        writer.println(text);
    } while (!text.equals("bye"));

    try {
        socket.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

, и этот код выше является частью моего класса потока записи. Как видите, если сообщение начинается с части «[имя]», «имя» означает пользователя, которому мы хотим отправить личное сообщение. Таким образом я могу получить имя пользователя, которому хочу отправить личное сообщение, но я не мог понять, как передать это сообщение только этому пользователю spesifi c. Я считаю, что мне нужно настроить функцию трансляции в классе ChatServer, но я действительно не знаю, как это сделать. Какие шаги мне следует выполнить?

- Изменить -

Я работал над своим вопросом и сделал некоторые дополнения для решения моей проблемы. Прежде всего, я думаю, что должен поделиться с вами всем, что у меня есть. Ранее я поделился своим классом ChatServer. Другие классы, которые у меня есть:

import java.io.IOException;
import java.net.Socket;

public class ChatClient {

    public static void main(String[] args) {
        new ChatClient().execute();
    }

    private void execute() {
        try {
            Socket socket = new Socket("localhost", 3);
            System.out.println("Connected to chat server");
            new ReadThread(socket, this).start();
            new WriteThread(socket, this).start();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

import java.net.*;
import java.io.*;

public class ReadThread extends Thread{
    private BufferedReader reader;
    private Socket socket;
    private ChatClient client;
    public ReadThread(Socket socket, ChatClient client) {
        this.socket = socket;
        this.client = client;

        InputStream input;
        try {
            input = this.socket.getInputStream();
            this.reader = new BufferedReader(new InputStreamReader(input));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public void run() {
        while(true) {
            try {
                String response = this.reader.readLine();
                System.out.println("\n" + response);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                break;
            }
        }
    }
}

import java.net.Socket;
import java.io.*;
public class UserThread extends Thread {

    private Socket socket;
    private ChatServer server;
    PrintWriter writer = null;
    public String userName;
    public UserThread(Socket socket, ChatServer chatServer) {
        this.socket = socket;
        this.server = chatServer;
    }


    public void run() {
        try {
            InputStream input = socket.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(input));
            OutputStream output = socket.getOutputStream();
            writer = new PrintWriter(output,true);

            String userName = reader.readLine();
            this.userName = userName;
            server.addUserName(userName);
            String serverMessage = "New user connected: " + userName;
            server.broadcast(serverMessage,this);



            String clientMessage;
            do {
                clientMessage = reader.readLine();
                serverMessage = "[" + userName + "] : " + clientMessage;
                server.broadcast(serverMessage, this);      

            }while(!clientMessage.equals("bye"));



        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    public void sendMessage(String serverMessage) {
        writer.println(serverMessage);
    }


}

import java.net.*;
import java.io.*;
public class WriteThread extends Thread {
    private Socket socket;
    private ChatClient client;
    private PrintWriter writer;
    public WriteThread(Socket socket, ChatClient client) {
        this.socket = socket;
        this.client = client;
        OutputStream output;
        try {
            output = socket.getOutputStream();
            this.writer = new PrintWriter(output, true);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public void run() {
        Console console = System.console();
        String userName = console.readLine("Enter your username : ");
        writer.println(userName);
        String text;
        do {
            text = console.readLine("[" + userName + "]: ");
            if(text.startsWith("[")){
                String aimUserName = text.substring(text.indexOf("[")+1,text.indexOf("]"));
                System.out.println("Private Message to: " + aimUserName);}
            writer.println(text);
        }while(!text.equals("bye"));

        /*do {
            text = console.readLine("[" + userName + "]: ");
            writer.println(text);
        }while(!text.equals("bye"));*/

        try {
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


}

Эти коды работают правильно, и я могу очень аккуратно общаться в мульти-чате. Но во время работы над личным чатом я добавил в ChatServer строку:

public void privatebr(String serverMessage, String targetUserName){
        for(UserThread aUser: userThreads){
            if(aUser.userName == targetUserName)
                aUser.sendMessage(serverMessage);
        }

в UserThread, я отредактировал часть как:

String clientMessage;
            do {
                clientMessage = reader.readLine();
                serverMessage = "[" + userName + "] : " + clientMessage;
                if(clientMessage.startsWith("[")){
                    String targetUserName = clientMessage.substring(clientMessage.indexOf("[")+1,clientMessage.indexOf("]"));
                    serverMessage = "[" + userName + "] : " + clientMessage;
                    server.privatebr(serverMessage, targetUserName);
                }else{

                    server.broadcast(serverMessage, this);
                }


            }while(!clientMessage.equals("bye"));

Но когда я сделал все эти правки нарушили нормальный ход мульти-чата, в чем моя вина? Почему все сломалось?

1 Ответ

1 голос
/ 29 мая 2020

Хороший вопрос! Чтобы ответить на вопрос, который вы задали, вы должны поддерживать Map пользователей для их соединений с сокетами, так что с помощью DM вы можете просто выбрать пользователя (ов), которому вы хотите отправить сообщение. Для этого вам также понадобится протокол обмена сообщениями (см. Ниже)

... Но я должен сказать вам, что использование классов Sockets и SocketServer в наши дни и в наши дни похоже на изобретение колеса заново. Лучше всего начать с чат-сервера с помощью протокола веб-сокетов. Даже в этом случае вы, вероятно, захотите определить протокол сообщений (как это сделал я - я создал протокол обмена сообщениями, используя JSON и типы сообщений, где строковое сообщение в событии websocket onMessage сначала анализируется на объект)

Существуют реализации для поддержки WS на всех платформах: java,. net, python, php et c. Это должно быть вашей отправной точкой.

--- Обновление ---

Я понимаю, откуда вы. Чтобы помочь вам понять Sockets / ServerSockets, вот несколько указателей и ресурсов

  1. DatagramSockets (также известный как UDP): это другой протокол передачи, чем обычный TCP, используемый Shockwave, а затем Fla sh, и это основная причина того, что Fla sh проблематичен c. Я настоятельно рекомендую не использовать этот
  2. Data & Object Input / OutputStreams: потоки «данных» - это только Java (не могут подключаться к технологиям, построенным на других платформах). Потоки объектов аналогичны, за исключением того, что вы транспортируете через поток фактические целые объекты (также * только Java). Никто * (почти никто) их больше не использует.
  3. SocketException: Использование java. net . [Server] Socket (s), вы можете столкнуться с этим исключением. Это происходит, когда вы ждете дополнительных данных (через вызов read / readLine) в сокете, и сокет закрывается. Мне потребовалось много времени, чтобы понять это, но ЭТО ИСКЛЮЧЕНИЕ - ВАШ ДРУГ! Вы получаете его, когда соединение закрывается (на стороне клиента или сервера). Это позволяет потоку, который ждал сокета, пробудиться, и позволяет вам выполнять любую очистку, которая вам нужна. SocketException - это подкласс IOException, поэтому вы можете даже не осознавать, что это такое. Но теперь, по крайней мере, я предупреждал вас:
  4. Потоки против писателей и читателей: писатели и читатели предназначены для интерпретации необработанных байтов как Java символов и строк. Это необходимо, поскольку существует несколько текстовых форматов (например, ascii, windows -xx, utf-8, utf-16). Читатели и писатели помогают вам читать и писать текст в различных текстовых форматах (а также интерпретировать изображения из графических форматов).
  5. Буферизованные писатели и потоки: они предназначены для НЕЭФФЕКТИВНОГО чтения и записи. Для письма это означает, что вы можете написать часть сообщения и не отправлять его, пока вы не будете готовы. Для чтения это означает чтение потоков построчно, например, а не чтение всего сразу go.
  6. TUS: tjacobs / io - https://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/io/ это старая коллекция Java библиотек Я поставил SourceForge лет go, но многие классы здесь относятся к работе с сокетами. В частности, см. SocketServerEx, DataFetcher, Main / App, Timeout и, возможно, IOUtils. И из всего, действительно посмотрите на DataFetcher, который представляет собой легкую многопоточную структуру для прослушивания ввода-вывода обратного вызова.

Удачи и получайте удовольствие!

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