简体   繁体   中英

Java Socket BufferReader.readline get null

I'm new in java and i try to write a simple client server with TCP Socket but i got trouble after some days struggle with it, i haven't able to solve this issue.

I got null with BufferReader.Readline();

MY server code:

Start Server Code

public class StartServer {
    ServerSocket server;
    public StartServer(){
        try {
            server = new ServerSocket(4444);
        } catch (Exception e) {
            System.out.println("server can't listen to this port");
        }
         System.out.println("Listening for clients on 4444..."); 
        int id =0;
        while(true)
        {
            try {
                Socket client = server.accept();
                ServerThread svThread = new ServerThread(client, id++);
                svThread.start();
            } catch (Exception e) {
                System.out.println("Error.......");
            }
        }
    }

    public static void main(String[] args) {
        new StartServer();
    }

}

Server Thread:

public class ServerThread extends Thread{
    Socket client;
    int clientID = 0;
    boolean threadRun = true;
    BufferedReader inputFromClient = null;
    PrintWriter outputFromServer = null;

    public ServerThread(Socket socket, int cID) {
        client = socket;
        clientID = cID;
    }


    public void run() {
        try {
            inputFromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
            outputFromServer  = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
            System.out.println("ClientID: " + clientID);

            while(threadRun){
                String textFromClient = inputFromClient.readLine();
                System.out.println("Client ID: " + clientID + " Client says: " + textFromClient);

                if(textFromClient.equals("Quit")){
                    threadRun = false;
                    System.out.println("Stop client Thread from: " + clientID);
                }else{
                    outputFromServer.print(textFromClient);
                    outputFromServer.flush();
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            try {
                inputFromClient.close();
                outputFromServer.close();
                client.close();
                System.out.println("Server Stopped...");
            } catch (Exception e) {
            }
        }
    }




}

My client i use JFrame call a Panel and use text field and jbutton to send message to server

But when i send one message, server can receive this message and print it out to command line but it continue try to get message from client (because it inside while loop) but it receive null, i have no idea in this situation

my CLient code:

JFrame Code:

public class NewJFrame extends javax.swing.JFrame {

    /**
     * Creates new form NewJFrame
     */

    Panel1 p ;
    public NewJFrame() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jDesktopPane1 = new javax.swing.JDesktopPane();
        jPanel1 = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jButton1.setText("jButton1");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                .addContainerGap(196, Short.MAX_VALUE)
                .addComponent(jButton1)
                .addGap(91, 91, 91))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(83, 83, 83)
                .addComponent(jButton1)
                .addContainerGap(134, Short.MAX_VALUE))
        );

        jPanel1.setBounds(0, 0, 360, 240);
        jDesktopPane1.add(jPanel1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jDesktopPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 365, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 35, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jDesktopPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 265, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 35, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        // TODO add your handling code here:
        p   = new Panel1();
        jDesktopPane1.removeAll();
        jDesktopPane1.repaint();
        jDesktopPane1.revalidate();
         p.setBounds(0, 0, 840, 558);
        p.setSize(840,558);
        jDesktopPane1.add(p);
        p.show();

    }                                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /*
         * Set the Nimbus look and feel
         */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel. For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /*
         * Create and display the form
         */
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new NewJFrame().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JDesktopPane jDesktopPane1;
    private javax.swing.JPanel jPanel1;
    // End of variables declaration                   
}

My Panel code:

public class Panel1 extends javax.swing.JPanel {
 Socket s;
 PrintWriter outPut = null;
    /**
     * Creates new form Panel1
     */
    public Panel1() {
        initComponents();
        ConnectServer();
       //sendToServer();
       // receiveFromServer();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */

    public void ConnectServer(){
        try {
             s = new Socket("localhost", 4444);
             System.out.println("Connect to server");
             outPut = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
           //  PrintWriter outPut = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
            //outPut.println("Test cai coi.....");
            //outPut.flush();
        } catch (UnknownHostException ex) {
            Logger.getLogger(Panel1.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Panel1.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void receiveFromServer(){
        try {
            BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
            System.out.println(input.readLine());
        } catch (IOException ex) {
            Logger.getLogger(Panel1.class.getName()).log(Level.SEVERE, null, ex);
        }

    }


    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jTextField1 = new javax.swing.JTextField();
        jButton1 = new javax.swing.JButton();

        jButton1.setText("jButton1");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(26, 26, 26)
                .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton1)
                .addContainerGap(157, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(34, 34, 34)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jButton1))
                .addContainerGap(243, Short.MAX_VALUE))
        );
    }// </editor-fold>                        

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
       //PrintWriter outPut = null;
        PrintWriter outToServer = null;
         BufferedReader input = null;
        try {
            // TODO add your handling code here:
            outToServer  = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));

            String txtFromClient = jTextField1.getText();
           // String clientText = input.readLine();
            System.out.println(txtFromClient);
            outToServer.println(txtFromClient);
            outToServer.flush();

            //





            //outPut.flush();
             //System.out.println(input.readLine());
        } catch (Exception ex) {
            Logger.getLogger(Panel1.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            //outPut.close();
             outToServer.close();
        }


    }                                        

    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JTextField jTextField1;
    // End of variables declaration                   
}

And my stacktrace from server:

Exception in thread "Thread-0" java.lang.NullPointerException
    at testserverclient.ServerThread.run(ServerThread.java:39)

Line 39 is:

if(textFromClient.equals("Quit"))

The idea of handling a quit message is good. But your client never sends such a quit-message. It simply closes the socket. This causes at the other side of the socket (your server) that the BufferedReader returns null when you ask the next line. So, to solve this, make sure your client writes the quit-message, which will allow the server to close the socket at the right moment and stop reading from it. And to be very sure, add a server-side check of the returned String if it is null.

if (textFromClient == null || textFromClient.equals("Quit"))
{
     socket.close();
     break; // Break out of the reading loop.
}

Edit : And this for the client side:

if (txtFromClient.equals("Quit"))
{
    outToServer.println("Quit");
    outToServer.flush();
    outToServer.close();
}

Make sure you don't close the socket in the finally block. Only close it when you send the quit-message.


Tip : You can construct the PrintStream in a auto-flush mode:

PrintStream outToServer = new PrintStream(socket.getOutputStream, true);

When enabling auto-flush, it flushes after each print(ln) statement. So you don't have to call each time flush() .

When BufferedReader.readLine() returns null, that means there's no more data to read. You're at the end of the stream. (Generally with sockets, that would mean the other end closed the connection.)

Of course, null not being an object, null.equals(anything) will throw an exception.

You can avoid the exception by saying something like

if (textFromClient == null || textFromClient.equals("Quit"))

since either condition means the client is done and the connection should be terminated.

As for the client...closing a stream given to you by a Socket (as you're doing in jButton1ActionPerformed ), closes the Socket as well. You'll probably want to make your topmost streams member fields somewhere in your client, so you can hold onto them between calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM