Есть програмка, которая ожидает данные из сети, а при получении выполняет определенные действия. Вот ее функции, осуществляющие чтение данных и их обработку:
protected void RecieveMessage(object Stream)
{
try
{
NetworkStream netStream = Stream as NetworkStream;
while (_client.Connected)
{
byte[] buffer = new byte[4096];
int count = netStream.Read(buffer, 0, buffer.Length);
if (count != 0)
{
new Thread(ParseMessage).Start(NetMessage.Recive(buffer));
GetStringFromArrayBytes(buffer);
_log.WriteLog("От клиента " + _remotehost.Address.ToString() + " получены данные " + String.Join("; ", NetMessage.Recive(buffer)));//+". Число считанных байт - "+count.ToString()+". Данные - "+GetStringFromArrayBytes(buffer));
}
else _SendInfo(new string[] { "YouHere", "YouHere" });
}
}
catch (System.IO.IOException)
{
_log.WriteLog("Клиент " + _remotehost.Address.ToString() + " отключен.");
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("Ошибка чтения данных от сервера! " + ex.ToString());
}
}
private void ParseMessage(object Message)
{
try
{
string[] message = Message as string[];
//запрос на добавление в список рассылкиswitch (message[0])
{
case"InsertMeToList":
_delyvery = true;
SendMessage(new string[] { "YouInList", "YouInList" });
break;
case"YouHere":
SendMessage(new string[] { "ImHere", "ImHere" });
break;
case"ImHere":
break;
default: if (Command != null) Command(this, message); break;
}
}
catch (Exception ex)
{
_log.WriteError("Ошибка при обработке команды клиента " + _remotehost.Address.ToString() + ". Сообщение: " + ex.Message);
}
}
Вот код используемого класса NetMessage
/// <summary>
/// Класс кодирования/декодирования сообщений для отправки по сети
/// </summary>public static class NetMessage
{
/// <summary>
/// Кодирует массив строк в массив байтов
/// </summary>
/// <param name="Strings">Кодируемый массив строк</param>
/// <returns>Массив байт для отправки по сети</returns>public static byte[] ForSend(string[] Strings)
{
try
{
byte[] temp = new byte[4096];
BitConverter.GetBytes(Strings.Length).CopyTo(temp, 0);
int pos = 4;
foreach (string str in Strings)
if (!String.IsNullOrEmpty(str))
{
int count = Encoding.UTF8.GetByteCount(str);
BitConverter.GetBytes(count).CopyTo(temp, pos);
pos += 4;
Encoding.UTF8.GetBytes(str, 0, str.Length, temp, pos);
pos += count;
}
return temp;
}
catch
{
return new byte[] { };
}
}
/// <summary>
/// Определяет колличество строк во входном сообщении
/// </summary>
/// <param name="recieve">Принятый массив байт</param>
/// <returns>Колличество строк в принятом сообщении</returns>public static int StringCount(byte[] recieve)
{
try
{
return BitConverter.ToInt32(recieve, 0);
}
catch
{
return 0;
}
}
/// <summary>
/// Декодирует массив байт
/// </summary>
/// <param name="recieve">Принятый массив байт</param>
/// <returns>Массив строк сообщения</returns>public static string[] Recive(byte[] recieve)
{
try
{
string[] temp = new string[StringCount(recieve)];
int pos = 0;
for (int i = 0; i < StringCount(recieve); i++)
{
int count = BitConverter.ToInt32(recieve, i * 4 + 4 + pos);
temp[i] = Encoding.UTF8.GetString(recieve, i * 4 + 8 + pos, count);
pos += count;
}
if (temp.Length == 0) return new string[] { "" };
return temp;
}
catch
{
return new string[] { "" };
}
}
}
Так, вот. Иногда при приеме данных от клиента из сети принимается пустая строка, то есть NetMessage.Recive(buffer) возвращает пустой массив, хотя должны быть данные. Почему такое происходит?
и вставить ее между этих двух строк (как это уже сделано в коде предыдущего сообщения)
new Thread(ParseMessage).Start(NetMessage.Recive(buffer));
_log.WriteLog("От клиента " + _remotehost.Address.ToString() + " получены данные " + String.Join("; ", NetMessage.Recive(buffer)));//+". Число считанных байт - "+count.ToString()+". Данные - "+GetStringFromArrayBytes(buffer));
то все работает нормально. Без нее работает через раз — то есть несколько нормально принятых сообщения, одно или два пустых (хотя данные там точно должны быть). После вставки вызома данной функции заработало. Объясните мне где я ошибся и как это убрать?
Здравствуйте, XaSSeR, Вы писали:
XSS>Есть програмка, которая ожидает данные из сети, а при получении выполняет определенные действия. Вот ее функции, осуществляющие чтение данных и их обработку:
Для начала код стоит немного поправить...
1) NetworkStream.Read заполнит буфер не полностью, а только на реально прочитанные count байт. Это надо учитывать при обработке массива. Т.е. за 1 чтение данные из сети могут быть получены в общем случае не все.
XSS>
XSS> int count = netStream.Read(buffer, 0, buffer.Length);
XSS>
2) Зачем тут catch? Если только длина массива меньше 4 байт, но опять возвращаемся к п.1. XSS>
XSS> public static int StringCount(byte[] recieve)
XSS>
Аналогично с Recive() — строить тут логику управления на исключениях настоятельно не рекомендуется.
XSS>Так, вот. Иногда при приеме данных от клиента из сети принимается пустая строка, то есть NetMessage.Recive(buffer) возвращает пустой массив, хотя должны быть данные. Почему такое происходит?
Здравствуйте, andrey82, Вы писали:
A>1) NetworkStream.Read заполнит буфер не полностью, а только на реально прочитанные count байт. Это надо учитывать при обработке массива. Т.е. за 1 чтение данные из сети могут быть получены в общем случае не все.
Я в курсе. Но count мне не важно. Внутри буфера уже есть вся необходимая информация о длинне сообщения.
A>2) Зачем тут catch? Если только длина массива меньше 4 байт, но опять возвращаемся к п.1.
Остался с тех времен, когда я искал ошибку, и долго не мог найти.
A>Аналогично с Recive() — строить тут логику управления на исключениях настоятельно не рекомендуется.
А от этого может быть то, что у меня получается?
A>А что при этом на входе у Recive() ?
В представленном выше коде есть такая строка
_log.WriteLog("От клиента " + _remotehost.Address.ToString() + " получены данные " + String.Join("; ", NetMessage.Recive(buffer)));//+". Число считанных байт - "+count.ToString()+". Данные - "+GetStringFromArrayBytes(buffer));
Так вот, когда я раскоменчиваю строку, чтобы посмотреть что на выходе у Recive() (то есть что лежит в buffer) все начинает отлично работать и выводит что считано 4096 байт данных и все байты через |. А когда убираю данную строку, получаю иногда NetMessage.Recive(buffer) возвращает такое — new string[] { "" }, хотя должно быть new string[] { "Helo", "World" }. Поэтому я не знаю что на входе когда работает не правильно.
if (count != 0)
new Thread(ParseMessage).Start(NetMessage.Recive(buffer));
netStream.Read прочитать может например первые 2 байта из потока, их обработка не пройдет, а при след. чтении — будут приняты остальные байты и на обработку пойдет фактически уже мусор.
XSS>Так вот, когда я раскоменчиваю строку, чтобы посмотреть что на выходе у Recive() (то есть что лежит в buffer) все начинает отлично работать и выводит что считано 4096 байт данных и все байты через |. А когда убираю данную строку, получаю иногда NetMessage.Recive(buffer) возвращает такое — new string[] { "" }, хотя должно быть new string[] { "Helo", "World" }. Поэтому я не знаю что на входе когда работает не правильно.
Так просто логгирование на входе в Recive() можно сделать...
Проблема похоже все таки в логике обработки читаемых из соединения байт.
Re[4]: Проблемы при работе с сетью
От:
Аноним
Дата:
11.01.13 14:30
Оценка:
Здравствуйте, andrey82, Вы писали:
A>Здравствуйте, XaSSeR, Вы писали:
A>Вот это еще как то не очень: A>
if (count != 0)
A>new Thread(ParseMessage).Start(NetMessage.Recive(buffer));
A>netStream.Read прочитать может например первые 2 байта из потока, их обработка не пройдет, а при след. чтении — будут приняты остальные байты и на обработку пойдет фактически уже мусор.
XSS>>Так вот, когда я раскоменчиваю строку, чтобы посмотреть что на выходе у Recive() (то есть что лежит в buffer) все начинает отлично работать и выводит что считано 4096 байт данных и все байты через |. А когда убираю данную строку, получаю иногда NetMessage.Recive(buffer) возвращает такое — new string[] { "" }, хотя должно быть new string[] { "Helo", "World" }. Поэтому я не знаю что на входе когда работает не правильно.
A>Так просто логгирование на входе в Recive() можно сделать... A>Проблема похоже все таки в логике обработки читаемых из соединения байт.
Почему же тогда после вставки функции вывода буфера все нормально заработало, если логика обработки хромала то ошибки были бы постоянно.