tIdHttpServer — EidConnClosed перед отправкой ответа на POST

У меня возникли проблемы с реализацией HTTP-сервера с indy 10 в delphi 2007.

Я настроил простой обработчик события CommandGet.

При ответе на данные, отправленные с использованием метода GET, я могу без проблем проанализировать параметры и отправить XML-данные обратно. (см. код ниже)

    Download := ARequestInfo.Params.Values['dld'];
    Config := ARequestInfo.Params.Values['config'];
    Flash := ARequestInfo.Params.Values['flash'];
    Employees := ARequestInfo.Params.Values['employees'];
    Schedule := ARequestInfo.Params.Values['schedules'];
    AppTables := ARequestInfo.Params.Values['apptables'];

    Heartbeat :=  NewHeartbeat;

    Heartbeat.Version.Dld := Download;
    Heartbeat.Version.Config := Config;
    Heartbeat.Version.Flash := Flash;
    Heartbeat.Version.Employee := Employees;
    Heartbeat.Version.Schedule := Schedule;
    Heartbeat.Version.AppTables := AppTables;

    AResponseInfo.ContentType := 'application/xml';
    AResponseInfo.ResponseNo := 200;
    AResponseInfo.ContentText := '<?xml version="1.0" encoding="utf-8"?>' +
      #13+#10 + FormatXMLData(Heartbeat.XML);

Когда я пытаюсь ответить на данные, которые отправляются с помощью POST, ответ никогда не отправляется indy, вместо этого TIdIOHandler.WriteDirect создает EidConnClosedGracefully из строки CheckForDisconnect(True, True). вот как я обрабатываю входящие данные POST

    XMLDocument1.xml.Clear;
    XMLDocument1.Active := True;
    XMLDocument1.XML.text := ARequestInfo.FormParams;

    SynMemo1.Lines.Add(ARequestInfo.FormParams);
    SynMemo1.Lines.Add(#13+#10);

    if XMLDocument1.XML.Count > 0 then
    begin
      XMLDocument1.XML.Delete(0);
      XMLDocument1.XML.Delete(0);

      for i := pred(xmldocument1.xml.count) downto 0 do
      begin
        stmp := XMLDocument1.XML.Strings[i];

        if Length(stmp) > 0 then
        begin
          if Copy(stmp,1,1) = '<' then
            break
          else
            XMLDocument1.XML.Delete(i);
        end
        else
          XMLDocument1.XML.Delete(i);

      end;

      XMLDocument1.XML.Text := StringReplace(XMLDocument1.XML.Text,
        '<Punches ', '<Punches xmlns="http://ats/punch" ', [rfReplaceAll]);



    end;

    Punch := GetPunches(XMLDocument1);

    PunchReply := NewOperationStatus;
    PunchReply.Uid := Punch.Uid;
    PunchReply.NodeValue := 'OK';

    stmp := '<?xml version="1.0" encoding="utf-8"?>' +
      #13+#10 + FormatXMLData(PunchReply.XML);
    SynMemo1.Lines.Add(stmp);
    SynMemo1.Lines.Add(#13+#10);

    AResponseInfo.ContentType := 'text/html';
    AResponseInfo.ContentStream := TStringStream.Create(stmp);

Я использовал wirehark, чтобы увидеть, что происходит, и похоже, что indy отправляет ACK до отправки ответа и вызывает отключение клиента.

чтобы проверить это, я настроил Apache с PHP и написал PHP-скрипт для выполнения той же работы, и все работает нормально. Разница в том, что на данные POST отвечает содержимое ответа, а не ACK.

любые предложения о том, как решить эту проблему, поэтому я отвечаю на данные POST, а также GET.


Я застрял с этим сейчас, как вы можете видеть из этой трассировки wireshark (щелкните ссылку для изображения), я увеличил время ожидания до 20 секунд. и он все еще не работает. Я собираюсь провести еще несколько исследований. и посмотреть, что я могу узнать. Похоже, Инди думает, что отключение произошло до того, как оно

Нажмите здесь, чтобы открыть изображение


person Mike Taylor    schedule 06.08.2010    source источник
comment
Я знаю, что не должен обращаться к компоненту SynMemo1 в этом коде без какой-либо синхронизации потоков, но он не работал до того, как я вставил его, и это просто быстрый и грязный способ вывода некоторой отладочной информации.   -  person Mike Taylor    schedule 06.08.2010


Ответы (2)


Похоже, http отправляется как

Transfer-Encoding: chunked

Следовательно, длина содержимого отсутствует. но версия Indy, которую я использую, не поддерживает этот режим.

person Mike Taylor    schedule 09.08.2010
comment
Вам необходимо обновиться до последней версии моментального снимка Indy 10.5.7, чтобы поддерживать сегментированные запросы. - person Remy Lebeau; 10.08.2010

Подтверждения отправляются не самим Indy, а базовым сокетом, и даже в этом случае только в ответ на пакеты, полученные от другой стороны. EIdConnClosedGracefully означает, что клиент намеренно отключает сокет на своем конце, прежде чем ваш сервер сможет отправить данные ответа. Тот факт, что присутствует ACK, помогает доказать это (сокет, скорее всего, ACK передает пакет FIN клиента во время отключения).

person Remy Lebeau    schedule 07.08.2010
comment
Это именно то, о чем я думал, пока не настроил apache и php, и все работало нормально. Также стоит отметить, что я могу перейти на страницу в порядке. В проводной акуле я получаю обычный SYN, SYN ACK, ACK, затем данные отправляются, затем ACK, затем FIN, ACK, FIN, ACK. Но в апаче между почтой данных и ACK отправляется ответ. Похоже, что подтверждение запускает отключение устройства. - person Mike Taylor; 08.08.2010
comment
SYN/SYN+ACK/ACK — это рукопожатие соединения. FIN/ACK/FIN/ACK — это согласованное отключение. Уверяю вас, что сам по себе ACK не приводит к отключению устройства. Любой сервер, будь то TIdHTTPServer или Apache, будет подтверждать данные HTTP-запроса устройства. Устройство просто не ждет вашего ответа TIdHTTPServer перед отключением. Не видя фактических следов Wireshark, я первым делом предположил, что на устройстве происходит тайм-аут чтения. Ваш TIdHTTPServer отвечает дольше, чем сервер Apache? - person Remy Lebeau; 08.08.2010
comment
Извините, может быть, я не ясно выражаюсь. Я не думаю, что подтверждение вызывает отключение, но сигнализирует устройству, что устройство должно инициировать рукопожатие отключения. Я также подумал, что проблема с тайм-аутом, глядя на трассировку wireshark, имеет смысл, но я ожидал, что tidhttpserver ответит менее чем за 5000 мс. Учитывая, что ответ пульса в методе get является более сложным ответом, чем ответ из почтовых данных. Я не понимаю, что может быть так долго. - person Mike Taylor; 08.08.2010
comment
Получение ACK НЕ приведет к отключению. Логика устройства должна обрабатывать отключение отдельно. - person Remy Lebeau; 10.08.2010