Write () и Read () необработанные байты из NetworkStream, данные - это разница в несколько байтов - PullRequest
2 голосов
/ 23 мая 2019

Я написал некоторый код для отправки массива byte [] с использованием NetworkStream с размером KNOWN перед отправкой, но отправленные данные и полученные данные различаются в некоторых позициях.

MAXSIZE - известный размер данныхЯ хочу отправить.

    public static void SendBytes(TcpClient clientSocket, byte[] outStream)
    {
        Debug.WriteLine("SendBytes() number of bytes: " + outStream.Length.ToString());

        NetworkStream serverStream = clientSocket.GetStream();

        serverStream.Write(outStream, 0, outStream.Length);
        //serverStream.Flush();
    }

    public static byte[] ReceiveBytes(TcpClient clientSocket, int MAX_SIZE)
    {
        Debug.WriteLine("[" + DateTime.Now.ToString("G") + "] - " + "ReceiveBytes() started.");

        NetworkStream networkStream = clientSocket.GetStream();

        byte[] bytesFrom = new byte[MAX_SIZE];
        clientSocket.ReceiveBufferSize = MAX_SIZE;

        networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);

        Debug.WriteLine("[" + DateTime.Now.ToString("G") + "] - " + "ReceiveBytes(), received number of raw bytes: " + bytesFrom.Length.ToString());

        return CommonUtils.SubArray(bytesFrom, 0, MAX_SIZE);
    }

При отправке данных (байты в шестнадцатеричном формате): a7 fc d0 51 0e 99 cf 0d 00, полученные данные: a7 fc d0 51 0e 99 cf 0d 53

Ответы [ 2 ]

2 голосов
/ 23 мая 2019

Скорее всего, вы видите мусор из-за структурирования пакетов;TCP только гарантирует, что правильные байты будут поступать в правильном порядке (или сбой потока) - он ничего не говорит о кусках , в которые они поступают.Поэтому vital означает, что вы:

  1. поймаете возвращаемое значение из Read и обработаете только столько байтов из любого куска
  2. выполнить ваше собственное кадрирование - то есть группировать поток в сообщения независимо от того, как куски прибывают

Если ваши сообщения всегда имеют фиксированный размер, то «2» становится «буферными данными, пока я не получупо крайней мере, N байтов, затем обрабатывают данные кусками по N, сохраняя все, что осталось, затем возобновляют буферизацию ".Но в общем случае это может быть «буфер до тех пор, пока я не увижу значение дозорного, например, перевод строки», или «буфер до тех пор, пока у меня не будет полный заголовок, затем проанализируйте заголовок, чтобы увидеть, сколько данных ожидать, затем выполните буфердо тех пор, пока у меня не будет столько данных ".

Существуют инструменты и утилиты, которые помогают упростить де-кадрирование и обработку невыполненных заданий - например, с новым API" конвейеры "это просто случай проверки каналаи сообщая каналу, сколько вы хотите потребить (вместо того, чтобы дать вам все, и у вас нет возможности сейчас отклонить данные), - но переключение с Stream на «конвейеры» для большинства людей представляет собой довольно незначительный набор изменений.

В вашем случае вы, вероятно, можете использовать:

byte[] bytesFrom = new byte[MAX_SIZE];
int outstanding = MAX_SIZE, read, offset = 0;
while (outstanding > 0 && (read = networkStream.Read(bytesFrom, offset, outstanding)) > 0)
{
    offset += read;
    outstanding -= read;
}
if (outstanding != 0) throw new EndOfStreamException();

Это создает цикл чтения, который полностью заполняет bytesFrom или завершается с ошибкой.

1 голос
/ 23 мая 2019

Stream.Read возвращает значение, которое указывает, сколько данных было на самом деле прочитано.Это ни в коем случае не гарантирует, что будет та же сумма, что и вы.Игнорируйте это значение на свой страх и риск.

Если вы счастливы выделить память для всего потока, почему бы просто не скопировать в MemoryStream и скопировать из этого полный буфер?Stream.CopyTo и Stream.CopyToAsync - хорошие абстракции высокого уровня, которые облегчают эту задачу.

...