2017-06-20 70 views
-2

對於一個小型大學項目我必須編寫一個服務器和客戶端UDP通信。Java客戶端服務器UDP獲取錯誤的包

如果客戶端發送數據並且服務器只讀取,則一切正常。只要我開始從服務器發送數據到客戶端,我的小程序錯誤。

public class Sensors { 
private static List<Produkt> allSensors = new ArrayList<Produkt>(); 

public static void main(String[] args) throws Exception { 
    //Preparing Our Data 
    initSensors(); 
    //Server Config 
    String serverIP = new String(); 
    BufferedReader eingabe = new BufferedReader(new InputStreamReader(System.in)); 
    System.out.print("IP Eintragen:"); 
    serverIP = eingabe.readLine(); 
    System.out.println(""); 

    //Preparing Data to Send 

    try{ 
     DatagramSocket serverSocket = new DatagramSocket(1234); 
     byte[] receiveData = new byte[4]; 
     DatagramPacket receivePacket = new DatagramPacket(receiveData, 
         receiveData.length); 

     for(;;){ 

      //Sending 
      for (Produkt s : allSensors) { 
       ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
       ObjectOutputStream os = new ObjectOutputStream(outputStream); 
       os.writeObject(s); 
       byte[] sendData = outputStream.toByteArray(); 
       InetAddress ia = InetAddress.getByName(serverIP); 
       DatagramPacket sendPacket= new DatagramPacket(sendData,sendData.length,ia,1223); 
       serverSocket.send(sendPacket); 
       outputStream.close(); 
      } 
      for (Produkt s : allSensors) { 
       System.out.println(s); 
      } 
      //Empfangen 
      try{ 
      serverSocket.receive(receivePacket); 
      String sentence = new String(receivePacket.getData(), 0, 
          receivePacket.getLength()); 
      System.out.println("RECEIVED: " + sentence); 

      }catch(IOException e){ 

      } 
      Thread.sleep(1000); 
      reduceValue(); 
     } 

    }catch (IOException e) { 
      System.out.println(e); 
    } 



} 

static public void initSensors() { 

    allSensors.add(new Produkt("Äpfel", 0, 100, "")); 
    allSensors.add(new Produkt("Birnen", 0, 100, "")); 
    allSensors.add(new Produkt("Kiwis", 0, 100, "")); 
    allSensors.add(new Produkt("Bananen", 0, 100, "")); 
    for (Produkt s : allSensors) { 
     System.out.print(s.p_name + " : " + s.p_quant + "\n"); 
    } 
} 

static public void reduceValue() { 
    for (Produkt s : allSensors) { 
     if (s.p_quant > 0) { 
      s.p_quant -= 20; 
     } 
    } 

} 

static public void fillValue() { 
    for (Produkt s : allSensors) { 
     s.p_quant = 100; 
    } 
} 

}

public class Fridge extends Thread { 

private static int port; 
private static String htmlInsert = ""; 
private static DataShare ds; 

public Fridge(int port, DataShare ds) { 
    this.port = port; 
    this.ds = ds; 
} 

@Override 
public void run() { 

    System.out.println("Start Fridge Server"); 

    try { 
     handleRequest(); 
    } catch (Exception ex) { 
     Logger.getLogger(Fridge.class.getName()).log(Level.SEVERE, null, ex); 
    } 

} 

static public void handleRequest() throws Exception { 
    try{ 
     DatagramSocket serverSocket = new DatagramSocket(port); 
     byte[] recivingData = new byte[512]; 

     DatagramPacket receivePacket = new DatagramPacket(recivingData, recivingData.length); 


     for(;;) 
     { 
      if(!ds.produkte.isEmpty()){ 
       if(ds.produkte.get(0).p_quant == 0){ 
        ds.reOrder = true; 
       }else{ 
        ds.reOrder = false; 
       } 
      } 
      //Empfangen 
      serverSocket.receive(receivePacket); 
      //prepare Data for conversion into Produkt 
      recivingData = receivePacket.getData(); 
      ByteArrayInputStream in = new ByteArrayInputStream(recivingData); 
      ObjectInputStream is = new ObjectInputStream(in); 
      Produkt reveivedProdukt = (Produkt) is.readObject(); 
      //Decoding Produkt into DataShare 
      //System.out.println(reveivedProdukt); 
      decodeData(reveivedProdukt); 
      writeHTML(); 

      //Senden 
      String reorder = new String(); 
      if(ds.reOrder){ 
       reorder = "FILL"; 
      }else{ 
       reorder ="NOT"; 
      } 
      System.out.println(reorder); 
      byte[] sendingDate = reorder.getBytes("UTF-8"); 
      DatagramPacket sendingPacket = new DatagramPacket(sendingDate, sendingDate.length, 
        receivePacket.getAddress(),receivePacket.getPort()); 
      serverSocket.send(sendingPacket); 

     } 

    }catch(IOException e){ 
     System.out.println(e); 
    }catch(ClassNotFoundException e){ 
     e.printStackTrace(); 
    } 


} 

static public void writeHTML() throws Exception { 
    List<String> lines = new ArrayList<String>(Arrays.asList("<!DOCTYPE html>\n", 
      "<html>\n", 
      " <head>\n", 
      "  <meta charset=\"utf-8\">\n", 
      "  <title>Test</title>\n", 
      " </head>\n", 
      " <body>\n", 
      "\n", 
      "  <h1 style=\"color:red;\">Das ist ein Test</h1>\n", 
      "\n", 
      " </body>\n", 
      "</html>")); 
    htmlInsert += "<p>"; 
    for(Produkt p : ds.produkte){ 
     htmlInsert+= p.p_name +" Preis: " + p.p_price + " Shopname: "+ 
        p.shop_name + " Quantity: " + p.p_quant + "</br>"; 
    } 

    htmlInsert+= "</p></br>";    
    lines.add(6, htmlInsert); 

    /* WINDOWS Path file = Paths.get(".\\src\\HttpServer\\data.html");*/ 
    /* LINUX*/ Path file = Paths.get("/home/debian/GitRepo/VSSS17/Fridge/src/HttpServer/data.html"); 
    Files.write(file, lines, Charset.forName("UTF-8")); 

} 

static public void decodeData(Produkt data) { 

    Produkt comp = ds.getProduktByName(data.p_name); 
    if (!comp.p_name.equals("Fail")) { 
     //System.out.println("Changed" + data.p_name + "for amount: " + data.p_quant); 
     ds.setQuant(data.p_name, data.p_quant); 
    } else { 
     ds.addProdukt(data); 
    } 

    //System.out.println("---"); 
    if (ds.getLegnth() != 0) { 
    // ds.print(); 
    } 
    //System.out.println("---"); 

} 

}

因此,一旦從Sensordata我的數量爲0,我開始發送 「填充」 字符串到我的客戶。客戶端只獲取「NOT」包。這大約持續50個包裹,直到客戶收到「FILL」包裹。在此之後,服務器發送一個「NOT」包,因爲數量回到100.但客戶仍然收到大約50個包的「FILL」包。我有不同的看法,像打開2個插座,一個用於閱讀一個寫作。但它仍然是同樣的問題。

我真的不明白爲什麼它不起作用。無法在互聯網上找到任何解決方案。也許你們可以幫助我。

+0

UDP沒有可靠性功能。如果你想要可靠性,你必須自己編寫代碼。注意在這種情況下,單詞是'包'而不是'包'。 '數據報'會更好。 – EJP

+0

*在調用包裝的ByteArrayOutputStream的'toByteArray()'方法之前,需要'關閉()'(或至少'flush()')ObjectOutputStream *。就我所瞭解的代碼而言。 –

+0

什麼是實現可靠性的最佳方式?有沒有辦法在收到包之後才發送數據包?我對UDP和數據包發送很新。 –

回答

0

我發現我的問題。我正在向服務器發送4個Packats。服務器正在發送4個數據包。對於每個循環,我的客戶端正在讀取一個數據包,他發送了4個新數據包並獲得了4個新數據包。因此,數據包堆棧剛剛增長。

我把客戶的讀寫分爲2個線程。現在它的工作是完美的