Селектор не становится активным, несмотря на то, что читается

1

В настоящее время я работаю над проектом проекта с использованием многоадресной рассылки UDP. Я пытаюсь реализовать NIO, так как мне приходится иметь дело с 3-мя каналами. В основном одна из целей состоит в том, чтобы разбить файл на куски, а затем отправить эти фрагменты в группу многоадресной рассылки для хранения.

Моя проблема в том, что я на самом деле отправляю все куски, но не получаю их всех. От куска 1 до куска 4 обычно идет хорошо, но потом он пропускает куски, и, пропуская, я имею в виду, что канал не читается.

Здесь код, который имеет отношение к селектору и каналам:

//Peer Class Constructor
public Peer(String mcast_addr, int mcast_port, String mcastbackup_addr, int mcastbackup_port, String mcastrestore_addr, int mcastrestore_port) throws IOException {
    this.ni = NetworkInterface.getByName("eth0");

    this.mcast_port = mcast_port;
    this.mcast_addr = mcast_addr;
    this.controlAddr = InetAddress.getByName(mcast_addr);
    this.ctrladr = new InetSocketAddress(mcast_addr,mcast_port);

    this.mcastbackup_addr = mcastbackup_addr;
    this.mcastbackup_port = mcastbackup_port;
    this.backupAddr = InetAddress.getByName(mcastbackup_addr);
    this.backadr = new InetSocketAddress(mcastbackup_addr, mcastbackup_port);

    this.mcastrestore_addr = mcastrestore_addr;
    this.mcastrestore_port = mcastrestore_port;
    this.restoreAddr = InetAddress.getByName(mcastrestore_addr);
    this.restadr = new InetSocketAddress(mcastrestore_addr, mcastrestore_port);

    this.selector = this.initSelector();

}               //TODO Check all methods/variables used in several thread and check concurrency
@Override
public void run() {
    System.out.println("Waiting...\n");
    while (true) {
        try {
            // Process any pending changes
            synchronized (this.pendingChanges) {
                Iterator changes = this.pendingChanges.iterator();
                while (changes.hasNext()) {
                    ChangeRequest change = (ChangeRequest) changes.next();
                    switch (change.type) {
                        case ChangeRequest.CHANGEOPS:
                            SelectionKey key = change.socket.keyFor(this.selector);
                            key.interestOps(change.ops);
                            break;
                    }
                }
                this.pendingChanges.clear();
            }

            // Wait for an event in one of the registered channels
            int readyChannels = selector.select();
            if (readyChannels == 0) continue;

            // Iterate over the set of keys for which events are available
            Iterator selectedKeys = this.selector.selectedKeys().iterator();

            while (selectedKeys.hasNext()) {
                SelectionKey key = (SelectionKey) selectedKeys.next();
                selectedKeys.remove();

                if (!key.isValid()) {
                    System.out.println("Not Valid Key");
                    continue;
                }
                // Check what event is available and deal with it
                if (key.isReadable()) {
                    System.out.println("Readable");
                    this.read(key);
                } else if (key.isWritable()) {
                    System.out.println("Writable");
                    this.write(key);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

//Channels Initialization - OPTION: REUSEADRR, MULTICAST_LOOPBACK, MULTICAST ON INTERFACE, MULTICAST TIME TO LIVE = 1
public Selector initSelector() throws IOException {
    Selector channelSelector = Selector.open();

    this.controlChannel = DatagramChannel.open(StandardProtocolFamily.INET)
            .setOption(StandardSocketOptions.SO_REUSEADDR, true)
            .setOption(StandardSocketOptions.IP_MULTICAST_LOOP, false)
            .setOption(StandardSocketOptions.IP_MULTICAST_IF, ni)
            .setOption(StandardSocketOptions.IP_MULTICAST_TTL, 1)
            .bind(new InetSocketAddress(mcast_port));
    controlChannel.configureBlocking(false);
    MembershipKey key = controlChannel.join(controlAddr, ni);
    controlChannel.register(channelSelector, SelectionKey.OP_READ);

    this.backupChannel = DatagramChannel.open(StandardProtocolFamily.INET)
            .setOption(StandardSocketOptions.SO_REUSEADDR, true)
            .setOption(StandardSocketOptions.IP_MULTICAST_LOOP, false)
            .setOption(StandardSocketOptions.IP_MULTICAST_IF, ni)
            .setOption(StandardSocketOptions.IP_MULTICAST_TTL, 1)
            .bind(new InetSocketAddress(mcastbackup_port));
    backupChannel.configureBlocking(false);
    MembershipKey key1 = backupChannel.join(backupAddr, ni);
    backupChannel.register(channelSelector, SelectionKey.OP_READ);


    return channelSelector;
}

//Read from channel method - Deploys runnable to execute the protocol
public void read(SelectionKey key) throws IOException {
    DatagramChannel channel = (DatagramChannel) key.channel();

    this.readBuffer.clear();

    System.out.println("Listening....");
    String in;

    try {
        InetSocketAddress sa = (InetSocketAddress) channel.receive(this.readBuffer);

        readBuffer.flip();
        ByteBuffer message = readBuffer.slice();

        int i = getReceivingChannel(sa);
        switch(i)
        {
            case BC:
                System.out.println("Backup Service for: " + sa.getHostName());
                initiateBackupService(message);
                break;

            case RC:
                System.out.println("Restore");
                break;

            case CC:
                System.out.println("Control");
                break;
        }

       // System.out.println(Arrays.toString(readBuffer.array()));
        /*String s = new String(readBuffer.array(), 0, readBuffer.limit());
        in = s;*/
       // System.out.println("Received: " + s + " from " + sa.getHostName() + " at port: " + sa.getPort());

    } catch (IOException e) {
        key.cancel();
        channel.close();
        e.printStackTrace();
        return;
    }

    this.selector.wakeup();
}

//Writes to channel pending information when exists
private void write(SelectionKey key) throws IOException {
    DatagramChannel channel = (DatagramChannel) key.channel();

    synchronized (this.pendingData) {
        List queue = (List) this.pendingData.get(channel);
        // Write until there not more data ...
        while (!queue.isEmpty()) {
            ByteBuffer buf = ByteBuffer.allocate(Chunk.CHUNK_SIZE);

            buf.clear().flip();
            buf = (ByteBuffer) queue.get(0);

            int i = channel.send(buf, backadr);
            //System.out.println("Sending to address: " + backadr.getHostName() + " :\n" + new String(buf.array(), 0, buf.array().length) + "\n");
            if (buf.remaining() > 0) {
                // ... or the socket buffer fills up
                break;
            }
            queue.remove(0);
        }

        if (queue.isEmpty()) {
            System.out.println("no data");
            // We wrote away all data, so we're no longer interested
            // in writing on this socket. Switch back to waiting for
            // data.

            key.interestOps(SelectionKey.OP_READ);
        }
    }
}

//Send Method - When the user triggers the backup button this is the class where we add what we want to send to the pendingdata
public void send(DatagramChannel channel, byte[] data) throws IOException {

    synchronized (this.pendingChanges) {
        // Indicate we want the interest ops set changed
        this.pendingChanges.add(new ChangeRequest(channel, ChangeRequest.CHANGEOPS, SelectionKey.OP_WRITE));

        // And queue the data we want written
        synchronized (this.pendingData) {
            List queue = (List) this.pendingData.get(channel);
            if (queue == null) {
                queue = new ArrayList();
                this.pendingData.put(channel, queue);
            }
            System.out.println(queue.size());
            queue.add(ByteBuffer.wrap(data));
        }
    }

    // Finally, wake up our selecting thread so it can make the required changes
    this.selector.wakeup();
}

public void initiateBackupFileProtocol(File file, int repDegree) throws IOException {
    //TODO Create runnable to execute de backupsubprotocol

    Future future = executor.submit(new BackupSubProtocol(this.executor, this, controlChannel, backupChannel, file, repDegree, backadr));

    try {
        if(future.get() == null){
            System.out.println("Backup Sub-Protocol finished correctly\n");
        }
        else
            System.out.println("Error while executing BackupSubProtocol.");
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }

    /* FileEntry filee = new FileEntry(file);

    Chunk c = new Chunk(filee, 1, 2,"coisas".getBytes());

    Message back = new PutChunkMessage(1, 0, filee.getFileID(), 0, 1, new byte[0]);

    System.out.println(new String(back.constructMessage(), "UTF-8"));
    System.out.println();

    Message sto = new StoredMessage(1, 0, filee.getFileID(), 0);

    System.out.println(new String(sto.constructMessage(), "UTF-8"));


    Message get = new GetChunkMessage(1, 0, filee.getFileID(), 0);

    System.out.println(new String(get.constructMessage(), "UTF-8"));


    Message ch = new ChunkMessage(1, 0, filee.getFileID(), 0, new byte[0]);

    System.out.println(new String(ch.constructMessage(), "UTF-8"));
    System.out.println();

    Message del = new DeleteMessage(1, 0, filee.getFileID());

    System.out.println(new String(del.constructMessage(), "UTF-8"));

    Message rem = new RemovedMessage(1, 0, filee.getFileID(), 0);

    System.out.println(new String(rem.constructMessage(), "UTF-8"));
*/

    //send(backupChannel, back.constructMessage());
    //send(controlChannel, str.getBytes());
}

public class ChangeRequest {
    public static final int CHANGEOPS = 2;

    public DatagramChannel socket;
    public int type;
    public int ops;

    public ChangeRequest(DatagramChannel socket, int type, int ops) {
        this.socket = socket;
        this.type = type;
        this.ops = ops;
    }
}

public int getReceivingChannel(InetSocketAddress sa)
{
    int port = sa.getPort();

    if(port == mcastbackup_port)
    {
        return BC;
    }
    else if(port == mcast_port)
    {
        return CC;
    }
    else if(port == mcastrestore_port)
    {
        return RC;
    }

    return -1;
}

public void initiateBackupService(ByteBuffer m) throws UnsupportedEncodingException {
    Future future = executor.submit(new BackupService(this.executor, m));

    try {
        if(future.get() == null){
            System.out.println("Backup Sub-Protocol finished correctly\n");

        }
        else
            System.out.println("Error while executing BackupSubProtocol.");
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

public void initiateRestoreFileProtocol(byte[] FileId) throws IOException {
    //TODO Create runnable to execute de backupsubprotocol

    Future future = executor.submit(new RestoreSubProtocol(this.executor, this, controlChannel, restoreChannel, FileId));

    try {
        if(future.get() == null){
            System.out.println("Backup Sub-Protocol finished correctly\n");
        }
        else
            System.out.println("Error while executing BackupSubProtocol.");
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

Вот распечатка того, что я получаю:

Изображение 174551

Он отправил, предположительно, 218 кусков, как я подтвердил через Wireshark, но, как говорится в изображении, он пропускает многие из них.

Может быть, он блокирует выбор, но я не могу понять, почему.

Любая помощь будет оценена,
заранее спасибо

Редактировать # 1 - Кажется, что если я вставляю Thread.sleep после отправки каждой дейтаграммы, он работает правильно, есть ли еще один aproach?

Теги:
multithreading
selector
nio

1 ответ

0

Вы, похоже, не знаете, что UDP не является надежным, т.е. Он не обладает функциями надежности, поэтому потеря пакетов никогда не обнаруживается и не компенсируется. Добавление сон снизило скорость передачи и, следовательно, скорость потери пакетов. В вашем протоколе необходимо реализовать некоторые функции надежности.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню