Чтение информации с неблокирующего SocketChanel - PullRequest
0 голосов
/ 22 февраля 2012

Я пытаюсь прочитать неблокирующий сокет, чтобы не застрять в какой-то момент в моей программе.Кто-нибудь знает, почему, когда я пытаюсь читать, всегда возвращаю ноль?Это было бы проблемой с ByteBuffer?Эта проблема возникает в методе чтения, длина которого всегда равна нулю.

package com.viewt.eyebird.communication;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.viewt.eyebird.PhoneInformation;
import com.viewt.eyebird.TrackingServiceData;
import com.viewt.eyebird.commands.*;

import android.os.Handler;
import android.util.Log;

final public class ServerCommunication {

    protected final int socketTimeout;
    protected final TrackingServiceData commandData;
    protected final Handler handler;
    protected final ServerCommunicationChecker clientChecker;
    protected final LinkedList<Serialize> queue = new LinkedList<Serialize>();

    protected final ByteBuffer socketBuffer = ByteBuffer.allocate(1024);
    protected final StringBuilder readBuffer = new StringBuilder();

    protected static final Pattern commandPattern = Pattern.compile(">[^<]+<");

    protected static final ServerCommand availableCommands[] = { new Panic(),
            new ChangeServer(), new GetServer(), new Restart(),
            new PasswordCleanup() };

    protected InetSocketAddress inetSocketAddress;
    protected SocketChannel sChannel;

    public ServerCommunication(Handler handler, String host, int port,
            int timeAlive, int socketTimeout,
            PhoneInformation phoneInformation, TrackingServiceData commandData) {

        this.commandData = commandData;
        this.handler = handler;
        this.socketTimeout = socketTimeout;

        try {
            connect(host, port);
        } catch (CommunicationException e) {
            Log.getStackTraceString(e);
        }

        clientChecker = new ServerCommunicationChecker(handler, this,
                timeAlive, new AliveResponse(phoneInformation));

        handler.postDelayed(clientChecker, timeAlive);

    }

    public void connect() throws CommunicationException {
        try {
            sChannel = SocketChannel.open();
            sChannel.configureBlocking(false);
            sChannel.socket().setSoTimeout(socketTimeout);
            sChannel.connect(inetSocketAddress);
        } catch (IOException e) {
            throw new CommunicationException(e);
        }
    }

    public boolean isConnectionPending() {
        return sChannel.isConnectionPending();
    }

    public boolean finishConnection() throws CommunicationException {
        try {
            return sChannel.finishConnect();
        } catch (IOException e) {
            throw new CommunicationException(e);
        }
    }

    public void connect(String host, int port) throws CommunicationException {
        inetSocketAddress = new InetSocketAddress(host, port);
        connect();
    }

    public void send(Serialize serialize) throws CommunicationException {
        try {
            sChannel.write(ByteBuffer
                    .wrap(String.valueOf(serialize).getBytes()));
        } catch (IOException e) {
            throw new CommunicationException(e);
        }
    }

    public void sendOrQueue(Serialize serialize) {
        try {
            send(serialize);
        } catch (Exception e) {
            queue(serialize);
        }
    }

    public void queue(Serialize serialize) {
        queue.add(serialize);
    }

    @Override
    protected void finalize() throws Throwable {
        handler.removeCallbacks(clientChecker);
        super.finalize();
    }

    public void sync() throws CommunicationException {
        int queueSize = queue.size();
        for (int i = 0; i < queueSize; i++) {
            send(queue.getFirst());
            queue.removeFirst();
        }
    }

    public void read() throws CommunicationException {

        int length, readed = 0;

        try {
            while ((length = sChannel.read(socketBuffer)) > 0)
                for (readed = 0; readed < length; readed++)
                    readBuffer.append(socketBuffer.get());
        } catch (IOException e) {
            throw new CommunicationException(e);
        } finally {
            socketBuffer.flip();
        }

        Matcher matcher = commandPattern.matcher(readBuffer);

        int lastCommand;
        if ((lastCommand = readBuffer.lastIndexOf("<")) != -1)
            readBuffer.delete(0, lastCommand);

        while (matcher.find()) {
            for (ServerCommand command : availableCommands) {
                try {
                    command.command(matcher.group(), commandData);
                    break;
                } catch (CommandBadFormatException e) {
                    continue;
                }
            }
        }

        if (length == -1)
            throw new CommunicationException("Server closed");

    }

}

Ответы [ 2 ]

0 голосов
/ 22 февраля 2012

Приложения всегда читают из сетевых буферов.

Вы, вероятно, пытаетесь прочитать сразу после отправки данных, а затем, когда получаете 0 байтов, вы прекращаете чтение. Вы даже не дали сети время вернуть данные.

Вместо этого вы должны читать в цикле и, если вы не получаете данных, немного поспать с Thread.sleep(time) (используйте около 100-300 мс), а затем повторить попытку.

Вы должны остановить цикл, если вы уже ждали слишком долго: подсчитайте количество снов, сбросьте их, когда получите некоторые данные. Или остановитесь, когда все данные прочитаны.

0 голосов
/ 22 февраля 2012

Вы используете неблокирующий канал, что означает, что он будет блокироваться до тех пор, пока данные не станут доступны.Возвращается с 0 сразу без блокировки, если данные недоступны.

...