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必须连续编码吗?

解决方案 »

  1.   

    主要是多线程的内存问题。
    很简单的,不要往其他方向想。
    可能我没有建立内存拷贝,所以如此吧。 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线程安全发现的问题。
    不知道哪位可以解答一下。
      

  2.   

    在httpClient组件内部,我没有建立内存拷贝,直接使用的是httpResponse 实例变量,多线程的时候,就会出现问题。
    我分析是这样的,看样子还得读一些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]
      

  3.   

    public event ReceiveDataHandler OnReceiveData;直接挂载事件进行下载。=================================================
    同一个文件属于单线程,但是发现每个文件都是不完整。
    分开不行,但是合并可以,文件完整。