При работе с сетевыми соединениями в Delphi часто возникают проблемы, связанные с передачей файлов, в том числе и изображений. Одной из таких проблем является повреждение или неполучение файла на стороне сервера. В данной статье мы рассмотрим типичные ошибки, с которыми можно столкнуться при передаче изображений по сокетам, и предложим решение, основанное на лучших практиках использования компонентов TClientSocket и TServerSocket.
Проблема и её описание
Пользователь столкнулся с проблемой, при попытке отправить изображение из файла C:\picture.bmp на сервер в файл C:\temp\picture.bmp с использованием клиентского и серверного сокетов. В обработчике события OnConnect клиентского сокета используется метод SendStream, который должен отправить содержимое файла на сервер. На стороне сервера, в обработчике события OnClientRead, происходит приём данных и их запись в файл.
Анализ кода и предложения по исправлению
Код, предоставленный пользователем, содержит несколько ошибок, которые могут привести к повреждению или неполучению файла на стороне сервера. Основная проблема заключается в использовании методов SendStream и ReceiveLength, которые не гарантируют передачу полного потока данных за один вызов.
Исправление клиентского кода
В клиентском коде необходимо убедиться, что весь поток данных был отправлен. Для этого следует использовать цикл, который будет вызывать SendStream до тех пор, пока не будет отправлено всё содержимое файла.
procedure TForm2.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
var
fs: TFileStream;
sentBytes: Integer;
begin
fs := TFileStream.Create('C:\picture.bmp', fmOpenRead);
try
sentBytes := Socket.SendStream(fs);
while sentBytes < fs.Size do
sentBytes := Socket.SendStream(fs);
finally
fs.Free;
end;
end;
Исправление серверного кода
На стороне сервера необходимо сначала получить размер потока данных, а затем приём данных и их запись в файл должны происходить до тех пор, пока не будет получен весь поток.
procedure TForm2.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
fmm: TFileStream;
iLen, readBytes: Integer;
Bfr: Pointer;
begin
iLen := Socket.ReceiveLength;
SetLength(Bfr, iLen);
fmm := TFileStream.Create('C:\temp\picture.bmp', fmCreate or fmShareDenyWrite);
try
readBytes := Socket.ReceiveBuf(Bfr^, iLen);
fmm.Write(Bfr^, readBytes);
while readBytes = iLen do
begin
iLen := Socket.ReceiveLength;
SetLength(Bfr, iLen);
readBytes := Socket.ReceiveBuf(Bfr^, iLen);
fmm.Write(Bfr^, readBytes);
end;
finally
FreeMem(Bfr);
fmm.Free;
end;
end;
Общие рекомендации
Убедитесь, что сокет настроен на блокирующий или неблокирующий режим соответственно с вашими требованиями, но правильно обработайте возможные ошибки, связанные с блокировкой сокета.
Перед передачей файла отправляйте его размер, чтобы сервер мог подготовиться к приёму данных.
Используйте обработчики событий OnWrite и OnRead для корректной обработки данных, если сокет работает в неблокирующем режиме.
Заключение
Передача изображений по сокетам в Delphi может быть сложной задачей, требующей внимательного подхода к деталям. Использование правильных методик и лучших практик поможет избежать распространенных ошибок и обеспечит корректную передачу данных между клиентом и сервером.
Пользователь сталкивается с проблемой повреждения файла изображения после его передачи через сокеты в Delphi, что требует исправления кода и улучшения процесса передачи данных.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS