Перед написанием статьи необходимо уточнить, что в исходном запросе пользователя присутствуют обсуждения и комментарии, которые указывают на ошибки в коде и предложения по их исправлению. В статье нужно будет описать общую проблему передачи изображения из Android-приложения на сервер Delphi, используя сокеты, а также подробно рассмотреть предложенные решения. Следует также включить примеры кода на Object Pascal для демонстрации исправленной логики сервера.
В данной статье рассмотрим проблему, с которой столкнулся разработчик при попытке передачи изображения из Android-приложения на сервер, написанный на Delphi. Проблема заключалась в том, что, несмотря на успешную отправку изображения клиентом, на сервере оно получалось пустым. В ходе обсуждения были выявлены несколько ключевых моментов, требующих внимания при работе с сокетами и передаче данных между клиентом и сервером.
Проблема и ее описание
При передаче изображения в формате Bitmap через сокет, где клиентом является Android-приложение, а сервером — исполняемый файл на Delphi, на стороне сервера изображение не получалось. Это было связано с тем, что, несмотря на корректную отправку данных клиентом, сервер не мог их правильно обработать и восстановить изображение.
Исходный код
В коде клиента (Android) изображение захватывалось и преобразуется в байтовый массив, который затем отправлялся на сервер. В коде сервера (Delphi) предполагалась обработка полученных данных и их сохранение в формате TBitmap.
Ошибка и предложенные решения
В ходе обсуждения были выявлены следующие проблемы:
Неправильная обработка размера получаемых данных на стороне сервера.
Отсутствие учета порядка байт (endian) при чтении данных.
Неправильная структура данных, отправляемых клиентом (необходимы заголовки файла bmp).
Подтвержденное решение
Для решения проблемы необходимо было:
Исправить логику чтения данных на сервере, учитывая возвращаемое значение функции ReceiveBuf().
Использовать функцию ntohl() для преобразования размера данных из big endian в little endian, соответствующий порядку байт в Delphi.
Отправить с клиента полные заголовки файла bmp или использовать другой формат, например PNG, который легче обрабатывается на стороне сервера.
Альтернативное решение
В качестве альтернативы можно было использовать функцию Bitmap.compress() для извлечения данных изображения в формате PNG, а на сервере использовать TPNGImage для загрузки полученных данных.
Пример кода на Delphi
procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
BytesReceived: Longint;
CopyBuffer: Pointer;
ChunkSize, TempSize: Integer;
Stream: TMemoryStream;
const
MaxChunkSize: Longint = 8192;
begin
if Socket.ReceiveLength > SizeOf(TempSize) then
begin
Socket.ReceiveBuf(TempSize, SizeOf(TempSize));
TempSize := ntohl(TempSize); // Преобразование из big endian в little endian
Stream := TMemoryStream.Create;
Stream.SetSize(TempSize);
end;
if TempSize > 0 then
begin
GetMem(CopyBuffer, MaxChunkSize);
try
while Socket.ReceiveLength > 0 do
begin
ChunkSize := Socket.ReceiveLength;
if ChunkSize > MaxChunkSize then ChunkSize := MaxChunkSize;
BytesReceived := Socket.ReceiveBuf(CopyBuffer^, ChunkSize);
Stream.Write(CopyBuffer^, BytesReceived);
end;
Stream.Position := 0;
with TPNGImage.Create do
try
LoadFromStream(Stream);
Image1.Picture.Graphic := Self;
finally
Free;
end;
finally
FreeMem(CopyBuffer, MaxChunkSize);
end;
end;
Stream.Free;
end;
Заключение
В данной статье были рассмотрены основные моменты, на которые следует обратить внимание при передаче данных между клиентом и сервером через сокеты. Исправление ошибок в коде сервера и клиента позволило успешно передавать изображения в формате PNG.
Проблема связана с некорректной передачей изображения из Android-приложения на сервер Delphi через сокеты из-за ошибок в обработке данных и формате передаваемого файла.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS