简体   繁体   English

Java Socket BufferReader.readline获取null

[英]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. 我是Java的新手,我尝试用TCP Socket编写一个简单的客户端服务器,但是经过几天的努力我遇到了麻烦,但我无法解决此问题。

I got null with BufferReader.Readline(); 我的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 我的客户端使用JFrame调用面板,并使用文本字段和jbutton将消息发送到服务器

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 但是,当我发送一条消息时,服务器可以接收到该消息并将其打印到命令行,但是它继续尝试从客户端获取消息(因为它在while循环内),但是接收到null,在这种情况下我不知道

my CLient code: 我的客户代码:

JFrame Code: JFrame代码:

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: 第39行是:

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. 这导致在套接字的另一端(您的服务器),当您询问下一行时,BufferedReader返回null。 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. 因此,要解决此问题,请确保您的客户端编写了quit-message,这将使服务器在适当的时候关闭套接字并停止从中读取信息。 And to be very sure, add a server-side check of the returned String if it is null. 并且非常确定的是,如果返回的String为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. 确保不要在finally块中关闭套接字。 Only close it when you send the quit-message. 仅在发送退出消息时将其关闭。


Tip : You can construct the PrintStream in a auto-flush mode: 提示 :您可以在自动刷新模式下构造PrintStream:

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

When enabling auto-flush, it flushes after each print(ln) statement. 启用自动刷新时,它将在每个print(ln)语句之后刷新。 So you don't have to call each time flush() . 因此,您不必每次都调用flush()

When BufferedReader.readLine() returns null, that means there's no more data to read. BufferedReader.readLine()返回null时,这意味着没有更多数据可读取。 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. 当然, null不是对象, null.equals(anything)将引发异常。

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. 至于客户端...关闭套接字给您的流(就像您在jButton1ActionPerformed所做的一样),也将关闭套接字。 You'll probably want to make your topmost streams member fields somewhere in your client, so you can hold onto them between calls. 您可能希望将最顶级的流成员字段设置为客户端中的某个位置,以便可以在两次调用之间保留它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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