Чтение в NetworkStream = 100% загрузка процессора - PullRequest
4 голосов
/ 12 октября 2010

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

Вот что у меня есть:

    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;

    }

Ответы [ 3 ]

8 голосов
/ 12 октября 2010

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

Причиной 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 вместо чтения в буфер символов.

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

6 голосов
/ 12 октября 2010

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

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

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

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

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

5 голосов
/ 12 октября 2010

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

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

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

Вот пример примера программирования асинхронных сокетов для клиентского приложения.

...