此问题已经在这里有了答案:
我正在用Java编写一个TCP客户端,该客户端将从服务器接收请求并对其进行响应,如果在最近一分钟内服务器未发送ping命令,则重新连接到服务器。客户端是同步的,所有内容都在一个线程上运行。每当我强行关闭服务器时(这对客户端来说是意外的,但是TCP不会超时而不是立即知道服务器已关闭吗?),即使我已经封闭了,我也会立即在SocketChannel.read上收到StackOverflowError。尝试一下。
以下是相关代码:
private void readRequestHeader() {
if (requestHeaderBuffer == null) {
requestHeaderBuffer = ByteBuffer.allocate(9);
}
try {
socketChannel.read(requestHeaderBuffer); //LINE 52: ERROR!
} catch (Exception e) {
}
if (lastPingTime != 0 && System.currentTimeMillis() > lastPingTime + pingInterval * 2) {
disconnect();
} else {
if (requestHeaderBuffer.hasRemaining()) {
readRequestHeader();
} else {
BinaryBufferReader requestHeader = new BinaryBufferReader(requestHeaderBuffer.array()); //LINE 61: MORE ERROR!
requestPing = requestHeader.readBool();
requestIndex = requestHeader.readInt();
requestDataLength = requestHeader.readInt();
if (requestPing) {
lastPingTime = System.currentTimeMillis();
}
requestDataBuffer = null;
readRequestData();
}
}
}
这是LogCat的输出:
10-31 13:41:34.385 3687 9289 E AndroidRuntime: FATAL EXCEPTION: Thread-2
10-31 13:41:34.385 3687 9289 E AndroidRuntime: Process: com.test.test, PID: 3687
10-31 13:41:34.385 3687 9289 E AndroidRuntime: java.lang.StackOverflowError: stack size 1037KB
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at java.lang.ThreadLocal$ThreadLocalMap.getEntry(ThreadLocal.java:416)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at java.lang.ThreadLocal$ThreadLocalMap.-wrap0(Unknown Source:0)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at java.lang.ThreadLocal.get(ThreadLocal.java:163)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at dalvik.system.BlockGuard.getThreadPolicy(BlockGuard.java:145)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:42)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at sun.nio.ch.IOUtil.read(IOUtil.java:197)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:419)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at com.test.test.Client.readRequestHeader(Client.java:52)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at com.test.test.Client.readRequestHeader(Client.java:61)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at com.test.test.Client.readRequestHeader(Client.java:61)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at com.test.test.Client.readRequestHeader(Client.java:61)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at com.test.test.Client.readRequestHeader(Client.java:61)
10-31 13:41:34.385 3687 9289 E AndroidRuntime: at com.test.test.Client.readRequestHeader(Client.java:61)
这是整个客户端类代码:
package com.test.test;
import android.app.Service;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
class Client {
public Service service;
private SocketChannel socketChannel;
private int pingInterval;
private long lastPingTime;
private ByteBuffer requestHeaderBuffer;
private ByteBuffer requestDataBuffer;
private ByteBuffer responseHeaderBuffer;
private ByteBuffer responseDataBuffer;
private boolean requestPing;
private int requestIndex;
private int requestDataLength;
public Client(Service service) {
this.service = service;
try {
socketChannel = SocketChannel.open();
} catch (Exception e) {
}
pingInterval = 30000;
connect();
}
private void connect() {
try {
socketChannel.connect(new InetSocketAddress("0.tcp.ngrok.io", 14081));
} catch (Exception e) {
}
lastPingTime = 0;
requestHeaderBuffer = null;
readRequestHeader();
}
public void disconnect() {
connect();
}
private void readRequestHeader() {
if (requestHeaderBuffer == null) {
requestHeaderBuffer = ByteBuffer.allocate(9);
}
try {
socketChannel.read(requestHeaderBuffer); \\LINE 52: ERROR!
} catch (Exception e) {
}
if (lastPingTime != 0 && System.currentTimeMillis() > lastPingTime + pingInterval * 2) {
disconnect();
} else {
if (requestHeaderBuffer.hasRemaining()) {
readRequestHeader();
} else {
BinaryBufferReader requestHeader = new BinaryBufferReader(requestHeaderBuffer.array()); \\LINE 61: MORE ERROR!
requestPing = requestHeader.readBool();
requestIndex = requestHeader.readInt();
requestDataLength = requestHeader.readInt();
if (requestPing) {
lastPingTime = System.currentTimeMillis();
}
requestDataBuffer = null;
readRequestData();
}
}
}
private void readRequestData() {
if (requestDataBuffer == null) {
requestDataBuffer = ByteBuffer.allocate(requestDataLength);
}
try {
socketChannel.read(requestDataBuffer);
} catch (Exception e) {
}
if (lastPingTime != 0 && System.currentTimeMillis() > lastPingTime + pingInterval * 2) {
disconnect();
} else {
if (requestDataBuffer.hasRemaining()) {
readRequestHeader();
} else {
BinaryBufferReader requestData = new BinaryBufferReader(requestDataBuffer.array());
BinaryBufferWriter responseHeader = new BinaryBufferWriter();
BinaryBufferWriter responseData = new BinaryBufferWriter();
if (requestPing) {
responseData.writeString("ping");
} else {
String requestAction = requestData.readString();
if (requestAction.equals("hello")) {
ActionHello.run(this, requestData, responseData);
} else if (requestAction.equals("update")) {
ActionUpdate.run(this, requestData, responseData);
} else {
responseData.writeString("blah");
}
}
byte[] temp = responseData.getBuffer();
responseHeader.writeBool(requestPing);
responseHeader.writeInt(requestIndex);
responseHeader.writeInt(temp.length);
responseHeaderBuffer = ByteBuffer.wrap(responseHeader.getBuffer());
responseDataBuffer = ByteBuffer.wrap(temp);
writeResponseHeader();
}
}
}
private void writeResponseHeader() {
while (responseHeaderBuffer.hasRemaining()) {
try {
socketChannel.write(responseHeaderBuffer);
} catch (Exception e) {
}
}
if (lastPingTime != 0 && System.currentTimeMillis() > lastPingTime + pingInterval * 2) {
disconnect();
} else {
if (responseHeaderBuffer.hasRemaining()) {
writeResponseHeader();
} else {
writeResponseData();
}
}
}
private void writeResponseData() {
while (responseDataBuffer.hasRemaining()) {
try {
socketChannel.write(responseDataBuffer);
} catch (Exception e) {
}
}
if (lastPingTime != 0 && System.currentTimeMillis() > lastPingTime + pingInterval * 2) {
disconnect();
} else {
if (responseDataBuffer.hasRemaining()) {
writeResponseData();
} else {
requestHeaderBuffer = null;
readRequestHeader();
}
}
}
}
不要默默地吞下例外
catch (Exception e) {
}
我想这将是记录消息的好地方,return
否则,at com.test.test.Client.readRequestHeader(Client.java:61)
继续被调用导致StackOverflow