Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
lan143
0 / 0 / 0
Регистрация: 10.12.2012
Сообщений: 15
1

HttpWebRequest.GetResponse не работает в потоке

30.12.2013, 14:45. Просмотров 1380. Ответов 4
Метки нет (Все метки)

Здравствуйте. Написал класс для загрузки файлов с поддержкой простой докачки. Выглядит он вот так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
 
namespace BlizzUpdateServerDownloader
{
    public class DownloadProgressChangedArgs
    {
        protected string filename;
        public string FileName
        {
            get { return filename; }
        }
 
        protected uint progress_percentage;
        public uint ProgressPercentage
        {
            get { return progress_percentage; }
        }
 
        public DownloadProgressChangedArgs(String Filename, uint Progress_percentage)
        {
            this.filename = Filename;
            this.progress_percentage = Progress_percentage;
        }
    }
    public class DownloadFileCompletedArgs
    {
        protected string filename;
        public string FileName
        {
            get { return filename; }
        }
 
        public DownloadFileCompletedArgs(String Filename)
        {
            this.filename = Filename;
        }
    }
    public class DownloadFileErrorArgs
    {
        protected string filename;
        protected Exception e;
        public string FileName
        {
            get { return filename; }
        }
        public Exception Error
        {
            get { return e; }
        }
 
        public DownloadFileErrorArgs(String Filename, Exception error)
        {
            this.filename = Filename;
            this.e = error;
        }
    }
 
    class InovationFileDownloader
    {
        public delegate void DownloadProgressChangedHandler(object sender, DownloadProgressChangedArgs e);
        public delegate void DownloadFileCompletedHandler(object sender, DownloadFileCompletedArgs e);
        public delegate void DownloadFileErrorHandler(object sender, DownloadFileErrorArgs e);
        public event DownloadProgressChangedHandler ProgressChanged;
        public event DownloadFileCompletedHandler FileCompleted;
        public event DownloadFileErrorHandler FileError;
 
        private const long fragment_size = 10 * 1024;
 
        private string url;
        private string filename;
        private long length;
        private long position;
        private long totalBytesRead;
 
        public long TotalBytesRead { get { return totalBytesRead; } }
        public long Length { get { return length; } }
        public long Position
        {
            get
            {
                return position;
            }
            set
            {
                if (value < 0) throw new ArgumentException();
                position = value;
            }
        }
        public InovationFileDownloader(string URL, string Filename)
        {
            url = URL;
            filename = Filename;
        }
 
        public void StartDownload()
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            HttpWebResponse result = (HttpWebResponse)request.GetResponse();
            length = result.ContentLength;
 
            using (FileStream fs = new FileStream(filename, FileMode.Append))
            {
                totalBytesRead = fs.Length;
                Position = fs.Length;
 
                while (TotalBytesRead < Length)
                {
                    try
                    {
                        int receivedLengh = 0;
                        if (TotalBytesRead + fragment_size < Length)
                            receivedLengh = (int)fragment_size;
                        else
                            receivedLengh = (int)(Length - TotalBytesRead);
 
                        byte[] buffer = new byte[receivedLengh];
                        int count = Read(buffer, 0, receivedLengh);
 
                        OnProgressChanged();
                        fs.Write(buffer, 0, count);
                    }
                    catch (Exception e)
                    {
                        OnFileError(e);
                    }
                }
 
                fs.Close();
            }
 
            OnDownloadComplete();
        }
 
        private int Read(byte[] buffer, int offset, int count)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.AddRange(Convert.ToInt32(position), Convert.ToInt32(position) + count);
            HttpWebResponse result = (HttpWebResponse)request.GetResponse();
 
            int readbytes = 0;
 
            using (Stream stream = result.GetResponseStream())
            {
                readbytes = stream.Read(buffer, offset, count);
                stream.Close();
            }
            result.Close();
            totalBytesRead += readbytes;
            Position += readbytes;
            return readbytes;
        }
 
        protected void OnProgressChanged()
        {
            if (ProgressChanged != null)
            {
                uint percents = (uint)((float)totalBytesRead / (float)Length * 100.0);
                ProgressChanged(this, new DownloadProgressChangedArgs(filename, percents));
            }
        }
 
        protected void OnDownloadComplete()
        {
            if (FileCompleted != null)
            {
                FileCompleted(this, new DownloadFileCompletedArgs(filename));
            }
        }
 
        protected void OnFileError(Exception e)
        {
            if (FileError != null)
            {
                FileError(this, new DownloadFileErrorArgs(filename, e));
            }
        }
    }
}
Когда я просто создаю объект этого класса и качаю какой-либо файл, то все идет нормально. Но стоит мне создать объект в потоке, и начать качать файл, то закачка не происходит. Зависает на GetResponse в методе Read, а после возвращает исключение с текстом: Время ожидания операции истекло.

Вот так я создаю тред:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        void StartDownloadFile(object filename)
        {
            if (outputBox.InvokeRequired)
                this.outputBox.BeginInvoke(new Action(() => outputBox.AppendText("Start download " + (string)filename + "\r\n")));
            else
                outputBox.AppendText("Start download " + (string)filename + "\r\n");
 
            InovationFileDownloader iw = new InovationFileDownloader(base_path + (string)filename, (string)filename);
            iw.ProgressChanged += iw_ProgressChanged;
            iw.FileCompleted += iw_FileCompleted;
            iw.FileError += iw_FileError;
            iw.StartDownload();
        }
 
        void StartDownloadThread(string filename)
        {
            Thread t = new Thread(new ParameterizedThreadStart(StartDownloadFile));
            t.Start(filename);
            threadList.Add(t);
        }
Подскажите, что может быть не так?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.12.2013, 14:45
Ответы с готовыми решениями:

HTTPWebRequest.GetResponse() возвращает WebException
Здравствуйте. Возникла еще одна проблема у меня. Есть многопоточное приложение...

ProgressBar не работает в потоке
Сразу оговорю, что короткие фразы вроде &quot;юзай BackgroundWorker&quot; и т.д. -...

Не работает try catch в потоке
....{ Thread accountActivateThread = new Thread(delegate() {...

GetRequestStream не работает в отдельном потоке
Вот код Uri адрес = new Uri(данные.ToString()); HttpWebRequest...

Обход ошибки 404 GetResponse()?
Воспрос такой. У меня проходит ntml авторизаци. Но url на который я ссылаюсь...

4
Fynivx
9 / 9 / 0
Регистрация: 13.08.2011
Сообщений: 41
30.12.2013, 15:33 2
Проблемы тут могут быть самые разные - в т.ч. в STL.
Очевидные варианты решения:

1) Использовать GetResponseAsync вместо самостоятельного запуска в другом потоке
2) Вообще отказаться от устаревшего HttpWebRequest в пользу HttpСlient. Последний, насколько я помню, работает в потоках нормально.
0
lan143
0 / 0 / 0
Регистрация: 10.12.2012
Сообщений: 15
31.12.2013, 01:12  [ТС] 3
1) Использовать GetResponseAsync вместо самостоятельного запуска в другом потоке
Переписал, все тоже самое.
2) Вообще отказаться от устаревшего HttpWebRequest в пользу HttpСlient. Последний, насколько я помню, работает в потоках нормально.
Переписал алгоритм работы программы для консольного приложения, без потоков. Все так же первый файл со списком качает нормально, а остальных такие же зависания.

Добавлено через 9 часов 37 минут
В общем в потоках заставить работать так и не получилось, но получилось заставить работать без потоков. Теперь возникла проблема немного другого плана. В месте, где я запрашиваю кусок данных от сервера мне постоянно возвращается поток размером в 3716 байт (это если запрошенный блок был размером больше этого значения). Причем я проверял снифером во время работы приложения - сервер возвращает положенный по размеру кусок данных. Отсюда возникает вопрос: как можно получать то кол-во байт, что я запрашивал? А то приложение не получается разогнать, качает не больше 20 кбайт/с при интернет соединении в 3 мбита.
0
Fynivx
9 / 9 / 0
Регистрация: 13.08.2011
Сообщений: 41
02.01.2014, 12:34 4
Цитата Сообщение от lan143 Посмотреть сообщение
Все так же первый файл со списком качает нормально, а остальных такие же зависания.
Так, вроде, речь немного о другой проблеме шла. Нет?

Цитата Сообщение от lan143 Посмотреть сообщение
получилось заставить работать без потоков
Так как именно работает? С тасками или с GetResponse?

Цитата Сообщение от lan143 Посмотреть сообщение
постоянно возвращается поток размером в 3716 байт
Пробовали на разных серверах или только на одном?
0
Wolfdp
857 / 770 / 198
Регистрация: 15.06.2012
Сообщений: 3,000
Записей в блоге: 1
Завершенные тесты: 1
02.01.2014, 14:55 5
Странно, у меня первоначальный метод прекрастно отработал. Ниже пример ваше исходника на формах. Вот только сам метод...

- в цикле постоянно создается буфер для приема/записи. Учитывая что некоторые сервисы выдаю тне 10240, а ~4096, это довольно тормозит работу. Буфер можно задать и больше, главное не пересоздавать его на каждой итерации. Я бы сделал вот так...
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
                byte[] buffer = new byte[4096];
                while (TotalBytesRead < Length)
                {
                    try
                    {
                        int count = Read(buffer, 0, buffer.Length);
                        OnProgressChanged();
                        fs.Write(buffer, 0, count);
                    }
                    catch (Exception e)
                    {
                        OnFileError(e);
                    }
                }
- Финальны метод вашей "либы" InovationFileDownloader, точнее способ передачи откуда грузить и куда грузить. Нужно разделить эти два файла (то есть в конструктор пердавать источкик и назначение), а уже на верхнем уровне настраивать имена. Так более проще использовать.

- возмите за правило все even наследовать от EventHandler или использовать EventHandler <T>. Это позволяет вешать один и тот же обработчик на разные события.

- вместо
C#
1
2
        private long length;
        public long Length { get { return length; } }
лучше писать
C#
1
public long Length { get; private set; }
Так код становится более читаемый.

P.S. не серчайте, на работе выдался перерыв, решил скоротать за вашим вопросом.
1
Вложения
Тип файла: zip Testdownload.zip (3.04 Мб, 8 просмотров)
02.01.2014, 14:55
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.01.2014, 14:55

Игнорировать 400 Bad Request в HttpWebResponse.GetResponse();
В запросе на узел используется сертификат(p.12)и подключение по SSH\TLS. Так...

Работа с Dictionary в одном потоке, при этом он может изменятся в другом потоке
Здравствуйте! Я делаю лабу сервер распределенных вычислений в сети. В одном...

Создать приложение, в отдельном потоке вычисляющее значение w и непрерывно обновляющее его в потоке
Ребят, с потоками не работал не когда. Есть задание , я понимаю что хотят, а...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru