从非阻塞 SocketChanel 读取信息

发布于 2025-01-08 06:36:58 字数 4915 浏览 2 评论 0原文

我正在尝试读取非阻塞套接字以避免在程序中的某个时刻卡住。有谁知道为什么当我尝试读取时总是返回零? 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");

    }

}

I'm trying to read a nonblocking socket to avoid getting stuck at some point in my program. Does anyone know why when I try to read always return zero? It would be a problem with ByteBuffer? This problem occurs in the read method with lenght is always zero.

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");

    }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

彼岸花似海 2025-01-15 06:36:58

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

You are using non blocking channel, which means it will block till data is available. It returns with 0 immediately without blocking if no data is available.

撞了怀 2025-01-15 06:36:58

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

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

相反,您应该循环读取,如果没有获取数据,请使用 Thread.sleep(time) 休眠一会儿(使用大约 100-300 毫秒),然后重试。

如果您已经等待太久,您应该停止循环:计算睡眠次数,在获得一些数据时重置。或者当所有数据读取完毕后停止。

Applications always read from network buffers.

You probably try to read immediately after you send some data and then when you get 0 bytes you stop reading. You didn't even give any time to the network to return data.

Instead, you should read in a loop and if you get no data, sleep a little with Thread.sleep(time) (use about 100-300ms), then retry.

You should stop the loop if you already waited too long: count the sleeps, reset when you get some data. Or stop when all data is read.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文