Работа с байтовыми массивами в C #

Для вашего массива длина массива равна 3 (например, name.length = 3). Но поскольку он хранит элемент, начинающийся с индекса 0, он имеет максимальный индекс 2.

Итак, вместо 'i ** & lt; = name.length' вы должны написать 'i & lt; ** name.length' чтобы избежать «ArrayIndexOutOfBoundsException».

13
задан casperOne 26 May 2011 в 18:27
поделиться

10 ответов

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

, Конечно, те же правила применяются, как будто необходимо было передать указатель как в C++ - массив не должен быть изменен, или иначе он может привести к неопределенному поведению, если Вы не уверены, когда точно данные будут использоваться. Но это не проблема, если Вы больше не собираетесь быть изменением массива.

24
ответ дан Spodi 27 May 2011 в 05:27
поделиться

Я передал бы ArraySegment<byte> в этом случае.

Вы изменили бы Ваш Parse метод к этому:

// Changed TCPHeader to TcpHeader to adhere to public naming conventions.
TcpHeader Parse(ArraySegment<byte> buffer)

И затем Вы изменили бы вызов на это:

// Create the array segment.
ArraySegment<byte> seg = new ArraySegment<byte>(packet, 20, 20);

// Call parse.
TcpHeader header = Parse(seg);

Используя эти ArraySegment<T> не скопирует массив, и он сделает проверку границ Вас в конструкторе (так, чтобы Вы не указывали неправильные границы). Затем Вы изменяете Ваш Parse метод для работы с границами, указанными в сегменте, и необходимо быть в порядке.

можно даже создать перегрузку удобства, которая примет полный массив байтов:

// Accepts full array.
TcpHeader Parse(byte[] buffer)
{
    // Call the overload.
    return Parse(new ArraySegment<byte>(buffer));
}

// Changed TCPHeader to TcpHeader to adhere to public naming conventions.
TcpHeader Parse(ArraySegment<byte> buffer)
22
ответ дан casperOne 27 May 2011 в 05:27
поделиться

Если можно изменить синтаксический анализ () метод, изменить его для принятия смещения, где обработка должна начаться. Синтаксический анализ TCPHeader (байт [] буфер, международное смещение);

2
ответ дан DotNET 27 May 2011 в 05:27
поделиться

Я не думаю, что можно сделать что-то как этот в C#. Вы могли или сделать Синтаксический анализ (), функция использует смещение или создает 3 массива байтов для начала; один для Заголовка IP, один для Заголовка TCP и один для Полезной нагрузки.

0
ответ дан Aistina 27 May 2011 в 05:27
поделиться

Вы могли использовать LINQ, чтобы сделать что-то как:

tcpbuffer.Skip(20).Take(20);

, Но Система. Буфер. BlockCopy / Система. Массив. Копия, вероятно, более эффективна.

1
ответ дан Steven Robbins 27 May 2011 в 05:27
поделиться

Это - то, как я решил его прибывающий из того, чтобы быть c программистом c# программисту. Мне нравится использовать MemoryStream для преобразования его в поток и затем BinaryReader для разбивания двоичного блока данных. Должны были добавить две функции помощника для преобразования от сетевого порядка до прямого порядка байтов. Также для создания байта [] для отправки видят , там путь, бросает объект назад к нему исходный тип без specifing каждый случай? , который имеет функцию, которые допускают преобразование из массива объектов к байту [].

  Hashtable parse(byte[] buf, int offset )
  {

     Hashtable tcpheader = new Hashtable();

     if(buf.Length < (20+offset)) return tcpheader;

     System.IO.MemoryStream stm = new System.IO.MemoryStream( buf, offset, buf.Length-offset );
     System.IO.BinaryReader rdr = new System.IO.BinaryReader( stm );

     tcpheader["SourcePort"]    = ReadUInt16BigEndian(rdr);
     tcpheader["DestPort"]      = ReadUInt16BigEndian(rdr);
     tcpheader["SeqNum"]        = ReadUInt32BigEndian(rdr);
     tcpheader["AckNum"]        = ReadUInt32BigEndian(rdr);
     tcpheader["Offset"]        = rdr.ReadByte() >> 4;
     tcpheader["Flags"]         = rdr.ReadByte() & 0x3f;
     tcpheader["Window"]        = ReadUInt16BigEndian(rdr);
     tcpheader["Checksum"]      = ReadUInt16BigEndian(rdr);
     tcpheader["UrgentPointer"] = ReadUInt16BigEndian(rdr);

     // ignoring tcp options in header might be dangerous

     return tcpheader;
  } 

  UInt16 ReadUInt16BigEndian(BinaryReader rdr)
  {
     UInt16 res = (UInt16)(rdr.ReadByte());
     res <<= 8;
     res |= rdr.ReadByte();
     return(res);
  }

  UInt32 ReadUInt32BigEndian(BinaryReader rdr)
  {
     UInt32 res = (UInt32)(rdr.ReadByte());
     res <<= 8;
     res |= rdr.ReadByte();
     res <<= 8;
     res |= rdr.ReadByte();
     res <<= 8;
     res |= rdr.ReadByte();
     return(res);
  }
1
ответ дан Community 27 May 2011 в 05:27
поделиться

Нет никакого способа использовать верифицируемый код, чтобы сделать это. Если Ваш метод Синтаксического анализа может иметь дело с наличием IEnumerable< byte> затем можно использовать выражение

TCPHeader tcp = Parse(packet.Skip(20));
LINQ
0
ответ дан JaredPar 27 May 2011 в 05:27
поделиться

Почему бы не зеркально отразить проблему и создать классы, которые накладывают буфер для вытаскивания битов?

// member variables
IPHeader ipHeader = new IPHeader();
TCPHeader tcpHeader = new TCPHeader();

// passing in the buffer, an offset and a length allows you
// to move the header over the buffer
ipHeader.SetBuffer( buffer, 0, 20 );

if( ipHeader.Protocol == TCP )
{
    tcpHeader.SetBuffer( buffer, ipHeader.ProtocolOffset, 20 );
}
0
ответ дан Johnie Karr 27 May 2011 в 05:27
поделиться

При реальной необходимости в подобных управление необходимо посмотреть unsafe функция C#. Это позволяет Вам иметь указатель и прикреплять его так, чтобы GC не перемещал его:

fixed(byte* b = &bytes[20]) {
}

Однако эта практика не предлагается для работы с управляемым, только кодируют, при отсутствии проблем производительности. Вы могли передать смещение и длину как в Stream класс.

3
ответ дан Mehrdad Afshari 27 May 2011 в 05:27
поделиться

Если IEnumerable<byte> приемлемо как вход, а не byte[], и Вы используете C# 3.0, то Вы могли записать:

tcpbuffer.Skip(20).Take(20);

Примечание, что это все еще выделяет экземпляры перечислителя под покрытиями, таким образом, Вы не выходите из выделения в целом, и таким образом, для небольшого количества байтов это может на самом деле быть медленнее, чем выделение нового массива и копирование байтов в него.

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

4
ответ дан Greg Beech 27 May 2011 в 05:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: