Строки оператора Switch совпадают, но не работают

У меня есть оператор switch, который использует строку, преобразованную из char[], которая была отправлена ​​через поток данных с сервера на клиент. Код находится на стороне клиента.

Случай по умолчанию всегда срабатывает, даже если сервер и код ошибки по умолчанию всегда точно соответствуют случаям.

SERVER SIDE
private void SendToClient(string message, TcpAccount account)
    {
        try
        {
            byte[] buffMessage = Encoding.ASCII.GetBytes(message);
            account.TcpClient.GetStream().WriteAsync(buffMessage, 0, buffMessage.Length);
            log.AppendText(string.Format("Message {0} sent to account {1}", message, account.ID));
            log.AppendText(Environment.NewLine);
        }
        catch
        {
            log.AppendText(string.Format("Message {0} sent to account {1}", message, account.ID));
            log.AppendText(Environment.NewLine);
        }
    }

CLIENT SIDE
public async void ReadDataAsync(TcpClient client)
    {
        try
        {
            StreamReader clientStreamReader = new StreamReader(client.GetStream());
            char[] buff = new char[64];
            int readByteCount = 0;

            while (true)
            {
                readByteCount = await clientStreamReader.ReadAsync(buff, 0, buff.Length);

                if (readByteCount <= 0)
                {
                    Console.WriteLine("Disconnected from server.");
                    client.Close();
                    break;
                }
                string code = new string(buff);
                ProcessServerCode(code);
                Array.Clear(buff, 0, buff.Length);
            }
        }
        catch
        {

        }
    }

public void ProcessServerCode(string code)
    {
        switch (code)
        {
            case "regcom":
                MessageBox.Show("Registration Complete");
                break;

            case "logcom":
                MessageBox.Show("Login Complete");
                break;

            case "badpass":
                MessageBox.Show("Invalid Password");
                break;

            case "badaccount":
                MessageBox.Show("Invalid Account");
                break;

            default:
                MessageBox.Show("Unknown Code: " + code);
                break;
        }
    }

Я не могу получить его из кода по умолчанию.

Кроме того, поскольку я новичок в программировании клиент-сервер и сокет, я только что понял, что сервер отправляет byte[], но клиент получает char[]. Нет ли там конфликта? Есть ли какая-то конкретная причина для этого (поскольку я использую эти конкретные фрагменты кода из онлайн-тренировки)?

Вы пытались отлаживать то, что получает клиентский код? Если вы всегда нажимаете значение по умолчанию, то ваш ввод не такой, как вы ожидаете.

Steve 28.01.2019 13:47

Можно попробовать обрезать полученную строку, обновить эту строку string code = new string(buff).Trim();. Я думаю, это может быть причиной, потому что вы ждете, чтобы получить 64 байта, но полученная строка меньше в ваших примерах

Sergey Anisimov 28.01.2019 13:48

примечание: никогда никогда использует async void. Даже если вас не волнует результат, вам следует всегда использовать async Task. Основная причина здесь заключается в том, что async заботится о контексте синхронизации, и существует множество контекстов синхронизации, которые активно блокироватьasync void — в частности, но не ограничиваясь этим, контекст синхронизации ASP.NET. Это означает, что вы можете обнаружить, что код отлично работает в одной системе и не работает вообще при смене версии/платформы/и т. д. из-за различий в контексте синхронизации (один разрешает async void, другой не разрешает). Итак: никогда никогда используйте async void

Marc Gravell 28.01.2019 14:03

@MarcGravell Спасибо! Я внес изменения и обязательно избегу асинхронной недействительности в будущем.

Arcaster 28.01.2019 14:09

еще одно примечание: на самом деле вы не используете await для WriteAsync - вы действительно должен ждете этого

Marc Gravell 28.01.2019 14:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
49
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Первая проблема, которую я вижу, заключается в том, что вы игнорируете readByteCount (который на самом деле является подсчетом символов, а не подсчетом байтов); вы должен используете:

string code = new string(buff, 0, readByteCount);

Однако следующая проблема, которую я вижу, заключается в том, что у вас нет никакого протокола кадрирования. Это означает:

  • если два сообщения отправляются близко друг к другу, вы можете получить то, что выглядит как одно объединенное значение.
  • даже отдельные значения могут быть произвольно усечены, поскольку они разделяются между пакетами
  • и т.д

В любом случае:

  • если сообщение длиннее, чем длина вашего буфера, вы сломаны
  • если вы когда-либо получали более одного сообщения за раз, вы сломались

как и в любом случае, никогда нельзя будет правильно восстановить позицию. Отсюда: фреймы, где каждый фрейм представляет собой законченное сообщение.

Обычный подход к текстовым протоколам заключается в использовании новой строки в качестве фрейма (я позволю вам решить, означает ли это CR, LF, CRLF и т. д.); тогда вы можете просто использовать ReadLine/ReadLineAsync для чтения текста, и это будет сделать все это автоматически, поэтому:

string code = await clientStreamReader.ReadLineAsync();
if (code is null)
{
    Console.WriteLine("Disconnected from server.");
    client.Close();
}
else
{
    ProcessServerCode(code);
}

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

Patrick Hofman 28.01.2019 13:52

@PatrickHofman действительно :) на самом деле, если бы я был педантичен, я бы сказал: «избегайте использования TextReader на сервере сокетов - обрабатывайте кадры вручную, декодируйте только тогда, когда у вас есть целые кадры, и в идеале используйте что-то вроде «конвейеров». двигатель", но это потребует много больше объяснений, чем я могу успеть в понедельник...

Marc Gravell 28.01.2019 13:54

@MarcGravell Итак, сосредоточившись на первой проблеме, изменение кода на вашу первую строку дало мне тот же результат. По умолчанию показано, что я получаю «regcom» в качестве кода, но опять же технически это не соответствует случаю «regcom». На глаз они совпадают, но почему-то в коде не совпадают. Что касается других ваших заметок, все это кажется мне неподходящим (я действительно новичок в любом виде сетевого общения), но, используя метод ReadLineAsync(), клиент больше не получает НИКАКОЕ сообщение от сервера успешно. Есть ли какие-то другие изменения, которые мне нужны на стороне сервера?

Arcaster 28.01.2019 14:16

@Arcaster да, кадры должны совпадать с обоих концов; самым простым решением будет byte[] buffMessage = Encoding.ASCII.GetBytes(message + "\r\n"); (но возможны и более эффективные подходы)

Marc Gravell 28.01.2019 14:24

@Arcaster, что касается проблемы «изменение кода на первую строку»; к сожалению, для дальнейшей диагностики мне действительно нужно смотреть побайтно, плюс этот подход обречен на провал так или иначе из-за проблемы с кадрированием, поэтому я не уверен, что стоит тратить время на попытки продолжить это.

Marc Gravell 28.01.2019 14:26

@MarcGravell В конечном итоге переключение на ReadLineAsync() и добавление разрыва строки в сообщение решили мою проблему. Что касается проблем с основой, то это личный учебный проект, а не код производственного уровня, я буду решать любые сложности в будущем. Спасибо за наводку и решение.

Arcaster 28.01.2019 14:38

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