Как узнать длину пакета по DatagramChannel?

193
23 апреля 2018, 00:17

Вот изучаю здесь код: http://cs.ecs.baylor.edu/~donahoo/practical/JavaSockets2/code/UDPEchoServerSelector.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
public class UDPEchoServerSelector {
    private static final int TIMEOUT = 3000; // Wait timeout (milliseconds)
    private static final int ECHOMAX = 255; // Maximum size of echo datagram
    public static void main(String[] args) throws IOException {
        if (args.length != 1) // Test for correct argument list
        throw new IllegalArgumentException("Parameter(s): <Port>");
        int servPort = Integer.parseInt(args[0]);
        // Create a selector to multiplex client connections.
        Selector selector = Selector.open();
        DatagramChannel channel = DatagramChannel.open();
        channel.configureBlocking(false);
        channel.socket().bind(new InetSocketAddress(servPort));
        channel.register(selector, SelectionKey.OP_READ, new ClientRecord());
        while (true) { // Run forever, receiving and echoing datagrams
        // Wait for task or until timeout expires
        if (selector.select(TIMEOUT) == 0) {
        System.out.print(".");
        continue;
        }
         // Get iterator on set of keys with I/O to process
        Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
        while (keyIter.hasNext()) {
        SelectionKey key = keyIter.next(); // Key is bit mask
    // Client socket channel has pending data?
    if (key.isReadable())
      handleRead(key);
    // Client socket channel is available for writing and
    // key is valid (i.e., channel not closed).
    if (key.isValid() && key.isWritable())
      handleWrite(key);
    keyIter.remove();
    }
    }
    }
public static void handleRead(SelectionKey key) throws IOException {
 DatagramChannel channel = (DatagramChannel) key.channel();
 ClientRecord clntRec = (ClientRecord) key.attachment();
 clntRec.buffer.clear();    // Prepare buffer for receiving
 clntRec.clientAddress = channel.receive(clntRec.buffer);
 if (clntRec.clientAddress != null) {  // Did we receive something?
   // Register write with the selector
   key.interestOps(SelectionKey.OP_WRITE);
 }
}
public static void handleWrite(SelectionKey key) throws IOException {
 DatagramChannel channel = (DatagramChannel) key.channel();
 ClientRecord clntRec = (ClientRecord) key.attachment();
 clntRec.buffer.flip(); // Prepare buffer for sending
 int bytesSent = channel.send(clntRec.buffer, clntRec.clientAddress);
 if (bytesSent != 0) { // Buffer completely written?
  // No longer interested in writes
   key.interestOps(SelectionKey.OP_READ);
  }
 }
static class ClientRecord {
public SocketAddress clientAddress;
public ByteBuffer buffer = ByteBuffer.allocate(ECHOMAX);
}
}

И не понимаю, каким образом можно узнать через DatagramChannel длинну приходящего пакета чтобы из ByteBuffer считать нужное количество?

Answer 1

Прежде всего важно понять, что попадание канала в выборку селектора по готовности на чтение не означает, что пришли все данные. Пришло сколько-то данных. Отправляющий код мог передать 512 байт, а селектор может выбрать канал 42 раза - несколько раз по одному байту, несколько раз по нескольку десятков байт и т.д. Поэтому в цикле мультиплексирования нельзя ожидать поступления всех данных, а надо только читать и добавлять в буффер столько, сколько пришло, до тех пор, пока не накопится нужное количество. В тех случаях, когда обмен идёт по tcp и через одно соединение будет передан только один блок данных, проще всего определить об окончании передачи по тому, что метод read вернул -1. Если же через один канал передаётся множество блоков или используется udp, то принимающая сторона должна знать, сколько она должна принять. Самый простой, но весьма неудобный способ - это передавать блоки данных фиксированного размера. Другой - это сначала передать int или long, содержащий размер передаваемых данных, а потом передать столько данных.

READ ALSO
Что возвращает return? [требует правки]

Что возвращает return? [требует правки]

Никак не могу понять, что должен возвращать return, true или false, или же вообще какое-то значение?

127
java android Фоновое распознавание текста

java android Фоновое распознавание текста

Находил такую реализацию распознавания текста (используя гугл сервисы) архив с исходникомТам открывается подобное окно

152
Android java, как сделать нескольких уровней в игре [требует правки]

Android java, как сделать нескольких уровней в игре [требует правки]

Необходимо сделать несколько уровней игрыНужно ли каждый уровень записывать в отдельный класс? Как сделать так чтобы на каждом уровне был...

134
Ошибка в sql запросе UPDATE

Ошибка в sql запросе UPDATE

в DAO пытаюсь выполнить такой запрос: UPDATE PRODUCTS SET PRICE = ?, SET STOCK = ? WHERE SOURCE_ID = ? используя PreparedStatement(), но получаю javasql

140