20

我有一个 TCP 套接字连接,它在 Android 2.3 上运行良好,但现在在 Android 4.1 上遇到了一些问题。问题是 InputStream.read() 方法总是返回 -1(没有阻塞),就像连接关闭一样。

创建套接字:

SocketFactory socketFactory = SocketFactory.getDefault();
Socket socket = socketFactory.createSocket("c.whatsapp.net", 5222);
socket.setSoTimeout(3*60*1000);
socket.setTcpNoDelay(true);

检索输入和输出流并写入一些初始数据:

InputStream inputStream = new BufferedInputStream(socket.getInputStream());
OutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());

outputStream.write(87);
outputStream.write(65);
outputStream.write(1);
outputStream.write(2);
outputStream.flush();

然后,这个条件总是通过而不阻塞:

int c = inputStream.read();
if (c < 0) {
    Log.d(TAG, "End of stream");
}

此代码在后台线程中运行。它正在研究姜饼。

尝试使用 InputStreamReader 和 OutputStreamWriter 而不是直接流 - 没有效果。

4

7 回答 7

1

我以前也看到过同样的错误,虽然这个答案可能看起来离题,给它一个机会,让我知道它是否有效,由于某种原因,即使它们在较低的 android 版本中完全正常工作,套接字在 jellybean 上也有奇怪的行为,我解决这个问题的方法是将targetSdkVersion移动到jelly bean以及项目的Android属性下的Project Build Target,没有修改一行代码,只是这样,出于某种原因它可以解决问题.. .

希望这可以帮助。

问候!

于 2013-09-13T16:13:13.823 回答
0

Try this code -

Runnable runnable = new Runnable() {

    @Override
    public void run() {

        synchronized (this) {
            Socket s = null;
            String inMsg = null, msg2 = null;
            try {
                try {
                    s = new Socket(server, port);
                } catch (Exception e) {
                    return;
                }
                BufferedReader in = new BufferedReader(
                        new InputStreamReader(s.getInputStream()));
                BufferedWriter out = new BufferedWriter(
                        new OutputStreamWriter(s.getOutputStream()));
                try {
                    inMsg = in.readLine()
                            + System.getProperty("line.separator");
                } catch (Exception e) {
                    return;
                }

                out.write(message + "\n\r");
                out.flush();
                try {
                    msg2 = in.readLine();
                    if (msg2 == null) {
                        return;
                    }
                } catch (Exception e) {
                    return;
                }
                out.close();
                s.close();
            } catch (Exception e) {
                return;
            }
        }

    }

};

It works for me.

于 2013-12-13T08:18:48.170 回答
0

朋友,

尝试inputStream.readLine();(即)DataInputStream.readLine();(不推荐使用的方法)

这对我有用...

于 2013-10-25T04:39:36.937 回答
0

我有一些类似的问题,inputStream.read()返回 -1 并且我没有得到任何异常。事实上,服务器已关闭,连接中断。我没有用不同的版本测试它,只有4.0。

这是有关此行为的Google 错误报告。

不幸的是,该错误的状态似乎是“关闭”的,因为不可复制。

我的解决方法是将 -1 解释为套接字的关闭和无法访问的服务器。当您尝试重新连接时,您会得到正确的错误。

于 2013-09-13T16:55:10.040 回答
0

我遇到了类似的问题并用这样的解决方法修复了它

private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);

private static class WatchDog implements Runnable{
    private Thread thread = Thread.currentThread();

    public void run() {
        Log.d(LOG_TAG, "Interrupting read due to timeout");
        thread.interrupt();
    }
}

private void read(InputStream in, ByteBuffer bb, long waitTime) throws IOException {
    int startingPos = bb.position();
    long timeout = System.currentTimeMillis() + RESPONSE_TIMEOUT;


    ScheduledFuture<?> watchdogFuture = executor.schedule(new WatchDog(), RESPONSE_TIMEOUT, TimeUnit.MILLISECONDS);
    try {
        while(System.currentTimeMillis() < timeout && bb.hasRemaining()){ //workaround fixing timeout after 1ms
            try{
                int read = in.read(bb.array(), bb.position(), bb.remaining());
                if(read > 0){
                    bb.position(bb.position()+read);
                }
            } catch(SocketTimeoutException e){}
            if(bb.hasRemaining()){
                Thread.sleep(5);
            }
        }
        watchdogFuture.cancel(true);
    } catch (InterruptedException e) {}


    if(bb.hasRemaining()){
        throw new SocketTimeoutException("Unable to read requested bytes: " 
                + (bb.position()-startingPos) + "/" +  (bb.limit()-startingPos)
                + " after " + (System.currentTimeMillis() - timeout + RESPONSE_TIMEOUT) + "ms");
    }
}
于 2013-10-25T07:44:30.570 回答
0

使用 BufferedReader 和 PrintWriter 对我来说适用于所有版本,并且对于通过任何通信协议发送和接收任何你想要的东西(甚至是 JSON 字符串)都非常方便。在启动后台线程时尝试将它们保存为成员变量,如下所示:

mInput = new BufferedReader(new InputStreamReader(
            socket.getInputStream()));
mOutput = new PrintWriter(new BufferedWriter(
            new OutputStreamWriter(socket.getOutputStream())), true);

对于异步通信,您的后台线程可能如下所示:

@Override
public final void run() {
    while (!Thread.currentThread().isInterrupted()) {
        if (mInput == null) {
            break;
        }
        String message = null;
        try {
            message = mInput.readLine();
        } catch (IOException e) {
            // handle the exception as you like
            break;
        }
        if (Thread.currentThread().isInterrupted()) {
            // thread was interrupted while reading
            break;
        } else if (message != null) {
            // handle the message as you like
        }
    }
}

使用另一个后台线程发送消息:

@Override
public void run() {
    if (mOutput != null) {
        mOutput.println(<message to be );
        if (mOutput == null) {
            // the above thread was interrupted while writing
        } else if (!mOutput.checkError()) {
            // everything went fine
        } else {
            // handle the exception
        }
    }
}

此外,您必须从外部关闭流以确保 readLine 不会永远阻塞:

try {
    mOutput.close();
    mInput.close();
    mOutput = null;
    mInput = null;
} catch (IOException e) {
    // log the exception
}

现在,由于您使用的是 TCP 套接字,因此可能会发生套接字实际上已死且 readLine 仍处于阻塞状态的情况。您必须像上面一样检测到并关闭流。为此,您必须添加另一个定期发送保持活动消息的线程(哦,好吧)。如果 X 秒内没有从远程设备接收到消息,它必须关闭流。

这整个方法确保套接字关闭并且所有线程在任何情况下都完成。当然,如果您需要,您可以通过删除发送者线程并在阅读器线程中包含 println() 来使通信同步。我希望对您有所帮助(即使答案晚了 8 个月)。

于 2013-11-08T13:14:39.703 回答
-1

您应该使用 Apache Commons IO:http ://commons.apache.org/proper/commons-io/

请参阅IOUtils.copy() http://commons.apache.org/proper/commons-io/javadocs/api-release/index.html?org/apache/commons/io/package-summary.html

于 2013-09-12T08:15:44.287 回答