大文件上传(WebException:连接被意外关闭) [英] Big files uploading (WebException: The connection was closed unexpectedly)
问题描述
更新时间:
看帖子<一href="http://stackoverflow.com/questions/1060966/big-files-uploading-webexception-the-connection-was-closed-unexpectedly/1066265#1066265">#3下文。
有必要对自动文件上传到网页(没有浏览器)。主持人 - 迷你文件中的主机V1.2 (如果这确实很重要)。没有找到的文档特有的API,所以起初我嗅了嗅浏览器请求在Firebug如下:
There is a need to upload a file to the web automatically (without browser). Host - Mini File Host v1.2 (if this does matter). Didn't find specific api in documentation, so at first i sniffed browser requests in Firebug as follows :
Params : do
Value : verify
POST /upload.php?do=verify HTTP/1.1
Host: webfile.ukrwest.net
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; ru; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 (.NET CLR 4.0.20506)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://filehoster.awardspace.com/index.php
Content-Type: multipart/form-data; boundary=---------------------------27368237179714
Content-Length: 445
-----------------------------27368237179714
Content-Disposition: form-data; name="upfile"; filename="Test.file"
Content-Type: application/octet-stream
12345678901011121314151617sample text
-----------------------------27368237179714
Content-Disposition: form-data; name="descr"
-----------------------------27368237179714
Content-Disposition: form-data; name="pprotect"
-----------------------------27368237179714--
在这里我们可以看到参数,标题,内容类型和信息块(1 - 文件名和类型,2 - 文件内容,3 - 附加PARAMS - 描述和密码,并不一定适用)。 所以,我创建了一步模拟这种行为步骤类:HttpWebRequest的URL上,用StringBuilder的应用所需的参数,要求,形式请求字符串,并将其转换为字节数组,读取使用的FileStream文件,把所有的东西MemoryStream的,然后写它要求(花的code主要部分从C $的CProject的一篇文章,在$它文件上载到RAPIDSHARE主机)。 干净整洁,但...这似乎并没有工作:(。作为结果返回最初的上传页面,而不是与联系,我可以解析和present给用户的结果页面... 这里有一个上传类的主要方法:
Here we can see parameter, headers, content type and chunks of information (1 - file name and type, 2 - file contents, 3 - additional params - description and password, not necessarily applied). So i've created a class that emulates such a behaviour step by step : HttpWebRequest on the url, apply needed parameters to request, form request strings with StringBuilder and convert them to byte arrays, read a file using FileStream, putting all that stuff to MemoryStream and then writing it to request (took major part of a code from an article at CodeProject where it uploads a file to Rapidshare host). Neat and tidy, but... It doesn't seem to work :(. As result it returns initial upload page, not a result page with links i could parse and present to a user... Here are main methods of an Uploader class :
// Step 1 - request creation
private HttpWebRequest GetWebrequest(string boundary)
{
Uri uri = new Uri("http://filehoster.awardspace.com/index.php?do=verify");
System.Net.HttpWebRequest httpWebRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri);
httpWebRequest.CookieContainer = _cookies;
httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
httpWebRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; ru; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 (.NET CLR 4.0.20506)";
httpWebRequest.Referer = "http://filehoster.awardspace.com/index.php";
httpWebRequest.Method = "POST";
httpWebRequest.KeepAlive = true;
httpWebRequest.Timeout = -1;
//httpWebRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
httpWebRequest.Headers.Add("Accept-Charset", "windows-1251,utf-8;q=0.7,*;q=0.7");
httpWebRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
httpWebRequest.Headers.Add("Accept-Language", "ru,en-us;q=0.7,en;q=0.3");
//httpWebRequest.AllowAutoRedirect = true;
//httpWebRequest.ProtocolVersion = new Version(1,1);
//httpWebRequest.SendChunked = true;
//httpWebRequest.Headers.Add("Cache-Control", "no-cache");
//httpWebRequest.ServicePoint.Expect100Continue = false;
return httpWebRequest;
}
// Step 2 - first message part (before file contents)
private string GetRequestMessage(string boundary, string FName, string description, string password)
{
System.Text.StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("--");
stringBuilder.Append(boundary);
stringBuilder.Append("\r\n");
stringBuilder.Append("Content-Disposition: form-data; name=\"");
stringBuilder.Append("upfile");
stringBuilder.Append("\"; filename=\"");
stringBuilder.Append(FName);
stringBuilder.Append("\"");
stringBuilder.Append("\r\n");
stringBuilder.Append("Content-Type: application/octet-stream");
stringBuilder.Append("\r\n");
return stringBuilder.ToString();
}
// Step 4 - additional request parameters. Step 3 - reading file is in method below
private string GetRequestMessageEnd(string boundary)
{
System.Text.StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(boundary);
stringBuilder.Append("\r\n");
stringBuilder.Append("Content-Disposition: form-data; name=\"descr\"");
stringBuilder.Append("\r\n");
stringBuilder.Append("\r\n");
stringBuilder.Append("Default description");
stringBuilder.Append("\r\n");
stringBuilder.Append(boundary);
stringBuilder.Append("\r\n");
stringBuilder.Append("Content-Disposition: form-data; name=\"pprotect\"");
stringBuilder.Append("\r\n");
stringBuilder.Append("\r\n");
stringBuilder.Append("");
stringBuilder.Append("\r\n");
stringBuilder.Append(boundary);
stringBuilder.Append("--");
//stringBuilder.Append("\r\n");
//stringBuilder.Append(boundary);
//stringBuilder.Append("\r\n");
return stringBuilder.ToString();
}
// Main method
public string ProcessUpload(string FilePath, string description, string password)
{
// Chosen file information
FileSystemInfo _file = new FileInfo(FilePath);
// Random boundary generation
DateTime dateTime2 = DateTime.Now;
long l2 = dateTime2.Ticks;
string _generatedBoundary = "----------" + l2.ToString("x");
// Web request creation
System.Net.HttpWebRequest httpWebRequest = GetWebrequest(_generatedBoundary);
// Main app block - form and send request
using (System.IO.FileStream fileStream = new FileStream(_file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
byte[] bArr1 = Encoding.ASCII.GetBytes("\r\n--" + _generatedBoundary + "\r\n");
// Generating pre-content post message
string firstPostMessagePart = GetRequestMessage(_generatedBoundary, _file.Name, description, password);
// Writing first part of request
byte[] bArr2 = Encoding.UTF8.GetBytes(firstPostMessagePart);
Stream memStream = new MemoryStream();
memStream.Write(bArr1, 0, bArr1.Length);
memStream.Write(bArr2, 0, bArr2.Length);
// Writing file
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
}
// Generating end of a post message
string secondPostMessagePart = GetRequestMessageEnd(_generatedBoundary);
byte[] bArr3 = Encoding.UTF8.GetBytes(secondPostMessagePart);
memStream.Write(bArr3, 0, bArr3.Length);
// Preparing to send
httpWebRequest.ContentLength = memStream.Length;
fileStream.Close();
Stream requestStream = httpWebRequest.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
// Sending request
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
requestStream.Close();
}
// Delay (?)
System.Threading.Thread.Sleep(5000);
// Getting response
string strResponse = "";
using (Stream stream = httpWebRequest.GetResponse().GetResponseStream())
using (StreamReader streamReader = new StreamReader(stream/*, Encoding.GetEncoding(1251)*/))
{
strResponse = streamReader.ReadToEnd();
}
return strResponse;
}
播放与ProtocolVersion(1.0,1.1),AllowAutoRedirect(真/假),即使已知的ServicePoint.Expect100Continue(假)并没有解决问题。即使在一个5秒的超时响应得到(如果不上传这么快,一个大文件的认为)没有帮助。 内容类型八位字节流被选择了目的上传任何文件(可以使用一些开关,最流行的JPG / ZIP / RAR /文档等,但人似乎普遍)。边界是由定时器蜱,没什么大不了的随机生成的。还有什么? :/ 我可以放弃,忘记了这一点,但我觉得我pretty的接近,解决和然后忘了这件事:P。 如果您需要在整个应用程序运行和调试 - 这里是(70KB,压缩C#2.0 VS2k8解决方案,无广告,无病毒):
Plays with ProtocolVersion (1.0, 1.1), AllowAutoRedirect (true/false), even known ServicePoint.Expect100Continue (false) didn't fix an issue. Even a 5sec timeout before getting response (thought in case of a big file it doesn't uploads so quick) didn't help. Content type "octet-stream" was chosen by purpose to upload any file (could use some switch for most popular jpg/zip/rar/doc etc., but that one seems universal). Boundary is generated randomly from timer ticks, not a big deal. What else? :/ I could give up and forget this, but i feel i'm pretty close to solve and then forget about it :P. In case you need the whole application to run and debug - here it is (70kb, zipped C# 2.0 VS2k8 solution, no ads, no viruses) :
@Mediafire @FileQube @FileDropper
推荐答案
更新:没有,没有重定向
Update : nope, there is no redirect.
阅读 RFC2388 几次,改写了code和它最后的工作(我猜麻烦的是在UTF-读到尾的正确的7位ASCII边界代替)。万岁?都能跟得上:(只有小文件的转移,大的抛连接被意外关闭。
Read RFC2388 few times, rewrote the code and it finally worked (i guess the trouble was in utf-read trailing boundary instead of correct 7 bit ascii). Hooray? Nope :(. Only small files are transfered, big ones throwing "The connection was closed unexpectedly".
System.Net.WebException was unhandled by user code
Message="The underlying connection was closed: The connection was closed unexpectedly."
Source="Uploader"
StackTrace:
at Uploader.Upload.ProcessUpload(String FilePath, String description, String password) in F:\MyDocuments\Visual Studio 2008\Projects\Uploader\Uploader.cs:line 96
at Uploader.Form1.backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in F:\MyDocuments\Visual Studio 2008\Projects\Uploader\Form1.cs:line 45
at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
我知道这是与.NET堆栈和几个解决方案存在错误:
I know that's a bug with .net stack and few solutions exists :
1),同时增加超时并要求ReadWriteTimeout
1) increase both Timeout and ReadWriteTimeout of request
2)分配request.KeepAlive =虚假和System.Net.ServicePointManager.Expect100Continue = FALSE
2) assign request.KeepAlive = false and System.Net.ServicePointManager.Expect100Continue = false
3)设置ProtocolVersion到1.0 但他们也不是所有的人的没有一个完全帮助我的情况。任何想法?
3) set ProtocolVersion to 1.0 But neither one of them nor all of them altogether help in my case. Any ideas?
修改 - 源$ C $ C:
EDIT - Source code:
// .. request created, required params applied
httpWebRequest.ProtocolVersion = HttpVersion.Version10; // fix 1
httpWebRequest.KeepAlive = false; // fix 2
httpWebRequest.Timeout = 1000000000; // fix 3
httpWebRequest.ReadWriteTimeout = 1000000000; // fix 4
// .. request processed, data written to request stream
string strResponse = "";
try
{
using (WebResponse httpResponse = httpWebRequest.GetResponse()) // error here
{
using (Stream responseStream = httpResponse.GetResponseStream())
{
using (StreamReader streamReader = new StreamReader(responseStream))
{
strResponse = streamReader.ReadToEnd();
}
}
}
}
catch (WebException exception)
{
throw exception;
}
这篇关于大文件上传(WebException:连接被意外关闭)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!