Как обработать ошибку сокета 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;
Когда обработчик возвращается, возможны две ситуации:
Обработано - Истина; Будет отправлен ответ, который приведет к новому исключению. Он будет передан обратно в вызывающий код (процедура в первом блоке), поэтому будет вызываться ShowException.
Обработано - ложь;
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)