Mac OS X上的Mono - 并行HTTP下载限制为2

时间:2012-03-14 17:19:59

标签: c# multithreading macos http mono

我正在使用Mono开发一个可以同时下载多个文件的程序(适用于Mac OS X和Debian)。

但是我只能同时下载2个文件,尽管我使用构造函数new RollingDownload(10)。我正在使用的代码就是这个

using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Threading;
using System.Net;
using System.Diagnostics;
using System.IO;
namespace worker
{
    public class RollingDownload
    {
        private static ConcurrentQueue<Download> _downloads = new ConcurrentQueue<Download>();
        private static short _NumberOfThreads;
        private static short DefaultTimeoutSeconds = 20;
        public RollingDownload (short NumberOfThreads)
        {
            _NumberOfThreads = NumberOfThreads;
        }

        public void addDownload(Download download) {
            _downloads.Enqueue(download);
        }
        public void SpawnWebRequests()
        {
            ServicePointManager.DefaultConnectionLimit = _NumberOfThreads;
            ServicePointManager.MaxServicePoints = _NumberOfThreads;
            IList<Thread> threadList = new List<Thread>();

            for (int i = 0; i < _NumberOfThreads; i++)
            {
                var thread = new Thread(ProcessWebRequests);
                threadList.Add(thread);
                thread.Start();
            }

            for (int i = 0; i < _NumberOfThreads; i++)
            {
                threadList[i].Join();
            }
        }

        private static void ProcessWebRequests()
        {
            while (true)
            {
                Download download;
                Console.WriteLine (Thread.CurrentThread.ManagedThreadId);
                if(_downloads.TryDequeue(out download)) {
                    ProcessWebRequest(download);
                } else {
                    break;
                }
            }
        }

        private static void ProcessWebRequest(Download download)
        {
            try
            {
                var request = (HttpWebRequest)WebRequest.Create(download.Url);
                request.Method = "GET"; // or "GET", since some sites (Amazon) don't allow HEAD
                request.Timeout = DefaultTimeoutSeconds * 1000;
                request.AllowAutoRedirect = true;
                //request.ServicePoint.ConnectionLimit = _NumberOfThreads;
                request.KeepAlive = false;
                //request.ServicePoint = ServicePointManager.FindServicePoint(new Uri(download.Url));
                // Get the response (throws an exception if status != 200)
                using (var response = (HttpWebResponse)request.GetResponse())
                {
                    if (response.StatusCode == HttpStatusCode.OK) {
                        /*string contents = "";
                        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                        {
                            contents = reader.ReadToEnd();
                        }*/
                        download.onCompleted(response.GetResponseStream(), response.StatusCode);
                    }
                }
            }
            catch (WebException ex)
            {
                var response = ((HttpWebResponse)ex.Response);
                var status = response != null
                                 ? response.StatusCode
                                 : HttpStatusCode.RequestTimeout;

                Console.WriteLine(String.Format("Broken link ({0}): {1}", status, download.Url), ex);

                // Don't rethrow, as this is an expected exception in many cases
            }
            catch (Exception ex)
            {
                Console.WriteLine(String.Format("Error processing link {0}", download.Url), ex);

                // Rethrow, something went wrong
                throw;
            }
        }
    }
public class Download
    {
        public string Url { get; set; }

        public string PathToSave { get; set; }

        public Download (String Url)
        {
            this.Url = Url;
        }

        public void onCompleted (Stream response, HttpStatusCode httpcode)
        {
            Console.WriteLine ("hello everybody: " + httpcode.ToString ());
        }
    }
}

我不知道。 #mono IRC频道中的某个人意味着,我应该使用this ticket来解决问题,但我不知道在哪里找到machine.config或如何在monodevelop中添加它。

我正在开发的应用程序是使用C#的控制台应用程序(无ASP!)。

很高兴收到你们的来信。

1 个答案:

答案 0 :(得分:3)

您的下载是否来自同一主机?如果是,则需要向RollingDownload(或其他初始化代码)的构造函数添加一些代码:

string downloadHost = ...;
ServicePoint sp = ServicePointManager.FindServicePoint(new Uri(downloadHost));
sp.ConnectionLimit = _NumberOfThreads;

[感谢this blog早些时候帮助我解决类似问题。]