2013-12-17 157 views
0

我試圖通過線程發送消息。 dataAvailable是一個變量,它告訴消息是否在文本字段上可用。如果可用dataAvailable被設置爲true,並且在run()方法中,如果在執行代碼後爲true。但問題是在運行()它永遠不會看到dataAvailable是真實的,沒有發送。需要幫助。使用線程處理基於java的聊天應用程序

 
/* 

This is client 

*/ 
import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.net.Socket; 
import java.net.UnknownHostException; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 

public class PeerOne extends JFrame implements Runnable 
{ 
    private static final long serialVersionUID = 1L; 

    JTextField outgoing; 
    JTextArea incoming; 
    JButton send; 
    Thread t,t1; 
    ObjectOutputStream output; //for writing objects to a stream 
    ObjectInputStream input; //for reading objects from a stream 
    Socket s; 
    volatile boolean dataAvailable=false; 
    String message = null; 
    public PeerOne() 
    { 
     outgoing = new JTextField(); 
     outgoing.setEnabled(true); 
     outgoing.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       if(!(e.getActionCommand().isEmpty())) 
       { 
        dataAvailable = true; 
        System.out.print("hi"); 
       } 
      } 
     }); 

     this.add(outgoing,BorderLayout.SOUTH); 

     incoming = new JTextArea(); 
     incoming.setEditable(true); 
     this.add(new JScrollPane(incoming),BorderLayout.CENTER); 
     this.add(incoming); 

     setSize(300,150); 
     setVisible(true); 

     try 
     { 
      s = new Socket("localhost",5500); 
      incoming.append("Connection Successfull..."+"\n"); 

      output = new ObjectOutputStream(s.getOutputStream()); 
      output.flush(); 
      input = new ObjectInputStream(s.getInputStream()); 

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

     t = new Thread(this,"PeerOne"); 
     System.out.print("New Thread"); 
     //t1 = new Thread(this,"Two"); 
     t.start(); 
    } 

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

    public void run() 
    { 
     while(true) 
     { 
      if(dataAvailable==true) 
      { 
       try 
       { 
        System.out.print(0); 
        output.writeObject(outgoing.getText()); 
        output.flush(); 
        dataAvailable = false; 
       } 
       catch (IOException e1) 
       { 
        e1.printStackTrace(); 
       } 
      } 
      try 
      { 
       try 
       { 
        message = (String)input.readObject(); 

        incoming.append(message); 
       } 
       catch (ClassNotFoundException e) 
       { 
        e.printStackTrace(); 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
      }  
     } 

    } 
} 

 
/* 

This is server 

*/ 
import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.BufferedInputStream; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.PrintStream; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.net.UnknownHostException; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 

public class PeerTwo extends JFrame implements Runnable 
{ 
    private static final long serialVersionUID = 1L; 
    JTextField outgoing; 
    JTextArea incoming; 
    JButton send; 
    Thread t; 
    Socket s; 
    ObjectOutputStream output; //for writing objects to a stream 
    ObjectInputStream input; //for reading objects from a stream 
    volatile boolean dataAvailable=false; 
    String message = null; 

    public PeerTwo() 
    { 
     outgoing = new JTextField(); 
     outgoing.setEnabled(true); 
     outgoing.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       if(!(e.getActionCommand().isEmpty())) 
       { 
        dataAvailable = true; 
       } 
      } 
     }); 

     this.add(outgoing,BorderLayout.SOUTH); 

     incoming = new JTextArea(); 
     incoming.setEditable(true); 
     this.add(new JScrollPane(incoming),BorderLayout.CENTER); 
     this.add(incoming); 

     setSize(300,150); 
     setVisible(true); 
     try 
     { 
      ServerSocket ss = new ServerSocket(5500,100); 
      s = ss.accept(); 

      output = new ObjectOutputStream(s.getOutputStream()); 
      output.flush(); 
      input = new ObjectInputStream(s.getInputStream()); 
     } 
     catch (UnknownHostException e) 
     { 
      e.printStackTrace(); 
     } 
     catch (IOException e) 
     { 
      e.printStackTrace(); 
     } 

     t = new Thread(this,"PeerTwo"); 
     System.out.print("New Thread"); 
     t.start(); 



    } 

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

    public void run() 
    { 
      while(true) 
      { 
       if(dataAvailable==true) 
       { 
        try 
        { 
         System.out.print("bbb"); 
         output.writeObject(outgoing.getText()); 
         output.flush(); 
         dataAvailable = false; 
        } 
        catch (IOException e1) 
        { 
         e1.printStackTrace(); 
        } 
       } 
       try { 
         try 
         { 
          message = (String)input.readObject(); 
          System.out.print(0); 
          incoming.append(message); 
         } 
         catch (ClassNotFoundException e) 
         { 
          e.printStackTrace(); 
         } 
       } catch (IOException e) { 
        e.printStackTrace(); 
       }  
      } 
     } 
} 

+0

你有兩個dataAvailable變量在不同的類中,因此不共享;設置一個不會設置另一個。 – pjc50

+0

dataAvailable用於限制寫入輸出流,但讀取消息的代碼不受任何條件語句限制。當PeerOne中的dataAvailable爲true時,run()應該能夠讀取dataAvailable爲true併發送msg,但它不是和如果我寫條件爲dataAvailable ==虛假它發送消息 – 2013-12-17 18:16:52

+0

你不試圖在不同的帳戶下提出這個問題嗎? –

回答

0

此代碼有幾個bug /問題:

  1. 無限循環。你的代碼浪費處理器時間。我建議使用guarded block進行寫入程序或至少睡眠。
  2. 閱讀被封鎖。代碼沒有從輸入流中檢查。
  3. 使用外部鞦韆部件EDT
  4. 當您關閉應用程序窗口時,應用程序仍然有效。 (使用this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);)

所以,我想建議修補程序。它會使你的代碼工作。 PeerOne(客戶端):

public void run() { 
     while (true) { 
      if (dataAvailable == true) { 
       try { 
        System.out.print(0); 
        output.writeUTF(outgoing.getText()); 
        output.flush(); 
        dataAvailable = false; 
       } catch (IOException e1) { 
        e1.printStackTrace(); 
       } 
      } 
      try { 
       if (input.available() > 0) { 
        message = input.readUTF(); 
        SwingUtilities.invokeLater(new Runnable() { 
         @Override 
         public void run() { 
          incoming.append(message); 
          incoming.append("\n"); 
         } 
        }); 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      try { 
       TimeUnit.MILLISECONDS.sleep(300); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

PeerTwo(服務器):

public void run() { 
    while (true) { 
     if (dataAvailable == true) { 
      try { 
       System.out.print("bbb"); 
       output.writeUTF(outgoing.getText()); 
       output.flush(); 
       dataAvailable = false; 
      } catch (IOException e1) { 
       e1.printStackTrace(); 
      } 
     } 
     try { 
      if (input.available() > 0) { 
       message = input.readUTF(); 
       System.out.print(0); 
       SwingUtilities.invokeLater(new Runnable() { 
        @Override 
        public void run() { 
         incoming.append(message); 
         incoming.append("\n"); 
        } 
       }); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     try { 
      TimeUnit.MILLISECONDS.sleep(300); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

因此,大家可以我固定1-3的問題和使用的readUTF/writeUTF代替的readObject /的writeObject來簡化代碼。下一步是分割讀/寫2個單線程。你可以自己做。

+0

不打算申請生產,但歡迎提出建議。很好地指出了一個接一個的問題。 – user101285