Отдельный поток SslStream

Я пытаюсь отобразить на экране любые данные, поступающие из потока ssl (с веб-сайта). Поскольку я не знаю, когда поступят данные, я использовал другой поток, который продолжает чтение из потока до тех пор, пока не будут прочитаны байты. Это работает отлично, однако использование моего ЦП подскакивает до 25% и остается там (это 1 поток при максимальном использовании, мой компьютер имеет 4 потока). Хотя это имеет смысл, поскольку поток застрял в цикле while, я не ожидал, что экземпляр класса Thread будет использовать весь поток моего ЦП (я мог бы поклясться, что этого не происходило при использовании простого клиента/ серверное приложение).

Поток запускается, как только соединение инициализируется, пользователь может отправлять данные на веб-сайт в любое время, когда он хочет, и приложение должно распечатать ответ. Какие могут быть альтернативные решения для этого? Должен ли я отказаться от 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];
            }
        }
    }

Еще раз спасибо


person Orestis P.    schedule 25.03.2013    source источник


Ответы (1)


Видеть while(true) обычно плохой знак... Если ваш код входит в "жесткий" цикл без конечного условия, он будет продолжать цикл и потреблять все доступные ему ресурсы.

Дважды проверьте, что условие «если» делает то, что вы ожидаете. Например, что произойдет, если поток будет прочитан более чем одной частью? (например, две части числа 32768). Это вполне возможно.

Как только вы довольны поведением, вы можете заставить поток немного приостановиться, прежде чем пытаться выполнить следующий Read, используя Thread.Sleep(100).

В качестве альтернативы попробуйте изучить асинхронный ввод-вывод, используя BeginRead< /а>. См. этот пример в MSDN.


Изменить, чтобы ответить на часть 2 вопроса:

Я подозреваю, что если что-то может пойти не так, то оно обязательно пойдет не так, поэтому кодируйте осторожно! Решение следующей проблемы состоит в том, чтобы буферизовать все данные, считанные из потока. Затем другой поток попытается прочитать целые пакеты из буфера. Не забывайте использовать блокировки, чтобы буфер не читался/записывался одновременно.

Также было бы неплохо написать для этого модульные тесты, чтобы охватить «фрагментированное» поведение (а также нормальное поведение).

В качестве альтернативы вы можете изучить протокол более высокого уровня, который позаботится об этих вещах за вас. Я часто упоминаю о Google Protocol Buffers.

person g t    schedule 25.03.2013
comment
Сон в течение 100 мс решил проблему с производительностью; Использование ЦП вернулось к норме (0%). Я попробовал вашу рекомендацию с BeginRead и EndRead. Для этого я использую BeginRead всякий раз, когда пользователь отправляет запрос, когда все данные получены, я печатаю их на экране. Кажется, это работает нормально, но меня беспокоит, не возникнут ли проблемы в будущем. Я отредактирую свой основной пост, так как здесь осталось недостаточно символов. Еще раз спасибо. - person Orestis P.; 25.03.2013
comment
Кроме того, поток действительно читается более чем в одной части. Это из-за фрагментации пакетов? Код, который я разместил выше, исправляет это, но мне было интересно, возможно ли, чтобы пакеты перепутались таким образом. - person Orestis P.; 26.03.2013
comment
Спасибо, я получил общее представление о том, что я должен делать, вы были очень полезны. Я ценю вашу помощь. Не уверен, есть ли способ пометить это как решенное (я здесь новичок), но я получил всю необходимую мне помощь. Еще раз спасибо! - person Orestis P.; 27.03.2013