2014-09-08 3 views
0

Я начинаю программировать Java NIO и создаю две отдельные программы Java. Один из них - создать некоторые случайные данные для отправки по протоколу UDP, а другой - для получения этих данных и, возможно, выполнить некоторую обработку на нем.Java DatagramChannel зависает

В каждом классе я определил РАЗМЕР данных, которые должны быть отправлены/приняты, и количество байтов, отправляемых или получаемых за один раз (за пакет) с 8 байтами. Когда у меня есть РАЗМЕР 1024 байта, я могу включить приемник (который по умолчанию ждет некоторых пакетов, чтобы прибыть), после чего я включаю отправителя, который отправляет пакеты, и получатель правильно принимает эти пакеты и завершает работу, когда все пакеты принимаются. Затем я попытался установить SIZE в 10 мегабайт. Я запускаю приемник, а затем запускаю отправителя. Отправитель, кажется, работает нормально и заканчивается через несколько секунд. Приемник начинает работать и переходит к чтению нескольких пакетов (я поставил несколько строк вокруг кода). Однако, где-то в процессе, приемник, кажется, виснет и перестает получать больше пакетов. Я не знаю, где происходит зависание, за исключением того, что это происходит сразу после очистки буфера для нового чтения.

Возможно, я неправильно использую библиотеку. Буду признателен за любую оказанную помощь.

Класс отправителя называется UDPSender, как показано ниже:

public class UDPSender { 

    public static void main(String[] args) { 
     try { 
      // Generate some data to send 
      int SIZE=1024*1024*10; 
      int bufferBytes = 8; 

      byte[] b = new byte[SIZE]; 
      new Random().nextBytes(b); 
      String value = new String(b); 
      //System.out.println(value); 

      // Create Datagram channel for sending UDP packets 
      DatagramChannel sendingChannel = DatagramChannel.open(); 
      // Bind the channel to a specific sending socket address and port 
      InetSocketAddress sendSocket = new InetSocketAddress("127.0.0.1", 9999); 
      sendingChannel.socket().bind(sendSocket); 

      //Target socket address 
      InetSocketAddress targetSocket = new InetSocketAddress("127.0.0.1", 8888); 
      //loop to send bufferBytes bytes at a time 
      int location = 0; 
      int bytesSent = 0; 
      long startTime=0; long endTime=0; long elapsedTime=0; // for speed benchmarking 
      startTime = System.nanoTime(); 
      for (int i = 1; i <= SIZE/bufferBytes; i++) { 
       //System.out.println(i); 
       ByteBuffer buf = ByteBuffer.allocate(bufferBytes); 
       buf.clear(); 
       buf.put(Arrays.copyOfRange(b, location, location + bufferBytes)); 
       location = location + bufferBytes; 
       buf.flip(); 
       bytesSent = bytesSent + sendingChannel.send(buf, targetSocket); 
      } 
      endTime = System.nanoTime(); 
      elapsedTime = endTime - startTime; 
      double elapsedTimeMs = elapsedTime/1000000.0; 
      System.out.println("Elapsed:" + elapsedTimeMs + " msec"); 
     } catch (IOException ex) { 
      Logger.getLogger(UDPSender.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 

Второй класс называется UDPReceiver, как показано ниже:

public class UDPReceiver { 
    public static void main(String[] args) { 
     try { 
      int SIZE=1024*1024*10; 
      int bufferBytes = 8; 
      int packet_max = SIZE/bufferBytes; 

      // Create Datagram channel for receiving UDP packets 
      DatagramChannel receivingChannel = DatagramChannel.open(); 
      // Bind the channel to a specific receiving socket address and port 
      InetSocketAddress receiveSocket = new InetSocketAddress("127.0.0.1",8888); 
      receivingChannel.socket().bind(receiveSocket); 
      // Set up address of send 
      InetSocketAddress sendSocket = new InetSocketAddress("127.0.0.1",9999); 
      // Connect our receiving socket to their sending socket address 
      receivingChannel.connect(sendSocket); 

      long startTime=0; long endTime=0; long elapsedTime=0; // for speed benchmarking 
      byte[] b = new byte[SIZE]; //receiving storage 
      int packets=0; int location=0; int bytesCount; //byte[] indexes 
      boolean clockStart=false; 


      //try indirect ByteBuffer 
      System.out.println("Indirect ByteBuffer()"); 
      ByteBuffer buf = ByteBuffer.allocate(bufferBytes); 
      packets=0; location=0; bytesCount = 0; clockStart=false; 
      while ((bytesCount = receivingChannel.read(buf)) > 0) { // Read data from file into ByteBuffer 
       System.out.println("."); 
       if(clockStart==false){ 
        startTime = System.nanoTime(); 
        clockStart=true; 
       } 
       // flip the buffer which set the limit to current position, and position to 0. 
       buf.flip(); System.out.println(".."); 
       System.arraycopy(buf.array(), 0, b, location, buf.capacity()); System.out.println("..."); // Write data from ByteBuffer to bytearray 
       location=location+bufferBytes; System.out.println("...."); 
       buf.clear(); System.out.println("....."); // For the next read 
       packets = packets+1; System.out.println("......"); 
       if(packets==packet_max){ 
        System.out.println("......."); 
        System.out.println(packets); 
        break; 
       } 
      } 
      endTime = System.nanoTime(); 
      elapsedTime = endTime - startTime; 
      System.out.println("ByteBuffer() Elapsed Time is " + (elapsedTime/1000000.0) + " msec"); 

     } catch (IOException ex) { 
      System.out.println(ex.toString()); 
      //Logger.getLogger(UDPReceiver.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 
+0

Почему 8 байтов? Восемь байтов полезной нагрузки и 28 байтов служебных данных заголовка UDP не имеют большого смысла. – EJP

+0

Привет @EJP - Спасибо за чтение. У меня нет особых причин для 8 байтов. Это просто пример, с помощью которого я пытаюсь узнать о UDP, NIO и т. Д. Такая же проблема возникает даже при больших нагрузках, например. 64 байта. –

+0

Некоторые дополнительные подробности после отладки: я замедлял скорость UDPSender, вставив Thread.sleep (1); после каждого отправленного пакета, и теперь получатель может пройти весь цикл. Кажется, это ограничение на пакет UDP-пакетов, которые могут быть приняты за один раз. –

ответ

0

Это не 'висеть', это блоки,, и это происходит потому, что вы пытаетесь прочитать определенное количество пакетов, не обращая внимания на то, что UDP ненадежен. Когда вы теряете пакеты, как и вы, ваш отправитель и получатель не знают об этом, поэтому ваш отправитель не отправляется повторно, и ваш получатель продолжает читать все количество пакетов, которые никогда не прибудут.

+0

Это имеет большой смысл, спасибо! Когда я замедлил передачу вниз, все пакеты были получены, и по мере ускорения передачи некоторые пакеты терялись или не получали вовремя, и поэтому процесс, как вы говорите, продолжал ждать большего количества (точного числа) пакетов которые никогда не появлялись с тех пор, как они потерялись. Боковой вопрос - как вы думаете, реалистично использовать Java-сокеты для высоких скоростей передачи данных, например. 10Gb/s входящих пакетов? В качестве альтернативы, возможно, неплохо использовать некоторую форму пакетного обнюхивания непосредственно в интерфейсе Ethernet. Возможно ли это с Java? –

+1

Это не имеет ничего общего с Java. Вопрос в том, целесообразно ли использовать UDP таким образом, а ответ - нет. Если вам нужно получить определенное количество пакетов, используйте TCP. Если вы можете позволить себе потерять пакеты, и вы можете переписать свой код, чтобы не ожидать фиксированного количества из них, обязательно используйте UDP. – EJP

+0

В этом примере выше я только тестировал, теряются ли пакеты и какие скорости передачи я могу достичь. Я рассматриваю приложение, где я могу позволить себе потерять некоторые пакеты без каких-либо последствий, но в то же время хотел бы ускорить скорость передачи и, насколько я понимаю, поскольку реализация UDP намного проще, поэтому гораздо быстрее, если вы «готовы согласиться с такими ограничениями, как потеря пакетов. Другой вопрос: может ли Java использоваться для чтения необработанных кадров на интерфейсе Ethernet (обход TCP/IP-стека). Я читаю в библиотеке под названием Jpcap now –