Search code examples
javasocketsclient-server

java.net.SocketException while trying to send message with BufferedWriter


I am trying to make a simple client/server application using Socket, BufferedReader and BufferedWriter. Authorization works good, and when i am sending first message everything also works, but when i am trying to send second message i catch the exception:

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: java.net.SocketException: Канал обірвано
    at utils.SocketManager.writeMsg(SocketManager.java:33)
    at client.Chat.sendMessage(Chat.java:53)
    at client.Chat.lambda$new$0(Chat.java:37)
    at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1972)
    at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2314)
    at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:407)
    at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
    at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279)
    at java.desktop/java.awt.Component.processMouseEvent(Component.java:6620)
    at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3398)
    at java.desktop/java.awt.Component.processEvent(Component.java:6385)
    at java.desktop/java.awt.Container.processEvent(Container.java:2266)
    at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4995)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4827)
    at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4948)
    at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4575)
    at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4516)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310)
    at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4827)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:98)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.net.SocketException: Канал обірвано
    at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:413)
    at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:433)
    at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:812)
    at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1120)
    at java.base/sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:313)
    at java.base/sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:409)
    at java.base/sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:414)
    at java.base/sun.nio.cs.StreamEncoder.lockedFlush(StreamEncoder.java:218)
    at java.base/sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:205)
    at java.base/java.io.OutputStreamWriter.flush(OutputStreamWriter.java:263)
    at java.base/java.io.BufferedWriter.implFlush(BufferedWriter.java:372)
    at java.base/java.io.BufferedWriter.flush(BufferedWriter.java:359)
    at utils.SocketManager.writeMsg(SocketManager.java:31)
    ... 37 more

Here is piece of server code:

private static void handleClient(Socket socket){
                try (BufferedWriter writer = new BufferedWriter(
                        new OutputStreamWriter(
                                socket.getOutputStream()));
                     BufferedReader reader = new BufferedReader(
                             new InputStreamReader(
                                     socket.getInputStream()))) {
        
                    String command = "";
                    while(!command.equals("Exit")) {//here starts endless loop
                        if (reader.ready()) {
                            command = reader.readLine();
                            switch (command) {
                                case "LogIn" -> logIn(writer, reader);
                                case "SendMsg" -> sendMsg(reader);
                                case "Exit" -> {
                                    clients.remove(socket);
                                    socket.close();
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
         private static void sendMsg(BufferedReader reader) throws IOException{
                String message = reader.readLine();
        
                for(Socket client : clients) {
                    try(BufferedWriter writer = new BufferedWriter(
                            new OutputStreamWriter(
                                    client.getOutputStream()))) {
                        writer.write(message);
                        writer.newLine();
                        writer.flush();
                    }
                }
            }

Client:

public Chat(String login) {
        this.login = login;

        Thread thread = new Thread(new ReceiveMessage());
        thread.start();

        sendButton.addActionListener(e -> sendMessage());
    }

    public void openFrame() {
        frame = new JFrame("YurChat");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.setContentPane(mainPanel);

        Toolkit toolkit = Toolkit.getDefaultToolkit();
        frame.setBounds(toolkit.getScreenSize().width / 2 - 325, toolkit.getScreenSize().height / 2 - 200, 550, 300);
    }

    private void sendMessage() {
        SocketManager.writeMsg("SendMsg");//server does not get command second time
        String message = login + ":\t" + messageTextField.getText();
        SocketManager.writeMsg(message);//throws exception
        messageTextField.setText("");
    }

    private class ReceiveMessage implements Runnable {
        @Override
        public void run() {
            while(true) {
                if(SocketManager.isReaderReady()) {
                    String msg = SocketManager.readMsg();
                    chatTextArea.append(msg);
                }
            }
        }
    }
}

SocketManager:

public final class SocketManager {
    private static final Socket socket;
    private static final BufferedWriter writer;
    private static final BufferedReader reader;

    static {
        try {
            socket = new Socket(
                    PropertiesUtil.getProperty("socket.ip"),
                    Integer.parseInt(PropertiesUtil.getProperty("socket.port")));
            writer = new BufferedWriter(
                    new OutputStreamWriter(
                            socket.getOutputStream()));
            reader = new BufferedReader(
                    new InputStreamReader(
                            socket.getInputStream()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void writeMsg(String message) {
        try {
            writer.write(message);
            writer.newLine();
            writer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static String readMsg() {
        try {
            return reader.readLine();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static boolean isReaderReady() {
        try {
            return reader.ready();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void close() {
        try {
            writer.close();
            reader.close();
            socket.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

Full code is here: https://github.com/lucifer116664/ClientServerChat.git

I debugged this app and found that when i am sending message second time client is sending command "SendMsg", but server does not get it and stops in the endless loop waiting for command.

Thanks in advice.


Solution

  • Thanks to Mark Rotteveel i got the answer. I just modified sendMsg method by putting try with resources into if(client != socket) (sending message everyone besides client who wrote it) and everything works great.

        private static void sendMsg(Socket socket, BufferedReader reader) throws IOException{
                String message = reader.readLine();
        
                for(Socket client : clients) {
                    if(client != socket) {
                        try (BufferedWriter writer = new BufferedWriter(
                                new OutputStreamWriter(
                                        client.getOutputStream()))) {
                            writer.write(message);
                            writer.newLine();
                            writer.flush();
                        }
                    }
                }
            }