如何解决从Android发送文件时从WCF服务重置连接
我正在解决连接重置问题,希望有人可以帮助我进行诊断。我们有一个WCF服务,该服务具有接收文件(sqlite数据库)并将其保存到服务器的功能。定期,客户端在上传文件时会收到连接重置异常。
我们从未能够在开发中重现此问题。它仅在生产中发生过,即使在那时也不一致。这将在客户一天发生,但第二天不会发生。我们已经从客户端上手动取下了相同的文件,并将其移至开发中的文件中,以调试将其发送到同一生产服务器,只是使其成功而没有问题。它将在某些生产服务器上发生,但在其他生产服务器上不会发生-再次不一致。
文件相对较小,通常在500kb至10mb之间。
这是服务功能:
[OperationContract]
[WebInvoke(Method = "POST",UriTemplate = "SendData",ResponseFormat = Webmessageformat.Json,RequestFormat = Webmessageformat.Json)]
public GenericObject SendData(Stream data)
{
GenericObject go = new GenericObject();
try
{
string fileName = "SomePathToFile.db";
FileStream fs = new FileStream(fileName,FileMode.Create);
int offset = 0;
byte[] buffer = new byte[16*1024];
while ((offset = databaseStream.Read(buffer,buffer.Length)) != 0)
fs.Write(buffer,offset);
fs.Close();
go.Item = "Send successful";
}
catch (Exception ex)
{
go.Error = "Error sending data\n\n" + ex.Message;
//Do some error logging
...
}
return go;
}
它只是获取文件流并将其本地保存到服务器。如果出现问题,它将返回一个通用的JSON对象,该对象包含成功消息或错误消息。注意:客户端不会取回对象,并且服务器上也不会记录任何异常。
这是Android端发送文件的功能(我们添加了一些重试逻辑以尝试减少错误):
public void sendData(String serviceURL,int attemptNumber)
{
//Declare all streams/disposable objects so that we can reset them if an error occurs
FileInputStream fs = null;
DataOutputStream os = null;
InputStreamReader isr = null;
BufferedReader in = null;
HttpURLConnection conn = null;
boolean connectionResetError = false;
File tempFile = null;
try
{
//Do some stuff to write the db file to the cache directory for temporary storage
tempFile = new File(getCacheDir(),"SomeFile.db");
...
//Open the cache copy of the file for reading
fs = new FileInputStream(tempFile);
//Establish URL to the service
URL url = new URL(serviceURL);
// Open an HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true); // Allow Inputs
conn.setDoOutput(true); // Allow Outputs
conn.setUseCaches(false); // Don't use a Cached copy
conn.setChunkedStreamingMode(1024);
conn.setRequestMethod("POST");
//Tried both of these options based on other Stack Overflow suggestions
//conn.setRequestProperty("Connection","Keep-Alive");
conn.setRequestProperty("Connection","close");
//Open a stream on the connection to write the file
os = new DataOutputStream(conn.getoutputStream());
int bytesRead,bytesAvailable,bufferSize;
byte[] buffer;
int maxBufferSize = 1 * 1024;
//Determine file size and if a buffer is needed
bytesAvailable = fs.available();
bufferSize = Math.min(bytesAvailable,maxBufferSize);
buffer = new byte[bufferSize];
// Read from the file into the buffer
bytesRead = fs.read(buffer,bufferSize);
//Continue reading while there is still more to be read from the file
while (bytesRead > 0)
{
//write the buffer to the connection
os.write(buffer,bufferSize);
//See if there is more to be read from the file and then read
bytesAvailable = fs.available();
bufferSize = Math.min(bytesAvailable,maxBufferSize);
bytesRead = fs.read(buffer,bufferSize);
}
//Get the response and message from the connection
int serverResponseCode = conn.getResponseCode();
String serverResponseMessage = conn.getResponseMessage();
//Flush the output stream
os.flush();
if (serverResponseCode == HttpURLConnection.HTTP_OK)
{
//If response is "OK",read the data that was sent
//Open a reader for the response and buffer it
isr = new InputStreamReader(conn.getInputStream());
in = new BufferedReader(isr);
//String to hold the response
String responseString;
StringBuilder sb = new StringBuilder();
//Read the response
while ((responseString = in.readLine()) != null)
sb.append(responseString);
//Return the response that was read
jResponse = new JSONObject(sb.toString());
}
else
{
//If any other response is received,return the message
response.putString("Error",serverResponseMessage);
}
}
catch(Exception ex)
{
//An error occurred
//Check to see if it's the connection reset error and if we've tried less than 3 times
if(ex instanceof java.net.socketException && ex.getMessage().equals("Connection reset") && attemptNumber < 3)
{
//If so,make a note so we can try again
connectionResetError = true;
}
else
{
//If not,just pass along the error
response.putString("Error",ex.getMessage());
}
}
finally
{
//dispose of everything before we quit or try again
try { if (fs != null) fs.close(); } catch(IOException e){}
try { if (in != null) in.close(); } catch(IOException e){}
try { if (isr != null) isr.close(); } catch(IOException e){}
try { if (os != null) os.close(); } catch(IOException e){}
try { if (conn != null) conn.disconnect(); } catch(Exception e){}
if(tempFile != null && tempFile.exists())
tempFile.delete();
}
//If we're going to try again,do so and increment the attempt number
if(connectionResetError)
{
sendData(serviceURL,attemptNumber+1);
}
}
我们已经在其中一台服务器上设置了Wireshark,以进行调试,但是我对它并不足够了解,以使其有意义。我所知道的是,我看到了请求,正在传输一些数据,然后进行了重置。
您可能有的任何建议或调试指南都将非常有帮助。
解决方法
异常的连接重置通常仅表示该连接已关闭。这可能是由网络问题引起的。建议您在配置文件中设置超时以避免此问题:
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
您可以在客户端启用WCF跟踪,以从错误客户端收集信息。 有关WCF跟踪的详细信息,请参阅本文:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。