我制作了一个Windows服务,上传了放入文件夹的所有文件(图片)。
ftp工作异步,基于msdn代码。
一切正常,直到我拔下网线。
ftp方法应该捕获错误并返回false bool。然后我将文件移动到一个失败的文件夹,然后继续下一个文件。 到达第3个文件时,WaitOne操作永远不会停止,并且永远不会到达EndGetStreamCallback。我真的不知道发生了什么。 在此之后,服务也会变得无法响应,直到我重新启动它。
文件处理程序:
string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
AsynchronousFtpUpLoader ftp = new AsynchronousFtpUpLoader();
foreach (string file in files) {
var result = ftp.Upload(ConfigurationManager.AppSettings["ftp_host"] + ConfigurationManager.AppSettings["ftp_path"] + file.Replace(path, "").Substring(1), file);
if (!result) {
return false;
}
}
AsynchronousFtpUpLoader:
public class AsynchronousFtpUpLoader
{
public bool Upload(string sTarget,string file)
{
bool succeed = false;
// Create a Uri instance with the specified URI string.
// If the URI is not correctly formed, the Uri constructor
// will throw an exception.
ManualResetEvent waitObject;
Uri target = new Uri(sTarget);
string fileName = file;
FtpState state = new FtpState();
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(target);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(ConfigurationManager.AppSettings["ftp_user"], ConfigurationManager.AppSettings["ftp_password"]);
// Store the request in the object that we pass into the
// asynchronous operations.
state.Request = request;
state.FileName = fileName;
// Get the event to wait on.
waitObject = state.OperationComplete;
// Asynchronously get the stream for the file contents.
request.BeginGetRequestStream(
new AsyncCallback(EndGetStreamCallback),
state
);
// Block the current thread until all operations are complete.
waitObject.WaitOne();
// The operations either completed or threw an exception.
if (state.OperationException != null)
{
Log.writeLog("ERROR","FTP error", sTarget.Substring(0, sTarget.IndexOf("_")).Substring(sTarget.LastIndexOf("\\") + 1), sTarget);
Log.writeError(state.OperationException.ToString() + (state.OperationException.InnerException != null ? state.OperationException.InnerException.ToString() : ""), sTarget);
//throw state.OperationException;
}
else
{
succeed = true;
Console.WriteLine("The operation completed - {0}", state.StatusDescription);
}
return succeed;
}
private static void EndGetStreamCallback(IAsyncResult ar)
{
FtpState state = (FtpState)ar.AsyncState;
Stream requestStream = null;
// End the asynchronous call to get the request stream.
try
{
Console.WriteLine("Opened the stream");
using(requestStream = state.Request.EndGetRequestStream(ar)){
// Copy the file contents to the request stream.
const int bufferLength = 2048;
byte[] buffer = new byte[bufferLength];
int count = 0;
int readBytes = 0;
using (FileStream stream = File.OpenRead(state.FileName))
{
do
{
readBytes = stream.Read(buffer, 0, bufferLength);
requestStream.Write(buffer, 0, readBytes);
count += readBytes;
}
while (readBytes != 0);
Console.WriteLine("Writing {0} bytes to the stream.", count);
// IMPORTANT: Close the request stream before sending the request.
requestStream.Close();
stream.Close();
}
}
Console.WriteLine("Closed the stream");
// Asynchronously get the response to the upload request.
state.Request.BeginGetResponse(
new AsyncCallback(EndGetResponseCallback),
state
);
}
// Return exceptions to the main application thread.
catch (Exception e)
{
Console.WriteLine("Could not get the request stream.");
state.OperationException = e;
state.OperationComplete.Set();
if (requestStream != null) {
requestStream.Close();
}
return;
}
}
// The EndGetResponseCallback method
// completes a call to BeginGetResponse.
private static void EndGetResponseCallback(IAsyncResult ar)
{
FtpState state = (FtpState)ar.AsyncState;
FtpWebResponse response = null;
try
{
response = (FtpWebResponse)state.Request.EndGetResponse(ar);
response.Close();
state.StatusDescription = response.StatusDescription;
// Signal the main application thread that
// the operation is complete.
state.OperationComplete.Set();
}
// Return exceptions to the main application thread.
catch (Exception e)
{
Console.WriteLine("Error getting response.");
state.OperationException = e;
state.OperationComplete.Set();
if (response != null) {
response.Close();
}
}
}
}
答案 0 :(得分:0)
有同样的问题。代码基于相同的MSDN示例,但已增强,可通过SSL / TLS工作。 文件可以成功上传数小时或数天,但有时会挂在互联网连接不良的环境中 - 主线程永远被阻止。 使用http://jagt.github.io/clumsy/重现问题并对其进行调试。看来,当上传字节完成时,我们坚持在这里关闭请求流
// IMPORTANT: Close the request stream before sending the request.
requestStream.Close();
当我们调用它时,FtpWebRequest关闭上传连接并等待操作完成。就FtpWebRequest而言,stage必须更改为ReleaseConnection。当FTP服务器通过控制通道发送消息,上传完成时(当我们关闭二进制连接时),完成此阶段更改。出于某种原因,它从未发生过。可能是由于网络错误ftp客户端没有从服务器接收消息并且永远等待。
可能的解决方案: