从非阻塞套接字通道读取信息

时间:2012-02-22 16:41:22

标签: java android sockets socketchannel

我正在尝试读取非阻塞套接字,以避免在我的程序中遇到问题。有谁知道为什么当我尝试阅读总是返回零?这会是ByteBuffer的问题吗?在read方法中出现此问题,lenght始终为零。

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 :(得分:0)

您正在使用非阻塞通道,这意味着它将阻塞直到数据可用。如果没有数据可用,它会立即返回0而不会阻塞。

答案 1 :(得分:0)

应用程序始终从网络缓冲区读取。

您可能在发送一些数据后立即尝试读取,然后在获得0字节时停止读取。你甚至没有给网络任何时间来返回数据。

相反,你应该在一个循环中读取,如果没有数据,请使用Thread.sleep(time)(使用大约100-300ms)稍微睡一觉,然后重试。

如果你已经等了太久,你应该停止循环:计算睡眠时间,当你得到一些数据时重置。或者在读取所有数据时停止。