2010-10-11 3 views
4

Я читаю из NetworkStream, который находится в цикле while. Проблема в том, что я вижу 100% использование ЦП. Есть ли способ остановить это?Чтение на NetworkStream = использование 100% CPU

Вот то, что я до сих пор:

while (client != null && client.Connected) 
      { 

       NetworkStream stream = client.GetStream(); 
       data = null; 

       try 
       { 
        // Check if we are still connected. 
        if (client.Client.Poll(0, SelectMode.SelectRead)) 
        { 
         byte[] checkConn = new byte[1]; 

         if (client.Client.Receive(checkConn, SocketFlags.Peek) == 0) 
         { 
          throw new IOException(); 
         } 
        } 

        if (stream.DataAvailable) 
        { 
         //Read the first command 
         WriteToConsole("Waiting for next command"); 
         data = ReadStringFromClient(client, stream); 
         WriteToConsole("Received Command: " + data); 
        } 
       } 

... Код продолжается ...

код ReadStringFromClient:

private string ReadStringFromClient(TcpClient clientATF, NetworkStream currentStream) 
    { 
     int i; 
     string builtString; 
     byte[] stringFromClient = new byte[256]; 

     if (clientATF.Connected && currentStream.CanRead) 
     { 

      i = currentStream.Read(stringFromClient, 0, stringFromClient.Length); 
      builtString = System.Text.Encoding.ASCII.GetString(stringFromClient, 0, i); 

     } 

     else 
     { 
      return "Connection Error"; 
     } 

     return builtString; 

    } 

ответ

6

Причина, по которой вы видите 100% использование ЦП, заключается в том, что вы всегда что-то делаете, что является результатом бесконечного цикла while без задержек.

Основные семантика:

  1. Проверьте, подключен клиент
  2. опрашивать клиента
  3. Проверить, если имеются данные
  4. Считывание данных
  5. Вернитесь к шагу 1

Поскольку вы находитесь в этом цикле, вы всегда делаете что-то что бы это ни было. Самой простой семантикой является выполнение Thread.sleep() в конце вашего цикла. Это поможет вам без необходимости внесения больших изменений. Тем не менее, вы введете задержку того, что такое время сна, и на самом деле это не совсем правильный способ (но может подойти к вашей ситуации).

Правильный способ - узнать о асинхронных сокетах, если вы хотите использовать высокопроизводительный сервер или что-то, что использует подходящий низкий процессор при подключении 1 или более сокетов. Вероятно, для быстрого поиска Google лучше всего учиться, но я не помню, чтобы какие-либо особенно хорошие статьи были сделаны. Преимущество Asynchronous IO в основном состоит в том, что вы будете использовать только процессорное время, когда вам нужно что-то делать. Когда данные будут получены, ваш метод будет вызван для выполнения любой обработки, которую вы должны выполнить.

+0

Это было самое простое решение, однако ... я теперь знаю, что асинхронные сокеты должны были стать отправной точкой. –

+0

Я использовал опросные петли с сокетами в прошлом и обнаружил, что очень короткая задержка блокировки в конце цикла устранит эту проблему. Следующий код работает хорошо: 'System.Threading.Thread.Sleep (10);' – Nate

+0

@Nate Это в основном то, что было моим предложением, но, пожалуйста, прочитайте глубже, хотя он работает и может быть легко сделать, это очень плохой дизайн. –

8

Ваш код содержит много ... шум. Вам это не понадобится.

Причина 100% загрузки процессора заключается в том, что вы ожидаете, что данные станут доступными. Вам не нужно это делать. Read будет блокироваться до тех пор, пока данные не будут доступны. Вам также не нужно воссоздавать NetworkStream для каждого фрагмента данных для приема.

Ваш код может быть гораздо проще, если вы хотите использовать StreamReader:

using (var reader = new StreamReader(new NetworkStream(socket)) 
{ 
    char[] buffer = new char[512]; 
    int received; 
    while ((received = reader.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     string s = new string(buffer, 0, received); 
     Console.WriteLine(s); 
    } 
} 

Read блок, пока данные не станет доступным. Код показывается, пока соединение живое. Вы еще более упростите код, если используете ReadLine вместо чтения в буфере символов.

Если вы не хотите блокировать поток до тех пор, пока данные не станут доступными, обратите внимание на асинхронное чтение.

+0

Я немного почистил свой код. Спасибо за ввод. –

+1

Это не плохой совет, просто будьте осторожны, что вы должны делать это только в том случае, если ваш поток является текстовым потоком. Если вы внедрили протокол (который вам нужен), вам нужно будет выполнить некоторую работу самостоятельно :-) –

5

Это потому, что вы постоянно просите ЦП сделать что-то для вас - а именно, проверить, есть ли что-либо в потоке.

Это довольно распространенный шаблон, с которым вам нужно научиться справляться соответствующим образом. Он называется асинхронным IO, и хорошей новостью является то, что платформа .NET имеет обширную поддержку, позволяющую вам легко выполнить то, что вы хотите, без постоянного использования ЦП на 100%.

Большая проблема заключается в том, что ваш код работает в бесконечном цикле, постоянно вызывая client.Client.Poll(0, SelectMode.SelectRead), который немедленно вернется с ответом. Вместо этого вы должны задать фреймворк, чтобы уведомить вас, когда произойдет что-то интересное, например, когда есть данные, доступные для чтения из сетевого потока. И есть более чем несколько способов, которыми вы можете это сделать. Один из способов - использовать метод NetStrkStream BeginRead.

Вот пример asynchronous sockets programming example для клиентского приложения.

+0

Ive начал изучать это. Спасибо –

Смежные вопросы