2014-02-11 53 views
3

我想寫一個簡單的控制檯程序,允許我發送和接收字符串消息。我遇到的問題是,我不知道如何同時運行接收代碼和發送代碼。如何同時運行這兩個循環? (Java)

個別地,類正在工作。我可以接收數據包併發送數據包,但是讓它們一次運行似乎對我來說是不可能的。

我研究過多線程,但由於我的知識仍然非常基礎,我似乎無法理解它是如何工作的。

這是我目前使用的代碼。我自己編寫了Dialog類,並在互聯網上找到了另外兩個類。

Dialog類:

import java.util.Scanner; 


public class Dialog { 

Scanner scanner = new Scanner(System.in); 
User user = new User(); 
Network net = new Network(); 

ThreadReceive tr = new ThreadReceive(); 
ThreadSend ts = new ThreadSend(); 


public void run() { 

    System.out.println("WELCOME"); 

    System.out.print("Port: "); 
    while(!user.setPort(giveInput())) { 
     System.out.println("Enter a valid port."); 
    } 

    System.out.print("IP: "); 
    user.setIP(giveInput()); 

    System.out.println(); 
    System.out.println("--- CONVERSATION STARTED ---"); 

    tr.receive(user.getIP(), user.getPort()); // Starts receiving loop (within ThreadReceive class). 

    while (true) { // Starts sending loop. 
     ts.sendMessage(giveInput(), user.getIP(), user.getPort()); // Sends packet when input is given. 
    } 

} 


private String giveInput() { 

    String input = scanner.nextLine(); 
    return input; 

} 

} 

接收類:

import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.InetAddress; 

public class ThreadReceive extends Thread { 

public void receive(String ip, int port) { 

    try { 

     // Create a socket to listen on the port. 
     DatagramSocket dsocket = new DatagramSocket(port); 

     // Create a buffer to read datagrams into. If a 
     // packet is larger than this buffer, the 
     // excess will simply be discarded! 
     byte[] buffer = new byte[2048]; 

     // Create a packet to receive data into the buffer 
     DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 

     // Now loop forever, waiting to receive packets and printing them. 
     while (true) { 
      // Wait to receive a datagram 
      dsocket.receive(packet); 

      // Convert the contents to a string, and display them 
      String msg = new String(buffer, 0, packet.getLength()); 
      System.out.println(packet.getAddress().getHostName() + ": " + msg); 

      // Reset the length of the packet before reusing it. 
      packet.setLength(buffer.length); 
     } 

    } 

    catch (Exception e) { 
     System.err.println(e); 
    } 

} 

} 

發送類:

import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.InetAddress; 


public class ThreadSend extends Thread { 

public void sendMessage(String message, String ip, int port) { 

     try { 
      byte[] data = message.getBytes(); 

      InetAddress address = InetAddress.getByName(ip); 

      DatagramPacket packet = new DatagramPacket(data, data.length, address, port); 

      DatagramSocket datagramSocket = new DatagramSocket(); 
      datagramSocket.send(packet); 
     } 

     catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 

此外,有沒有什麼辦法來測試,如果我可以接收數據包?我一直在和一位朋友一起測試它,但自己做起來會更方便。

謝謝!

+4

難道你只是讓兩個程序互相交談,而不是試圖在一個? – doctorlove

+0

嗯,我想將代碼發送給我的朋友,看看是否可以通過控制檯聊天。這意味着它需要監聽數據包並允許同時發送數據包。 – Daan

+1

與問題無關的注意事項:考慮使用Executors/ThreadFactory而不是創建Thread的子類:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html – Puce

回答

0

您沒有正確使用線程。

邏輯應該在run方法中。

我建議你使用queue如ArrayBlockingQueue來傳遞參數給你的線程。例如,你可以有將元素添加到這個隊列

public void addMessage(String message) { 
    synchronized(inputQueue) { 
      inputQueue.offer(r); 
      inputQueue.notify(); 
    } 
} 

和運行方法將使用這些元素作爲這樣的方法:

public void run() { 
     try { 
      while(!running) 
        synchronized (inputQueue) { 
         inputQueue.wait(); // you can have a timeout also... 
          String message = this.inputQueue.poll(); 
           // use the message item.... 
           // in your case send it to the other user. 
         } 
        }  
       } 
     } catch (Exception e) { 
      /////// your exception handler 
     } 
} 

而且記住開始你的線程:

Thread t = new MyThread(); 
t.start(); /// Start the thread !!! 

PS:消息可以是任何對象這裏使用的字符串,因爲我基於這個我的一些代碼,我使用的是

Queue<String> 
+0

好的,所以我首先初始化了兩個線程。我不明白如何將參數傳遞給run()方法。 – Daan

+0

對不起,我忘了queue.wait()。編輯 –

+0

線程一旦啓動,它就會等待inputQueue被通知。一旦你調用了addMessage,它就會通知在inputQueue上等待的線程,因此線程恢復並開始處理隊列。一旦完成,就像在while循環中一樣,它會再次等待inputQueue上的通知。 –

0

檢查Beej的網絡編程指南:http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html - 這會給你更多的例子來看看。就測試而言,您可以設置虛擬機或使用您擁有的另一臺計算機。當我必須在學校學習網絡時,我們會回到兩個獨立的Linux機器來測試我們的代碼。

編輯:也要確保您正確接收您可以使發件人和接收方都打印出他們收到的數據包數據。或者你可以讓他們打印一個簡單的字符串來表示數據包已收到。

如果您想要連續流,您也可能想要檢查TCP而不是UDP。 UDP只是創建一個數據報包並將其發送到網絡上,而TCP會在兩個主機之間創建一個持久連接。

+0

對於UDP和TCP,您可以閱讀:http://www.diffen.com/difference/TCP_vs_UDP它基本上是關於速度與可靠性的關係。 –

+0

@LaurentB好的補充。絕對要考慮如果你選擇看TCP。 –