Как обработать ошибку сокета 10053 в SOAPServerwithINDYVCL в Delphi XE

Я создал SOAPServer с INDYVCL в Delphi XE. Когда клиент отключается от сервера по любой причине, например, из-за тайм-аута на стороне клиента или сбоя сетевого соединения. Я получаю сообщение об ошибке на стороне сервера, поскольку Socket Error 10053 - программное обеспечение вызвало прерывание соединения.

эта ошибка всплывает и блокирует мой поток на сервере.

Я также проверил это с демонстрацией SOAPDMServerIndy. Здесь также, если я запускаю сервер, подключаю клиента и до того, как сервер отвечает, отключает клиента, я получаю ошибку сокета.

Кто-нибудь знает, как справиться с этим исключением?

0 ответов

Даже в настоящее время эта проблема все еще существует. Это из-за этого кода:

procedure TWebRequestHandler.HandleException(Sender: TObject);
var
  Handled: Boolean;
  Intf: IWebExceptionHandler;
begin
  Handled := False;
  if ExceptObject is Exception and
    Supports(Sender, IWebExceptionHandler, Intf) then
    try
      Intf.HandleException(Exception(ExceptObject), Handled);
    except
      Handled := True;
      System.SysUtils.ShowException(ExceptObject, ExceptAddr);
    end;
  if (not Handled) then
    System.SysUtils.ShowException(ExceptObject, ExceptAddr);
end;

Линия Intf.HandleException(Exception(ExceptObject), Handled)вызывает процедуру TCustomWebDispatcher.HandleException. Эта процедура проверяет наличие обработчика событий OnException в потомке TWebModule в вашем приложении. Если он существует (я бы порекомендовал это), процедура обработчика событий вызывается с аргументом var 'Handled', установленным в значение true.

procedure TCustomWebDispatcher.HandleException(E: Exception; var Handled: Boolean);
begin
  Handled := False;
  if Assigned(FOnException) then
  begin
    Handled := True;
    if Response <> nil then
      Response.StatusCode := 500; { Allow the user to override the StatusCode }
    FOnException(Self, E, Handled);
    if Handled and (Response <> nil) then
      Response.SendResponse;
  end;
  if not Handled then
    if Response <> nil then
    begin
      Response.Content := Format(sInternalApplicationError, [E.Message, Request.PathInfo]);
      if not Response.Sent then
      begin
        Response.StatusCode := 500;
        Response.SendResponse;
      end;
      Handled := True;
    end;
end;

Когда обработчик возвращается, возможны две ситуации:

  1. Обработано - Истина; Будет отправлен ответ, который приведет к новому исключению. Он будет передан обратно в вызывающий код (процедура в первом блоке), поэтому будет вызываться ShowException.

  2. Обработано - ложь; Response <> nil будет оцениваться как True, поэтому, когда Response.Sent ложно то же самое произойдет.

Я решил это, попытавшись отправить ответ от обработчика события OnException. В случае сбоя возникает исключение. В этом случае я устанавливаю для поля "FResponse" свойства "Response", доступного только для чтения, моего потомка TWebModule значение "nil". Однако это поле является частным, поэтому я использовал некоторые rtti, чтобы получить к нему доступ.

procedure TwbmWebBrokerServerModule.UnlinkResponseObject;
begin
  inherited;

  TRTTIContext.Create.GetType(ClassInfo).GetField('FResponse').SetValue(Self, TValue.From(nil));
end;

procedure TwbmWebBrokerServerModule.WebModuleException(Sender: TObject; E: Exception; var Handled: Boolean);
begin
  uVMI_Tools.AppendToLog(E.Message + ' (' + Request.PathInfo + ')');

  if Request.Accept.Contains(CONTENTTYPE_APPLICATION_JSON) then
  begin
    Response.Content := StringToJSON(E.Message);
    Response.ContentType := CONTENTTYPE_APPLICATION_JSON;
  end
  else
    Response.Content := E.Message;

  try
    Response.SendResponse;
  except
    UnlinkResponseObject;
  end;
end;

Поэтому, когда при отправке ответа возникает исключение, для свойства Response устанавливается значение nil, поэтому попыток отправить ответ снова не будет.

Нет необходимости уничтожать объект ответа, достаточно присвоить ему nil. Это потому, что объект Response создается в классе TIdCustomHTTPServer, который только что передал его потомку TWebModule. (Фактически, к родительскому классу TWebModule TCustomWebDispatcher)

Другие вопросы по тегам