Как мне продолжать считывать данные из моего сокета для добавления моего буфера

#c# #arrays #.net #sockets #tcp

#c# #массивы #.net #сокеты #tcp

Вопрос:

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

КЛИЕНТ

 private void SendImage(byte[] opcode, byte[] length, byte[] payload)
{
    var packet = new byte[payload.Length   length.Length   1];
    Array.Copy(opcode, 0, packet, 0, 1);

    //Set the length
    Array.Copy(length, 0, packet, 1, length.Length);


    Array.Copy(payload, 0, packet, 5, payload.Length);
    _clientSocket.Send(packet);
}
  

Это отправляет просто отлично, я использую код операции 0x15 , который будет интерпретирован сервером как «есть входящее изображение». Длина равна payload.Length , с которой я это сделал

var length = BitConverter.GetBytes(myImage.Length);

Таким образом, он занимает 4 байта.

Итак, моя структура пакетов выглядит следующим образом OpCode(1 byte), Length(4 bytes), Payload(imageBytes)

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

СЕРВЕР

 private byte[] _buffer = new byte[1024];
private void ReceiveCallback(IAsyncResult ar)
{
    var client = (Socket)ar.AsyncState;
    int received = client.EndReceive(ar);

    //Temporary buffer
    var dataBuf = new byte[received];
    Array.Copy(_buffer, dataBuf, received);

    
    switch (dataBuf[0])
    {
        //Received image
        case 0x15:
            //Read the packet header and check the length of the payload
            var length = BitConverter.ToInt32(dataBuf.Skip(1).Take(4).ToArray(), 0);

            //This will hold the bytes for the image
            var imageBuffer = new byte[length];

            //First incoming packet payload (image bytes)
            var imgData = dataBuf.Skip(5).ToArray();

            //Copy that into the buffer
            Array.Copy(imgData, 0, imageBuffer, 0, imgData.Length);


            var pos = imgData.Length;
            //Keep reading bytes from the incoming stream
            while (dataBuf.Length > 0)
            {
                imgData = new byte[1024];
                client.Receive(imgData);
                Array.Copy(imgData, 0, imageBuffer, pos, dataBuf.Length);
                pos  = 1024;
            }

            //This takes the bytes and creates a bitmap from it
            AnotherViewModel.SetImage(imageBuffer);
            break;

        default:
            Debug.WriteLine("Wat");
            break;
    }

    client.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), client);

}
  

Проблемы, с которыми я сталкиваюсь, заключаются в том, что я не знаю, как продолжать добавлять входящие данные в imageBuffer , потому что я хочу получить полное изображение, а не только первые 4 байта, и с моим циклом while я в настоящее время получаю это исключение

Целевой массив был недостаточно длинным. Проверьте destIndex и длину, а также нижние границы массива.

В этой строке Array.Copy(imgData, 0, imageBuffer, pos, dataBuf.Length);

Как мне правильно прочитать все изображение, которое клиент отправляет на сервер?

Комментарии:

1. Возможно, вам потребуется проверить, сколько байт вы на самом деле получаете, вы, похоже, предполагаете, что это идеальное число, кратное 1024, что может быть не так. переменная pos должна увеличиваться только на фактически полученную длину, а не на 1024 (максимальный размер). Мои чувства паука говорят мне, что это последний блок, из-за которого у вас проблемы.

2. Я не хочу показаться грубым, но вам, возможно, потребуется разработать лучший протокол обмена данными. Подсчет байтов в сетевых потоках, по моему скромному мнению, не очень хорош. Посмотрите, как работает FTP. Тот факт, что вы отправляете все изображение в клиенте, не гарантирует, что оно таким образом поступит на сервер. Он, безусловно, будет фрагментирован на всем пути вниз и вверх по стеку tcpip. Сервер принимает данные асинхронно, поэтому я предполагаю, что код в ReceiveCallback вызывается много раз. Это неправильное место для чтения некоторых байтов и соответствующего переключения.