我有一个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而不是直接流 - 没有效果。
答案 0 :(得分:1)
之前我看过同样的错误,虽然这个答案可能看起来像offtopic给它一个机会,让我知道它是否有效,由于某种原因,套接字在jellybean上有奇怪的行为,即使它们在下层机器人工作完全正常版本,我解决这个问题的方法是将targetSdkVersion移动到果冻豆以及项目的Android属性下的Project Build Target,没有修改一行代码,只是因为某些原因,它确实特技...
希望这有帮助。
问候!
答案 1 :(得分:0)
我有一些类似的问题,inputStream.read()
返回-1,我没有得到任何异常。事实上,服务器已关闭,连接断开。我没有用不同的版本测试它,只用4.0。
这是关于此行为的Google Bug Report。
不幸的是,这个bug的状态似乎是“关闭”的,因为它不可重现。
我的工作是将-1解释为套接字的关闭和无法访问的服务器。当您尝试重新连接时,您会收到正确的错误。
答案 2 :(得分:0)
朋友,
尝试inputStream.readLine();
(即)DataInputStream.readLine();
(弃用方法)
这对我有用......
答案 3 :(得分: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");
}
}
答案 4 :(得分: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仍然阻塞。你必须像上面那样检测到并关闭流。为此,你必须添加另一个周期性发送keep-alive-messages的线程(哦)。如果在X秒内未从远程设备收到任何消息,则必须关闭流。
这整个方法确保套接字关闭,所有线程在所有情况下都完成。当然,通过删除sender-thread并在reader-thread中包含println(),您可以使通信同步,如果这是您需要的。我希望能帮到你(即使答案迟到了8个月)。
答案 5 :(得分:0)
试试这段代码 -
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;
}
}
}
};
它对我有用。
答案 6 :(得分:-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