#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 вызывается много раз. Это неправильное место для чтения некоторых байтов и соответствующего переключения.