Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Исправление бесконечного цикла при чтении данных из сокета в Delphi

Delphi , Интернет и Сети , Сокеты

При работе с сокетами в среде Delphi разработчики часто сталкиваются с различными проблемами, одной из которых является бесконечный цикл при чтении данных. В данной статье мы рассмотрим, почему может возникать такая ситуация и как её можно исправить.

Описание проблемы

Работая с компонентами TClientSocket и TServerSocket в Delphi, разработчик столкнулся с проблемой бесконечного цикла при чтении данных из сокета. В коде чтения используется метод ReceiveBuf, который не возвращает значение 0, что должно было бы сигнализировать о завершении чтения. Вместо этого, цикл продолжается бесконечно.

Пример кода

procedure csRead(Sender: TObject; Socket: TCustomWinSocket);
var
   MSCli : TMemoryStream;
   cnt   : Integer;
   buf   : array [0..1023] of byte;
begin
    MSCli := TMemoryStream.Create;
    try
        repeat
          cnt := Socket.ReceiveBuf(buf[0], 1024);
          MSCli.Write(buf[0], cnt)
        until cnt = 0;
    finally
        MSCli.SaveToFile('somefile.dmp');
        MSCli.Free;
    end;
end;

Анализ проблемы

Метод ReceiveBuf возвращает количество полученных байт или 0, если сокет был закрыт. В случае, если сокет находится в режиме не блокировки и данные не доступны, ReceiveBuf может вернуть -1 с кодом ошибки WSAEWOULDBLOCK. Также, если сокет отсоединен, метод вернет 0. В случае возникновения реальной ошибки сокета, ReceiveBuf может поднять исключение ESocketError.

Подтвержденное решение

Использование метода SendStream не является хорошей практикой, так как он предназначен для отправки всего потока данных, после чего должен освободить его. Если сокет находится в режиме не блокировки и возникает блокировка во время отправки, SendStream завершит работу без освобождения потока. Более безопасный подход — избегать использования SendStream и напрямую вызывать SendBuf в цикле.

Альтернативный подход

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

Пример исправленного кода

procedure ReadRawFromSocket(Socket: TCustomWinSocket; Buffer: Pointer; BufSize: Integer);
var
  buf: PByte;
  cnt: Integer;
begin
  buf := PByte(Buffer);
  while BufSize > 0 do
  begin
    cnt := Socket.ReceiveBuf(buf^, BufSize);
    if cnt < 1 then
    begin
      if (cnt = -1) and (WSAGetLastError() = WSAEWOULDBLOCK) then
      begin
        Application.ProcessMessages;
        Continue;
      end;
      Abort;
    end;
    Inc(buf, cnt);
    Dec(BufSize, cnt);
  end;
end;

procedure ReadMemStreamFromSocket(Socket: TCustomWinSocket; Stream: TMemoryStream);
var
  cnt: Int64;
begin
  cnt := ReadInt64FromSocket(Socket);
  if cnt > 0 then
  begin
    Stream.Size := cnt;
    ReadRawFromSocket(Socket, Stream.Memory, cnt);
  end;
end;

procedure csRead(Sender: TObject; Socket: TCustomWinSocket);
var
  MSCli : TMemoryStream;
begin
  MSCli := TMemoryStream.Create;
  try
    ReadMemStreamFromSocket(Socket, MSCli);
    MSCli.SaveToFile('somefile.dmp');
  finally
    MSCli.Free;
  end;
end;

Заключение

Чтобы избежать бесконечного цикла при чтении данных из сокета в Delphi, рекомендуется использовать альтернативный подход с предварительной отправкой размера данных и чтением данных в цикле с обработкой возможных ошибок. Это позволит корректно обрабатывать ситуации, когда данные не доступны, и избегать непредвиденного поведения программы.

Создано по материалам из источника по ссылке.

Проблема заключается в бесконечном цикле при чтении данных из сокета в Delphi из-за неправильной обработки результатов метода `ReceiveBuf`.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Сокеты ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-02-05 07:53:02/0.0032539367675781/0