Медленная работа и ловля исключений в многопоточной программе - C#

Узнай цену своей работы

Формулировка задачи:

Здравствуйте. Сразу хочу предупредить, что это мой первый проект поэтому судите строго, но не тролльте ) В общем после прочтения нескольких книг, естественно не до конца. Захотелось по быстрее написать что-то рабочее. И недолго думая решил написать многопоточный файл менеджер. И практически сразу наткнулся на две проблемы. 1-ая: Как поймать исключение дочерних потоков в основном потоке ? 2-ая: Почему загрузка файла и сохранение его на диск происходит довольно длительное время? Код либы в которой я качаю и сохраняю файл:
Листинг программы
  1. using System;
  2. using System.Net;
  3. using System.Net.Http.Headers;
  4. using System.Collections.Generic;
  5. using System.Threading;
  6. using System.Net.Mime;
  7. using System.IO;
  8. namespace phttp
  9. {
  10. public class HttpClient
  11. {
  12. protected readonly HttpConfigurator config;
  13. protected readonly Uri uri;
  14. protected Queue<HttpClientRange> queue;
  15. protected List<HttpClientRange> ranges;
  16. protected UInt32 threadsRun = 0;
  17. protected UInt32 threadsFinished = 0;
  18. protected string fileName;
  19. protected string fullFileName;
  20. protected string charSet;
  21. protected long bytesRecieved = 0;
  22. protected long bytesRecievedTotal = 0;
  23. protected long contentLength;
  24. static object locker = new object();
  25. static object filelocker = new object();
  26. public HttpClient(HttpConfigurator config)
  27. {
  28. this.config = config;
  29. if (isValidURL(config.source)) this.uri = new Uri(config.source);
  30. }
  31. public void Run()
  32. {
  33. Thread t = new Thread(_Run);
  34. t.SetApartmentState(ApartmentState.STA);
  35. t.Start();
  36. }
  37. protected void _Run()
  38. {
  39. if (ranges != null)
  40. {
  41. ranges = null;
  42. }
  43.  
  44. WriteLog("Get headers");
  45. WebResponse headResponse = getHeadData(config.source, config.method);
  46. UInt32 threadCount = 1;
  47. if (headResponse.Headers.Get("Accept-Ranges") != "")
  48. {
  49. threadCount = config.threadCount;
  50. }
  51. WriteLog("Check path to file");
  52. fileName = headResponse.ResponseUri.Segments[headResponse.ResponseUri.Segments.Length - 1].Trim();
  53. var contentDispositionString = headResponse.Headers.Get("Content-Disposition");
  54. if (contentDispositionString != null && contentDispositionString.Length > 0)
  55. {
  56. var contentDisposition = ContentDispositionHeaderValue.Parse(contentDispositionString);
  57. if (contentDisposition.FileName.Length > 0)
  58. {
  59. fileName = contentDisposition.FileName;
  60. }
  61. }
  62. var contentTypeString = headResponse.Headers.Get("Content-Type");
  63. if (contentTypeString != null && contentTypeString.Length > 0)
  64. {
  65. var ContentType = new ContentType(contentTypeString);
  66. if (ContentType.MediaType == "text/html")
  67. {
  68. fileName = Common.Fs.ChangeExtension(fileName, ".html");
  69. }
  70. charSet = ContentType.CharSet;
  71. }
  72.  
  73. if (fileName == null || fileName.Length == 0) {
  74. throw new HttpClientException(string.Format("Program cant get filename for {0}", config.source));
  75. }
  76. if (config.savePath == null || config.savePath.Length > 0)
  77. {
  78. fullFileName = Common.Fs.CreateFullFileName(config.savePath, fileName);
  79. }
  80. contentLength = Convert.ToUInt32(headResponse.Headers.Get("Content-Length"));
  81. var contentRangeString = headResponse.Headers.Get("Content-Range");
  82. if (contentRangeString != null && contentRangeString != "")
  83. {
  84. var crhv = ContentRangeHeaderValue.Parse(contentRangeString);
  85. contentLength = (long) crhv.Length;
  86. }
  87. // make segmentation
  88. WriteLog("Make segmentation download data");
  89. UInt32 iterSegment = 0;
  90. queue = new Queue<HttpClientRange>();
  91. if (threadCount == 1)
  92. {
  93. var hcr = new HttpClientRange();
  94. hcr.id = 1;
  95. hcr.start = hcr.stop = hcr.bytes = 0;
  96. queue.Enqueue(hcr);
  97. }
  98. else
  99. {
  100. long start = 0;
  101. long stop = contentLength;
  102.  
  103. do
  104. {
  105. iterSegment++;
  106. if (start > 0) start += 1;
  107. var htr = new HttpClientRange();
  108. htr.start = start;
  109. htr.stop = start + config.segmentBytes;
  110. if (htr.stop > stop) htr.stop = stop;
  111. start = htr.stop;
  112. htr.bytes = config.segmentBytes;
  113. htr.id = iterSegment;
  114. queue.Enqueue(htr);
  115. } while (start < stop);
  116. }
  117.  
  118. ranges = new List<HttpClientRange>();
  119. do
  120. {
  121. if (threadsRun >= threadCount)
  122. {
  123. Thread.Sleep(250);
  124. continue;
  125. }
  126. HttpClientRange segment = queue.Dequeue();
  127. Thread t = new Thread(new ParameterizedThreadStart(Download));
  128. t.SetApartmentState(ApartmentState.STA);
  129. segment.thread = t;
  130. segment.setState(HttpClientRange.STATE_START);
  131. ranges.Add(segment);
  132. t.Start(segment);
  133. lock (locker)
  134. {
  135. threadsRun++;
  136. }
  137. } while (queue.Count > 0);
  138. }
  139.  
  140. protected void Download(object o)
  141. {
  142. HttpClientRange hcr = o as HttpClientRange;
  143. WriteLog(string.Format("Start thread [{0}]", hcr.id));
  144. hcr.setState(HttpClientRange.STATE_START);
  145. HttpWebRequest wr = HttpWebRequest.CreateHttp(uri);
  146. if (hcr.stop > 0)
  147. {
  148. wr.AddRange((int) hcr.start, (int) hcr.stop);
  149. }
  150. wr.Method = config.method;
  151. WebResponse response = wr.GetResponse();
  152. Stream ReceiveStream = response.GetResponseStream();
  153. byte[] buffer = new byte[1024];
  154.  
  155. int bytesRead;
  156. long pos = hcr.start;
  157. while ((bytesRead = ReceiveStream.Read(buffer, 0, buffer.Length)) != 0)
  158. {
  159. write(pos, buffer, bytesRead);
  160. pos += bytesRead;
  161. }
  162. response.Close();
  163. WriteLog(string.Format("Stop thread [{0}]", hcr.id));
  164. hcr.setState(HttpClientRange.STATE_FINISH);
  165. lock (locker)
  166. {
  167. threadsRun--;
  168. }
  169. }
  170.  
  171. public static bool isValidURL(string source)
  172. {
  173. Uri uriResult;
  174. return Uri.TryCreate(source, UriKind.Absolute, out uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
  175. }
  176. public WebResponse getHeadData(string source, string method)
  177. {
  178. if (!isValidURL(source)) throw new HttpClientException("URL is incorrect");
  179. HttpWebRequest wr = HttpWebRequest.CreateHttp(source);
  180. wr.Method = method;
  181. wr.AddRange(0,1);
  182. var wres = wr.GetResponse();
  183. wr.Abort();
  184. wres.Close();
  185. return wres;
  186. }
  187. public void WriteLog(string message)
  188. {
  189. if (config.logManager != null)
  190. {
  191. config.logManager.AddLogText(message);
  192. }
  193. }
  194. protected void write(long pos, byte[] buffer, int bytesRead)
  195. {
  196. lock (filelocker)
  197. {
  198. FileStream outFile = new FileStream(fullFileName, FileMode.OpenOrCreate);
  199. outFile.Seek(pos, SeekOrigin.Begin);
  200. outFile.Write(buffer, 0, bytesRead);
  201. outFile.Close();
  202. }
  203. lock (locker)
  204. {
  205. bytesRecieved += bytesRead;
  206. }
  207. Progress();
  208. }
  209. protected void Progress()
  210. {
  211. if (config.progress != null)
  212. {
  213. config.progress((int)(100*bytesRecieved /contentLength));
  214. }
  215. }
  216. }
  217. public class HttpClientRange
  218. {
  219. public static readonly string STATE_NEW = "new";
  220. public static readonly string STATE_START = "start";
  221. public static readonly string STATE_SUSPEND = "suspend";
  222. public static readonly string STATE_FINISH = "finish";
  223. public UInt32 id;
  224. public long bytes;
  225. public long start;
  226. public long stop;
  227. public readonly Guid guid;
  228. public Thread thread;
  229. public WebClient wc;
  230. protected string _state;
  231. public string state
  232. {
  233. get { return _state; }
  234. }
  235. public HttpClientRange()
  236. {
  237. _state = STATE_NEW;
  238. guid = Guid.NewGuid();
  239. }
  240. public void setState(string state)
  241. {
  242. List<string> list = new List<string>();
  243. list.Add(STATE_NEW);
  244. list.Add(STATE_START);
  245. list.Add(STATE_SUSPEND);
  246. list.Add(STATE_FINISH);
  247. foreach (var item in list)
  248. {
  249. if (item == state)
  250. {
  251. _state = state;
  252. return;
  253. }
  254. }
  255. throw new HttpClientRangeException(string.Format("State {0} is incorrect", state));
  256. }
  257. }
  258. public class HttpClientException : Exception
  259. {
  260. public HttpClientException(string message) : base(message)
  261. {
  262. }
  263. }
  264. public class HttpClientRangeException : Exception
  265. {
  266. public HttpClientRangeException(string message) : base(message) { }
  267. }
  268. }
Листинг программы
  1. using System;
  2. using System.Collections.Generic;
  3. using Loger;
  4. namespace phttp
  5. {
  6. public delegate void Progress(int step);
  7. public class HttpConfigurator
  8. {
  9. public readonly string source;
  10. public readonly string savePath;
  11. public readonly UInt32 threadCount;
  12. public readonly long segmentBytes;
  13. public bool writeToFile = true;
  14. public string charSet;
  15. public LogManager logManager;
  16. public Progress progress;
  17. private Dictionary<string, string> methods;
  18. private string _method = "GET";
  19. public string method
  20. {
  21. set { if (methods.ContainsKey(value)) _method = value; }
  22. get { return _method; }
  23. }
  24.  
  25. public HttpConfigurator(string source, string savePath, UInt32 threadCount, long segmentBytes)
  26. {
  27. this.source = source;
  28. this.savePath = savePath;
  29. this.threadCount = threadCount;
  30. this.segmentBytes = segmentBytes;
  31. methods = new Dictionary<string, string>();
  32. methods.Add("GET", "GET");
  33. methods.Add("POST", "POST");
  34. }
  35. }
  36.  
  37. }
Весь проект целиком

Решение задачи: «Медленная работа и ловля исключений в многопоточной программе»

textual
Листинг программы
  1.         public event ErrorEventHandler ErrorAppeared;
  2.  
  3.         public void Run()
  4.         {
  5.             Thread t = new Thread(_Run);
  6.             t.SetApartmentState(ApartmentState.STA);
  7.             t.Start();
  8.         }
  9.  
  10.         protected void _Run()
  11.         {
  12.             try
  13.             {
  14.                 __Run();
  15.             }
  16.             catch (Exception ex)
  17.             {
  18.                 if (ErrorAppeared != null)
  19.                     ErrorAppeared(null, new ErrorEventArgs(ex));
  20.             }
  21.         }
  22.  
  23.         protected void __Run()
  24.         {
  25.             if (ranges != null)
  26.             {
  27.                 ranges = null;
  28.             }
  29.             .....

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

14   голосов , оценка 4 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут
Похожие ответы