Ув. программисты, подскажите, пожалуйста, как решить проблему.
Принимаю от клиента текстовую строку:
stream = client.GetStream();
byte[] data = new byte[64]; // буфер для получаемых данных
List<byte> list = new List<byte>(); // Большой buffer
while (true)
{
// получаем сообщение
// StringBuilder builder = new StringBuilder();
int bytes = 0;
do
{
bytes = stream.Read(data, 0, data.Length);
// builder.Append(Encoding.UTF8.GetString(data, 0, bytes));
list.AddRange(data.Take(bytes));
}
while (stream.DataAvailable);
string message = Encoding.UTF8.GetString(list.ToArray(), 0, list.Count);
Но при получение большой строки (1700 байт например) строка режется (вот этим символом �).
Если увеличить вместимость массива data больше чем байтов в строке (например, с 64 на 2048 байт), то все работает норм.
Подскажите, пожалуйста, почему это происходит и как это исправить, ибо строки иногда могут быть и длиннее…
В том то и дело, что я не могу понять…
Не вижу связи и логики, где может все оборваться…
Когда присылаю данные, например в 500 байт - все работает четко…
Насчет, отладки… Когда я включаю отладку и построчно пробегаю по коду вручную (а именно по циклу), то есть до “string message”, то все работает, как ни странно… Никаких ошибок не вылетает и в переменную в итоге пишутся все данные.
Кстати, не дописал в предыдущем посте: ошибка вылетает “Индекс находился вне границ массива”.
Я просто новичок… как это сделать…
Как посмотреть list в hex редакторе…
И где можно посмотреть, где именно ошибка вылетает? Просто программа не прекращает свою работу, как при обычной ошибке, где Студия показывает строку проблемную… У меня это сообщение вылетает в консоле (Само приложение консольное), так как вышеуказанный код обернут в Ловушку ошибок (КетчЭкспешн)… Может убрать его? И оставить чисто этот код? Посмотреть, что покажет Студия?
File.WriteAllBytes("myfile.bin", list.ToArray()); и чтобы увидеть его в виде байтов скачать любой хекс-редактор, например, https://mh-nexus.de/en/hxd/
Так там и выведите куда угодно информацию об исключении.
using System;
public class Program
{
public static void badFunction()
{
throw new Exception("BOOM");
}
public static void Main()
{
try
{
badFunction();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
Я сделал, как вы сказали… И нашел строчку, которая вызвает ошибку, но она вроде не имеет отношения к проблемы. Дело в том, что после получения переменной message я ее делю через сплит и части ее помещаю в массив, а потом передаю ее части для дальнейшей работы в другую функцию… И так как строка приходит не полностью, но не всех параметров хватает, поэтому и вылетает ошибка, как я понял… Но ведь проблема не исчезла. Строка пришла не полностью.
Посмотрел данные в HEX редакторе… Тоже самое. В файле данные строки не полностью содержатся.
Вот выслал весь код этой функции.
public void Process()
{
NetworkStream stream = null;
try
{
stream = client.GetStream();
byte[] data = new byte[64]; // буфер для получаемых данных
List<byte> list = new List<byte>(); // Большой buffer
while (true)
{
// получаем сообщение
// StringBuilder builder = new StringBuilder();
int bytes = 0;
do
{
bytes = stream.Read(data, 0, data.Length);
/// builder.Append(Encoding.UTF8.GetString(data, 0, bytes));
list.AddRange(data.Take(bytes));
}
while (stream.DataAvailable);
string message = Encoding.UTF8.GetString(list.ToArray(), 0, list.Count) /* builder.ToString() */;
System.IO.File.WriteAllBytes("myfile.bin", list.ToArray());
Console.WriteLine(message);
String[] strArr = null;
char[] splitchar = { '&' };
strArr = message.Split(splitchar);
if (strArr[0] == "VHOD")
{
String otvet = Enter(strArr[1], strArr[2]); //Здесь ошибка
data = Encoding.UTF8.GetBytes(otvet);
stream.Write(data, 0, data.Length);
}
stream.Close();
client.Close();
// отправляем обратно сообщение
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
stream.Close();
client.Close();
}
finally
{
if (stream != null)
stream.Close();
if (client != null)
client.Close();
}
}
Напечатайте или вставьте сюда код
Я не могу понять, почему при ручной отладке все работает… когда я медленно построчно прохожу код. Такое ощущение, что эта процедура выполняется быстрее, чем данные до нее доходят, и соответственно она принимает не всю строку. С другой стороны, ведь while (stream.DataAvailable); должна обеспечивать обработку данных пока они не закончатся?
Ну так если тут в файле не все данные, а например при прохождении по шагам в отладчике всё работает, то несложно догадаться о причинах )
Скорее всего чтение происходит быстрее, чем приходят данные, и stream.DataAvailable временно становится false.
Надо по-другому протокол и чтение организовывать.
Например, в самом начале прислать длину сообщения, и потом пытаться читать пока не прочитается столько.
Вроде сделал. Отправляю в первой порции данных, первыми 6 байтами размер всего того, что будет в строке после. А DataAvaible заменил на количество байтов в строке (не считая байтов, определяющих размер строки после них) и кручу циклю пока размер Списка не станет таким же, как и количество байт, которые должны прийти. Таким методом я все получаю… Пробовал даже очень большие строки отправлять - все доходит. Надеюсь в этой схеме нет подводных камней.)))) Спасибо за совет!))))