WedX - журнал о программировании и компьютерных науках

Java, как заставить сервер отправлять сообщение каждому подключенному клиенту

Я пытаюсь создать программу чата, в которой клиент отправляет сообщение на сервер, а затем сервер отправляет это сообщение всем подключенным клиентам для его отображения. Программа работает, но когда клиент отправляет сообщение, только он получает его обратно, а остальные подключенные клиенты ничего не получают.

код клиента:


public class Client {

    protected static JTextArea textArea = new JTextArea(20, 30);
    protected static String sendMSG, getMSG;

    public static void main(String[] args) throws IOException {
        String hostName = args[0];
        String Username = args[1];
        boolean sending = true;

        try (
            Socket socket = new Socket(hostName, 1010);
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        ) {
            BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));

            //frame setup
            JFrame frame = new JFrame("chat client");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            //text area
            JScrollPane scrollPane = new JScrollPane(textArea);

            //text field
            JTextField MSGText = new JTextField(5);

            //"send" button
            JButton sMSGB = new JButton("send");
            sMSGB.setPreferredSize(new Dimension(60, 30));
            sMSGB.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent event) {
                    sendMSG = MSGText.getText();
                    MSGText.setText("");
                    out.println("<" + Username + ">: " + sendMSG);
                }

            });

            //panel
            JPanel p = new JPanel();
            p.setLayout((new BoxLayout(p, BoxLayout.PAGE_AXIS)));
            p.add(Box.createVerticalStrut(5));
            p.add(scrollPane);
            p.add(Box.createVerticalStrut(5));
            p.add(MSGText);
            p.add(Box.createVerticalStrut(5));
            p.add(sMSGB);
            p.add(Box.createVerticalStrut(5));
            frame.getContentPane().add(p);

            //set frame visible
            frame.pack();
            frame.setVisible(true);

            System.out.println("<Client>: opened stream");

            while(sending) {
                while((getMSG = in.readLine()) != null) {
                    System.out.println(getMSG);
                    textArea.append(getMSG + "\n");
                }
            }
        } 
    }       
}   

код сервера:

public class Server {

    public static void main(String[] args) {
        boolean listening = true;
        try (ServerSocket serverSocket = new ServerSocket(1010)) {
            while(listening) {
                new ServerThread(serverSocket.accept()).start();
                System.out.println("opened thread");
            }

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

    }
}

Код потока сервера:

public class ServerThread extends Thread {

    private Socket socket = null;

    public ServerThread(Socket socket) {
        super("ServerThread");
        this.socket  = socket;
    }

    public void run() {
        try (
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        ) {
            System.out.println("stream opened");
            String getMSGs;

            while((getMSGs = in.readLine()) != null) {
                out.println(getMSGs);
                System.out.println("msg received and sent");
            }

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


}

Заранее спасибо.

28.08.2019

Ответы:


1

Очень простое решение — создать держатель PrintWriter, например список. Не забудьте создать закрытый механизм для этой коллекции! И подумайте о многопоточности.

public class ServerThread extends Thread {
    private final Socket socket;
    private final List<PrintWriter> outs;

    public ServerThread(Socket socket, List<PrintWriter> outs) {
        super("ServerThread");
        this.socket  = socket;
        this.outs = outs;
        System.out.println("Opened outs: " + outs.size());
    }

    private void sendToAll(String msg) throws IOException {
        for(PrintWriter out: outs) {
            out.println(msg);
        }
    }

    public void run() {
        try (
                PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        ) {
            System.out.println("stream opened");
            outs.add(out);
            String getMSGs;
            while((getMSGs = in.readLine()) != null) {
                System.out.println("msg received and sent " + getMSGs);
                sendToAll(getMSGs);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Если это большой проект, лучше создайте очередь для обмена сообщениями.

29.08.2019
  • любая реализация List, но лучше new CopyOnWriteArrayList<PrintWriter>() 29.08.2019
  • Вам нужно добавить один и тот же объект для каждого сокета. List<PrintWriter> outs = new CopyOnWriteArrayList<PrintWriter>(); ... new ServerThread(serverSocket.accept(), outs).start(); 29.08.2019
  • Новые материалы

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..


    Для любых предложений по сайту: [email protected]