C# - StreamReader.ReadLine не работает должным образом!

Просто я пытался реализовать то, что BufferedStreamReader делает в Java. У меня открыт поток сокетов, и я просто хочу читать его по линии - строка за строкой.

У меня есть следующий серверный код.

while (continueProcess)
        {
            try
            {
                StreamReader reader = new StreamReader(Socket.GetStream(), Encoding.UTF8);
                string command = reader.ReadLine();
                if (command == null)
                    break;

                OnClientExecute(command);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

И следующий код клиента:

TcpClient tcpClient = new TcpClient();
        try
        {
            tcpClient.Connect("localhost", serverPort);
            StreamWriter writer = new StreamWriter(tcpClient.GetStream(), Encoding.UTF8);
            writer.AutoFlush = true;
            writer.WriteLine("login>user,pass");
            writer.WriteLine("print>param1,param2,param3");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
        finally
        {
            tcpClient.Close();
        }

Сервер читает только самую первую строку (login>user,pass) а потом ReadLine возвращает ноль!

Какой самый простой способ добиться этого линейно-ориентированного читателя, как в Java BufferedStreamReader?:s

4 ответа

Решение

Типичный читатель строки выглядит примерно так:

using(StreamReader reader = new StreamReader(Socket.GetStream(), Encoding.UTF8)) {
    string line;
    while((line = reader.ReadLine()) != null) {
        // do something with line
    }
}

(Обратите внимание using чтобы мы Dispose() это даже если мы получим ошибку и цикл)

Если вы хотите, вы можете абстрагировать это (разделение задач) с помощью блока итератора:

static IEnumerable<string> ReadLines(Stream source, Encoding encoding) {
    using(StreamReader reader = new StreamReader(source, encoding)) {
        string line;
        while((line = reader.ReadLine()) != null) {
            yield return line;
        }
    }
}

(обратите внимание, что мы переместили это в функцию и удалили "сделать что-то", заменив его "yield return", который создает итератор (лениво итерированный, без буферизации конечный автомат)

Затем мы бы потребляли это так же просто, как:

foreach(string line in ReadLines(Socket.GetStream(), Encoding.UTF8)) {
    // do something with line
}

Теперь нашему коду обработки не нужно беспокоиться о том, как читать строки - просто с учетом последовательности строк, сделайте что-нибудь с ними.

Обратите внимание, что using (Dispose()) относится к TcpClient тоже; Вы должны сделать привычку проверять IDisposable; например (все еще включая вашу регистрацию ошибок):

using(TcpClient tcpClient = new TcpClient()) {
    try {
       tcpClient.Connect("localhost", serverPort);
       StreamWriter writer = new StreamWriter(tcpClient.GetStream(), Encoding.UTF8);
       writer.AutoFlush = true;
       writer.WriteLine("login>user,pass");
       writer.WriteLine("print>param1,param2,param3");
    } catch (Exception ex) {
        Console.Error.WriteLine(ex.ToString());
    }
}

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

    public string READS()
    {
        byte[] buf = new byte[CLI.Available];//set buffer
        CLI.Receive(buf);//read bytes from stream
        string line = UTF8Encoding.UTF8.GetString(buf);//get string from bytes
        return line;//return string from bytes
    }
    public void WRITES(string text)
    {
        byte[] buf = UTF8Encoding.UTF8.GetBytes(text);//get bytes of text
        CLI.Send(buf);//send bytes
    }

CLI это сокет. для некоторых зон класс TcpClient больше не работает прямо на моем компьютере, но класс Socket работает просто отлично.

UTF-8 - это многопоточное кодирование StreamReader / Writer

Попробовал это и получил

Не удалось найти тип или имя пространства имен "Stream" (отсутствует директива using или ссылка на сборку?) Не удалось найти тип или имя пространства имен "StreamReader" (отсутствует директива using или ссылка на сборку?) Не удалось найти тип или имя пространства имен StreamReader (отсутствует директива using или ссылка на сборку?) System.Net.Sockets.Socket не содержит определения для GetStream.

Другие вопросы по тегам