С# - 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 возвращает значение null!

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

Ответ 1

Типичный линейный читатель - это что-то вроде:

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());
    }
}

Ответ 2

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

Ответ 3

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

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

Ответ 4

    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 - это сокет. для некоторого rezone класс TcpClient больше не работает на моем ПК, но класс Socket работает очень хорошо.

UTF-8 - это скрученное кодирование StreamReader/Writer