2012-03-23 22 views
0

我是新來的java和我嘗試寫一個簡單的客戶端服務器與TCP套接字,但我有麻煩了一段日子後,與它鬥爭,我無法解決這個問題。Java Socket BufferReader.readline得到null

我得到null與BufferReader.Readline();

我的服務器代碼:

啓動服務器代碼

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(); 
    } 

} 

服務器線程:

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) { 
      } 
     } 
    } 




} 

我的客戶,我使用JFrame中調用一個面板,並使用文本字段的JButton要發送消息給服務器

但是,當我發送一條消息,服務器可以收到這messag e和打印出來,以命令行,但它繼續嘗試從客戶端獲取信息(因爲它的內部,而循環),但它接收空,我在這種情況下不知道

我的客戶端代碼:

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     
} 

我的小組代碼:

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     
} 

而且從服務器我的堆棧跟蹤:

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

線路是:

if(textFromClient.equals("Quit")) 

回答

1

BufferedReader.readLine()返回null,這意味着沒有更多的數據讀取。你在流的盡頭。 (一般用插座,這意味着另一端關閉連接。)

當然,null不是一個對象,null.equals(anything)會拋出一個異常。

你可以因爲任何一種情況意味着客戶端完成,連接應該終止又說什麼

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

避免例外。

至於客戶端...關閉一個Socket給你的流(如你在做的jButton1ActionPerformed),關閉Socket。您可能希望在客戶端的某個位置創建最上面的流成員字段,以便您可以在調用之間保持它們。

2

處理退出消息的想法很好。但是你的客戶永遠不會發送這樣的退出消息。它只是關閉了插座。這會導致套接字(您的服務器)的另一端在您詢問下一行時BufferedReader返回null。因此,要解決這個問題,請確保您的客戶端寫入退出消息,這將允許服務器在正確的時間關閉套接字並停止讀取它。並且要非常確定,如果返回的String爲空,請添加服務器端檢查。

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

編輯:這對於客戶端:

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

確保你不關閉套接字在finally塊。只有在您發送退出信息時才關閉它。


提示:您可以構建的PrintStream在自動刷新模式:

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

當啓用自動刷新,則每次打印(LN)聲明後刷新。所以你不必每次打電話flush()

+0

謝謝 但是當我做我的客戶線程打破,我不能發送新的文本到服務器,因爲在文本框時,文本框文本發送到服務器,我想送其他文本到服務器上,但我該怎麼辦? – Bronx 2012-03-24 02:07:04

+0

@Bronx:我編輯了答案。我認爲這應該起作用。 – 2012-03-24 08:12:49

+0

首先感謝您的幫助 但作爲您的解決方案上面,當服務器收到空這意味着客戶端不會發送任何東西到服務器,客戶端將斷開連接,但我不是這個意思,因爲在我的應用程序中,當客戶端連接到服務器,服務器將爲客戶端創建一個ID,並且我想用這個ID作爲其他方法,但客戶端對服務器沒有任何影響,並且在服務器disconect客戶端之後,當客戶端重新連接它時將獲得新的ID並且與第一次連接不同的客戶端,這將是可怕的,我的客戶端獲得新的ID :( – Bronx 2012-03-24 17:46:53