Я использую компонент Internet Direct TIdTCPClient для связи с удаленной службой для получения сообщения, которое обычно имеет размер около 5 КБ. Во время обычной операции я отправлю в службу около 400 запросов, каждый из которых занимает около 1 секунды. В большинстве случаев все работает отлично. Однако примерно один процент времени запроса занимает 189 секунд, и я вообще не получаю данных. Для простоты обсуждения я назову это провалом.
Мне особенно интересно понять, что именно происходит, когда происходит сбой, чтобы я мог представить свои доказательства издателю службы. Прежде всего, неудача не воспроизводима. Если я повторно отправлю неудавшийся запрос, существует очень высокая вероятность (возможно, 99 процентов), что он будет работать.
Я также фиксирую запрос, отправляемый в случае сбоя, поэтому я могу подтвердить, что запрос сформирован правильно.
Я предполагаю, что во время сбоя я получаю некоторые данные, но не все. Вот почему. Мой IdTCPClient имеет 30-секундный тайм-аут (я даже установил его на 5 секунд, но это не имело значения). Когда происходит сбой, он всегда дает сбой через 189 секунд (плюс около 500 миллисекунд).
В результате я думаю, что во время сбоя мой компонент получает поток данных, поэтому у моего клиента нет времени ожидания. И я предполагаю, что отключение происходит в службе, поскольку ни одно из моих значений тайм-аута никогда не устанавливается равным 189 секундам. С другой стороны, чтение IOHandler.AllData не вызывает исключение (даже исключение EIdConnClosedGracefully). Я правильно истолковываю эти доказательства?
То, что я хочу сделать, это подтвердить, что я получаю некоторые данные, но не все, до того, как служба прервет соединение. Кроме того, я хочу знать, как выглядят эти частичные данные, так как считаю, что они могут помочь определить источник ошибки.
В настоящее время мой запрос похож на следующий:
//ExceptionName is a temporary global variable
//that I am using while trying to solve this issue
ExceptionName = 'no exception';
try
s := GetRequest(id);
IdTcpClient1.Host := Host;
IdTcpClient1.Port := StrToInt(Port);
IdTcpClient1.ReadTimeout := ReadTimeout;
try
IdTcpClient1.Connect;
except
on e: exception do
begin
ExceptionName := e.ClassName;
raise EConnectionFailure.Create('Connection refused: ' + e.Message)
end;
end;
IdTcpClient1.IOHandler.Writeln(s);
try
Result := IdTcpClient1.IOHandler.AllData;
except
on E: EIdConnClosedGracefully do
begin
ExceptionName := e.ClassName;
//eat this exception
end;
on e: Exception do
begin
ExceptionName := e.ClassName;
raise;
end;
end;
finally
if IdTcpClient1.Connected then
IdTcpClient1.Disconnect;
end;
Использование IOHandler.AllData для чтения данных очень удобно, но я не могу получить какие-либо данные после сбоя (AllData возвращает пустую строку). Я проверил IOHandler.InputBufferIsEmpty после сбоя, и он возвращает True.
Я также пробовал другие методы для чтения данных, такие как IOHandler.ReadStream (это приводило к тому же результату, что и чтение AllData). Я также использовал IOHandler.ReadBytes и IOHandler.ReadByte (в сочетании с IOHandler.CheckForDataOnSource). Ничего не сработало.
Я ошибаюсь из-за частичной передачи данных? Если да, то почему я вижу постоянную задержку в 189.nnnn секунд до сбоя.
Если возможна частичная передача данных, какой подход я должен использовать для захвата каждого байта данных, полученных до сбоя.
Я использую Delphi 2009 для этого проекта и Indy 10, но я не думаю, что версия имеет к этому какое-либо отношение. Я не думаю, что это проблема Indy.
Редактировать: Я проверил связь между моим клиентом Indy и сервером, используя WireShark. Когда происходит один из этих сбоев, после отправки моего запроса сервер отправил два пакета [ACK] с последующим молчанием в течение чуть более 189 секунд. После этой задержки ответ включал [FIN, PSH, ACK], но без данных приложения.
Когда связь работала нормально, за двумя пакетами ACK, возвращенными сервером в ответ на мой запрос, последовал пакет данных приложения.
Изменить: Сообщить о проблеме издателю веб-службы, и я жду ответа.
Редактировать: Хорошо, издатель веб-службы ответил. Они признали проблемы с их стороны и решили некоторые из них. Мы больше не получаем тайм-ауты. Большинство ответов получаются примерно за 2 секунды, а некоторые - чуть дольше. Издатель работает над устранением оставшихся проблем.
Спасибо всем за ваш вклад.