SslStream отдельная тема
Я пытаюсь отобразить на экране любые данные, которые поступают из потока ssl (с веб-сайта). Поскольку я не знаю, когда поступят данные, я использовал другой поток, который продолжает чтение из потока до тех пор, пока не будут прочитаны байты. Это работает отлично, однако, загрузка моего процессора увеличивается до 25% и остается там (это 1 поток при максимальном использовании, мой компьютер имеет 4 потока). Хотя это имеет смысл, поскольку поток застрял в цикле while, я не ожидал, что экземпляр класса Thread будет занимать весь поток моего ЦП (я могу поклясться, что этого не произошло при использовании простого Client/ Серверное приложение).
Поток начинает работать, как только соединение инициализируется, пользователь может отправлять данные на веб-сайт в любое время, когда он хочет, и приложение должно распечатать ответ. Каковы альтернативные решения для этого? Должен ли я отказаться от SslStream и начать использовать что-то еще?
Вот код, который выполняется в этом отдельном потоке:
void ReadDataAsync(Object obj) {
byte[] buffer = new byte[65536]; //65536, make sure all bytes can be
//from a single packet
int bytesRead = -1;
while (true) {
//It makes sense for sslStream.Read to block until bytes have been
//read, but it doesn't. Which is why I'm checking if bytesRead!=0
bytesRead = sslStream.Read(buffer, 0, 65536);
if (bytesRead != 0) {
Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, bytesRead));
buffer = new byte[65536];
}
}
}
Спасибо всем, я ценю вашу помощь
Редактировать:
Вместо этого я попытался использовать BeginRead и EndRead, как предложил "gt". Для этого я использую BeginRead всякий раз, когда пользователь отправляет запрос. Когда все данные получены, я печатаю их на экране. Кажется, это работает нормально, но я беспокоюсь о том, будут ли какие-либо проблемы в будущем. Есть ли вероятность, что пакеты испортятся? Например, возможно ли, что EndRead не возвращает 0 в конце первого пакета и продолжает читать второй пакет? Если это возможно, как я буду продолжать решать это? Полученные данные - это просто тело уровня http, поэтому я не могу получить доступ к уровню IP заранее, чтобы узнать длину пакета.
public void SendData(byte[] message) {
sslStream.Write(message);
sslStream.Flush();
//Start reading for response (if not already reading)
if (sslStream.CanRead) {
sslStream.BeginRead(buffer, 0, BufferSize, ReadData, null);
}
}
void ReadData(IAsyncResult ar) {
int bytesRead = sslStream.EndRead(ar);
if (bytesRead > 0) {
//data may be on their way so start reading again
message.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead));
sslStream.BeginRead(buffer, 0, BufferSize, ReadData, null);
Console.WriteLine("Data received but more may be on their way...");
} else {
//All data arrived (Checking if length is more than 0 since all the
//data may had already arrived in the previous check (above)
if (message.ToString().Length > 0) {
Console.WriteLine(message.ToString());
//Clear StringBuilder and reset buffer.
message.Clear();
buffer = new byte[BufferSize];
}
}
}
еще раз спасибо
1 ответ
Проводы while(true)
обычно это плохой признак... Если ваш код входит в "жесткий" цикл без конечного условия, он будет продолжать цикл и потреблять все доступные ему ресурсы.
Дважды проверьте, что условие "если" выполняет то, что вы ожидаете. Например, что произойдет, если поток будет прочитан более чем в одной части? (например, две части 32768). Это вполне возможно.
Как только вы довольны поведением, вы можете заставить нить немного поспать, прежде чем пытаться Read
, с помощью Thread.Sleep(100)
,
Или попробуйте поискать асинхронный ввод-вывод, используя BeginRead
, Посмотрите этот пример на MSDN.
Отредактируйте, чтобы ответить на часть 2 вопроса:
Я подозреваю, что если что-то пойдет не так, то пойдет не так, поэтому используйте защитный код! Решение следующей проблемы заключается в буферизации всех данных, прочитанных из потока. Затем сделайте попытку другого потока прочитать целые пакеты из буфера. Не забудьте использовать блокировки для предотвращения одновременного чтения / записи в буфер.
Также было бы неплохо написать для этого модульные тесты, чтобы охватить "фрагментированное" поведение (а также нормальное поведение).
В качестве альтернативы вы можете посмотреть протокол более высокого уровня, который позаботится об этом за вас. Один из часто упоминаемых мной примеров - это буфер протокола Google.