C#在线程主函数里面调用和分开调用的结果不同为什么。
我在写下载的代码httpRequest,httpResponse下下载的功能,采用多线程的。
public class Download : BaseObject
{
..... //============================
public Download(DownloadPool manager)
{
this.lockObject = new object();
this.mManager = manager;
}
#endregion #region 线程下载处理
/// <summary>
/// 开始线程处理
/// </summary>
public void Start()
{
//开始启动线程
this._Thread = new Thread(new ThreadStart(DoWork));
this._Thread.IsBackground = false;
this._Thread.Start(); while (!_Thread.IsAlive) ;
}
/// <summary>
/// 执行读取线程方法
/// </summary>
private void DoWork()
{
string urlPath = path1;
string localFile = path2; try
{
//发请求A【A】
Uri url = new Uri(urlPath);
HttpWebRequest mRequest = (HttpWebRequest)WebRequest.Create(url);
mRequest.Method = "GET";
mRequest.ContentType = "application/x-www-form-urlencoded"; HttpWebResponse httpResponse = (HttpWebResponse)mRequest.GetResponse();
//下载图像【B】
using (Stream responseStream = httpResponse.GetResponseStream())
{
using (FileStream localFileStream = new FileStream(localFile, FileMode.Create))
{
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
//totalBytesRead += bytesRead;//可以绘制进度,此处保留,后期升级使用。
localFileStream.Write(buffer, 0, bytesRead);
}
}
} this.DocPage.DataState = DataState.Normal;
this.DoCompleteEvent(new CompleteEventArgs(true)); }
catch (Exception ex)
{
this.DoCompleteEvent(new CompleteEventArgs(false));
Workspace.log.Debug("下载过程中产生错误,错误代码:" + ex.Message);
} //return result;
}
#endregion }我把下载放在DoWork里面正常下载,如果我把DoWork里面的 【见代码注释】分开,把【A】和【B】两个部分放在心的类httpClient 里面两个方法,做成了个方法,形如:
private void DoWork()
{
httpClient client=new HttpClient(xxxx);
httpClient.Get(url);
httpClient.OnData=>(o,e)=>
{
这里接受流,并且保存文件。
}
}结果下载就不正常,为什么??文件成半个。
结果我又试过将httpClient的两个发送方法和接受方法不分开,结果也不正常。难道线程里面的DoWork必须连续编码吗?
我在写下载的代码httpRequest,httpResponse下下载的功能,采用多线程的。
public class Download : BaseObject
{
..... //============================
public Download(DownloadPool manager)
{
this.lockObject = new object();
this.mManager = manager;
}
#endregion #region 线程下载处理
/// <summary>
/// 开始线程处理
/// </summary>
public void Start()
{
//开始启动线程
this._Thread = new Thread(new ThreadStart(DoWork));
this._Thread.IsBackground = false;
this._Thread.Start(); while (!_Thread.IsAlive) ;
}
/// <summary>
/// 执行读取线程方法
/// </summary>
private void DoWork()
{
string urlPath = path1;
string localFile = path2; try
{
//发请求A【A】
Uri url = new Uri(urlPath);
HttpWebRequest mRequest = (HttpWebRequest)WebRequest.Create(url);
mRequest.Method = "GET";
mRequest.ContentType = "application/x-www-form-urlencoded"; HttpWebResponse httpResponse = (HttpWebResponse)mRequest.GetResponse();
//下载图像【B】
using (Stream responseStream = httpResponse.GetResponseStream())
{
using (FileStream localFileStream = new FileStream(localFile, FileMode.Create))
{
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
//totalBytesRead += bytesRead;//可以绘制进度,此处保留,后期升级使用。
localFileStream.Write(buffer, 0, bytesRead);
}
}
} this.DocPage.DataState = DataState.Normal;
this.DoCompleteEvent(new CompleteEventArgs(true)); }
catch (Exception ex)
{
this.DoCompleteEvent(new CompleteEventArgs(false));
Workspace.log.Debug("下载过程中产生错误,错误代码:" + ex.Message);
} //return result;
}
#endregion }我把下载放在DoWork里面正常下载,如果我把DoWork里面的 【见代码注释】分开,把【A】和【B】两个部分放在心的类httpClient 里面两个方法,做成了个方法,形如:
private void DoWork()
{
httpClient client=new HttpClient(xxxx);
httpClient.Get(url);
httpClient.OnData=>(o,e)=>
{
这里接受流,并且保存文件。
}
}结果下载就不正常,为什么??文件成半个。
结果我又试过将httpClient的两个发送方法和接受方法不分开,结果也不正常。难道线程里面的DoWork必须连续编码吗?
很简单的,不要往其他方向想。
可能我没有建立内存拷贝,所以如此吧。 using (Stream responseStream = httpResponse.GetResponseStream())
{
using (FileStream localFileStream = new FileStream(localFile, FileMode.Create))
{
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
//totalBytesRead += bytesRead;//可以绘制进度,此处保留,后期升级使用。
localFileStream.Write(buffer, 0, bytesRead);
}
}
}
this.DocPage.DataState = DataState.Normal;
this.DoCompleteEvent(new CompleteEventArgs(true));我在看Servlet线程安全发现的问题。
不知道哪位可以解答一下。
我分析是这样的,看样子还得读一些JAVA Servlet的图书才能知道。 一下是httpClient组件源代码。
估计问题就是出现在多线程的时候,httpResponse 没有复制一个新的拷贝所有,通过事件获得流就出现半个,或者数据不全。
[code=csharp]using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;namespace XXXXX.Core
{
public class HttpClient :BaseObject
{
#region --- 内部成员声明---
protected HttpWebResponse _response;
protected HttpWebRequest _request;
private bool _isThrowException=true; #endregion
#region --- 公开属性声明--- ///省略其他属性。 public HttpWebRequest Request
{
get { return _request;}
set { _request = value;}
} public HttpWebResponse Response
{
get { return _response; }
set { _response = value; }
} /// <summary>
/// 是否扔出异常
/// </summary>
public bool IsThrowException
{
get { return _isThrowException; }
set { _isThrowException = value; }
}
#endregion #region --- 委托事件声明---
public event ReceiveDataHandler OnReceiveData;
public event PostResponseHandler OnPostResponse;
public event PreRequestHandler OnPreRequest;
public event HttpClientErrorHandler OnHttpClientError;
#endregion #region --- 构造解构方法---
public HttpClient()
{
this._userAgent ="West Wind HTTP .NET";
this._maxTimeout = 30;
this._packTimeout = -1;//默认不设置此时间
this._isThrowException = true;
} #endregion #region --- 核心事件及方法 ----
/// <summary>
/// 获得当前的编码格式
/// </summary>
/// <param name="contentType"></param>
/// <returns></returns>
public static Encoding GetEncoding(string contentType)
{
//省略;
}
/// <summary>
/// 设置请求参数信息
/// </summary>
protected void HandleRequest()
{
。;省略;
} /// <summary>
/// 设置响应参数信息
protected void HandleRespose()
{
。;省略;
} //------------相关重载操作-----
/// <summary>
/// 接收返回字符串
/// </summary>
/// <returns></returns>
protected string ReceiveDataString()
{
var ret = "";
if (this.Response == null) return ret; if (this.Response.StatusCode == HttpStatusCode.OK)
{
var encoding = GetEncoding(this.Response.ContentType);//获取返回的消息编码
StreamReader sr = new StreamReader(this.Response.GetResponseStream(), encoding); ret = sr.ReadToEnd();
sr.Close();
}
else
{
throw new Exception(Response.StatusDescription);
} if (this.Response != null)
{
this.Response.Close();
} return ret;
} /// <summary>
/// 接收数据事件
/// </summary>
/// <param name="stream">写入的流</param>
/// <param name="BufferSize">每次写入的缓存大小</param>
protected void ReceiveDataEvents(Stream stream, int BufferSize = 1024)
{
var responseStream = this.Response.GetResponseStream(); ReceiveDataEvents(responseStream, stream, BufferSize);
} /// <summary>
/// 接收数据事件
/// </summary>
/// <param name="stream"></param>
/// <param name="BufferSize"></param>
protected void ReceiveDataEvents(Stream responseStream, Stream stream, int BufferSize = 1024)
{
【!!!!此处多线程,接收的流出现问题,是不是没有对流做拷贝?】?
//获取流的总长度
long totalSize = BufferSize;
if (this.Response.ContentLength > 0)
totalSize = this.Response.ContentLength;
else
totalSize = 0; //初始化变量
byte[] buffer = new byte[BufferSize];//每次读取的大小
long readByteSize = 0;//读取的字节计数器
int readBytes = 0; //当前读取的字节
ReceiveDataEventArgs args = new ReceiveDataEventArgs();
while ((readBytes = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
readByteSize += readBytes;
stream.Write(buffer, 0, readBytes); //执行事件
if (this.OnReceiveData != null)
{
args._readByteSize = readByteSize;
args._totalSize = totalSize;
args._buffer = buffer; this.OnReceiveData(this, args);
if (args.Cancle)
{
goto CloseDown;//跳转到关闭
}
}
} //JMP到此处
CloseDown:
this.Response.Close(); if (this.OnReceiveData != null && !args.Cancle)
{
args._done = true;
//重新处理消息
this.OnReceiveData(this, args);
}
} #endregion #region --- HTTP动作(GET,POST,PUT等)实现---
//由于CSDN输入受限;省略GET,PUT方法。
/// <summary>
/// 通过Post提交表单
/// </summary>
/// <param name="uri">跟地址</param>
/// <param name="form"> 表单</param>
/// <param name="proxy">代理服务器</param>
/// <param name="creds">SSL证书</param>
/// <returns></returns>
protected bool Post(Uri uri, FormContent form)
{
try
{
this._request = (HttpWebRequest)(WebRequest.Create(uri));
this._request.Method = HttpMethod.POST.ToString();
this.HandleRequest();//设置代理和证书接口
if (OnPreRequest != null)
OnPreRequest(this, new EventArgs()); form.PrepareData();//开始准备表单数据
this._request.ContentType = form.GetContentType();
this._request.ContentLength = form.PostStream.Length;
this._request.Timeout = CalcTimeout(form.PostStream.Length);//设置超时时间
//开始写入请求流
Stream requestStream = this._request.GetRequestStream();
form.PostStream.WriteTo(requestStream); form.Close();//关闭流
requestStream.Close(); this._response = (HttpWebResponse)this._request.GetResponse();
HandleRespose();
if (OnPostResponse != null)
OnPostResponse(this, new EventArgs());
return true;
}
catch (Exception e)
{
if (IsThrowException)
{
throw e;
}
else
{
if (OnHttpClientError != null)
OnHttpClientError(this, new HttpClientErrorArgs(e));
return false;
}
} }
/// <summary>
/// 重载的POST,支持流监听事件
/// </summary>
/// <param name="uriString"></param>
/// <param name="form"></param>
/// <param name="fileName"></param>
public void PostWithEvent(string uriString, FormContent form, string fileName)
{
SetSSL(uriString);
if (Post(new Uri(uriString), form))
{
using (FileStream localFileStream = new FileStream(fileName, FileMode.Create))
{
ReceiveDataEvents(localFileStream);
}
}
}}[/code]
同一个文件属于单线程,但是发现每个文件都是不完整。
分开不行,但是合并可以,文件完整。