我的Android代码一直发送数据,它似乎一直有效,直到抛出完全意外的IOException,冻结所有内容。我不明白为什么我可以毫无问题地发送几个帖子请求,直到出现异常,几乎是随机的。这是我的代码:
public class HttpsClient {
private final static String TAG = "HttpsClient";
private final static String TOKEN_HEADER_KEY = "Token";
private final String urlString;
private SSLContext sslContext;
// application-specific HTTP header
private String TokenHeaderValue = null;
public HttpsClient(String host, String path) {
// this.sslContext will be init'ed in open()
this.urlString = "https://" + host + ":443/" + path;
}
public boolean open() {
try {
this.sslContext = SSLContext.getInstance("TLS");
this.sslContext.init(null, null, new java.security.SecureRandom());
return true;
} catch (NoSuchAlgorithmException e) {
Logger.e(TAG, "NoSuchAlgorithmException:");
} catch (KeyManagementException e) {
Logger.e(TAG, "KeyManagementException:");
}
return false;
}
public byte[] send(byte[] req) {
Logger.d(TAG, "sending " + Utils.byteArrayToString(req) + " to " + this.urlString);
URL url;
try {
url = new URL(this.urlString);
} catch (MalformedURLException e) {
Logger.e(TAG, "MalformedURLException:");
return null;
}
HttpsURLConnection connection;
try {
connection = (HttpsURLConnection) url.openConnection();
} catch (IOException e) {
Logger.e(TAG, "send IOException 1 " + ((null == e.getMessage()) ? e.getMessage() : ""));
e.printStackTrace();
return null;
}
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Connection", "close");
try {
connection.setRequestMethod("POST");
} catch (ProtocolException ignored) { }
connection.setSSLSocketFactory(this.sslContext.getSocketFactory());
connection.setReadTimeout(3000);
if ( this.TokenHeaderValue != null )
connection.setRequestProperty(TOKEN_HEADER_KEY, this.TokenHeaderValue);
{
final Map<String, List<String>> requestProps = connection.getRequestProperties();
Logger.d(TAG, requestProps.size() + " Request header(s):");
for (Map.Entry<String, List<String>> entry : requestProps.entrySet())
for (String value : entry.getValue())
Logger.d(TAG, " " + entry.getKey() + ": <" + value + ">");
}
try {
// open up the output stream of the connection
DataOutputStream output = new DataOutputStream(connection.getOutputStream());
// write out the data
output.write(req, 0, req.length);
output.flush();
Logger.i(TAG, "Response Code: " + connection.getResponseCode());
Logger.i(TAG, "Response Message: " + connection.getResponseMessage());
} catch (SocketTimeoutException e) {
Logger.e(TAG, "SocketTimeoutException:" + ((null == e.getMessage()) ? e.getMessage() : ""));
return null;
} catch (IOException e) { // FAILS HERE !!!!!!!
Logger.e(TAG, "send IOException 2 " + ((null == e.getMessage()) ? e.getMessage() : ""));
return null;
}
final Map<String, List<String>> responseHeaderFields = connection.getHeaderFields();
Logger.d(TAG, responseHeaderFields.size() + " Response header(s):");
for (Map.Entry<String, List<String>> entry : responseHeaderFields.entrySet()) {
final String key = entry.getKey();
if ( (null != key) && key.equals(TOKEN_HEADER_KEY) )
this.TokenHeaderValue = entry.getValue().get(0);
for (String value : entry.getValue())
Logger.d(TAG, " " + key + ": <" + value + ">");
}
// read response
ArrayList<Byte> response = new ArrayList<Byte>();
try {
DataInputStream input = new DataInputStream(connection.getInputStream());
// read in each character until end-of-stream is detected
for( int c = input.read(); c != -1; c = input.read() ) {
response.add((byte) c);
}
Logger.w(TAG, "Https connection is " + connection);
connection.disconnect();
Logger.w(TAG, "Https connection is " + connection);
input.close();
} catch (IOException e) {
Logger.e(TAG, "send IOException 3 " + ((null == e.getMessage()) ? e.getMessage() : ""));
return null;
}
if ( 0 == response.size() ) {
Logger.w(TAG, "response is null");
return null;
}
// else
byte[] result = new byte[response.size()];
for (int i = 0; i < result.length; i++)
result[i] = response.get(i).byteValue();
Logger.i(TAG, "Response payload: " + Utils.byteArrayToString(result));
return result;
}
}
我再说一遍:代码在许多发送后发挥作用,然后崩溃导致IO异常。此外,服务器很好,我的代码有问题。
这是整个错误堆栈跟踪:
send IOException 2
0: org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_read_byte(Native Method)
1: org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.java:783)
2: org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.readLine(HttpURLConnectionImpl.java:671)
3: org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.readResponseHeaders(HttpURLConnectionImpl.java:699)
4: org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getFromNetwork(HttpURLConnectionImpl.java:1088)
5: org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.retrieveResponse(HttpURLConnectionImpl.java:1041)
6: org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:736)
7: org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:146)
8: com.bitstorms.gui.channels.HttpsClient.send(HttpsClient.java:117)
9: com.bitstorms.gui.apps.Application$MyRunnable.run(Application.java:81)
10: java.lang.Thread.run(Thread.java:1020)
答案 0 :(得分:0)
可疑点是你永远不会正确释放流。例如,您创建DataOutputStream output
,使用它,但永远不会关闭。尝试更改使用finally
关闭流的代码:
DataOutputStream output = null;
try {
output = new DataOutputStream(connection.getOutputStream());
...
} catch (...) {
...
} finally {
if (output != null) {
try {
output.close();
} catch (IOException ignored) {}
}
}
同样应该使用DataInputStream input
和connection
本身(在某些全球finally
部分中应保证关闭)。