하나의 특정 요청에 대해 잘린 데이터를 반환하는 Delphi Indy IdTcpClient 읽기 작업

StackOverflow https://stackoverflow.com/questions/1278333

  •  16-09-2019
  •  | 
  •  

문제

이것은 제가 아직 해결하지 못한 흥미로운 문제입니다.

저는 인터넷을 통해 서버와 통신하는 클라이언트를 작성 중입니다.RAD Studio 2007 기본 특성을 사용하여 Indy 10에서 TIdTcpClient Internet Direct(Indy) 구성 요소를 사용하고 있습니다.

서버에서 데이터를 가져오기 위해 요청 세부 정보가 HTTP 메시지 본문에 포함되어 있는 포트 443을 통해 SSL을 사용하여 HTTP 요청을 발행합니다.여태까지는 그런대로 잘됐다.코드는 한 가지 예외를 제외하고는 매력처럼 작동합니다.

서버에서 약 336KB의 응답을 생성해야 하는 요청이 하나 있습니다. HTTP 응답 헤더에는 Content-Length가 포함되어 있습니다.344795).문제는 320KB만 돌려받는다는 것입니다.XML로 된 응답은 XML 요소 중간에서 명확하게 잘립니다.

그만한 가치가 있는 만큼 XML은 단순한 텍스트입니다.잘림을 설명할 수 있는 특수 문자는 없습니다.내 TIdTcpClient 구성 요소는 부분 응답을 받은 후 서버가 연결을 정상적으로 닫았다고 간단히 보고합니다. 이는 잘리지 않은 응답도 포함하여 모든 응답이 완료될 것으로 예상되는 방법이므로 문제가 되지 않습니다.

응답이 몇 K 바이트를 넘는 동일한 서버에 대해 거의 동일한 호출을 할 수 있으며 이 모든 것이 잘 작동합니다.한 요청은 약 850KB를 반환하고 다른 요청은 약 300KB를 반환하는 식으로 진행됩니다.

즉, 하나의 특정 요청에서만 이 문제가 발생합니다.많은 다른 요청은 완전한 응답을 받습니다.

나는 서비스 제작자와 이야기를 나눴으며 내 요청의 예를 제공했습니다.그는 요청이 정확하다고보고했습니다.그는 또한 자신의 서버에 동일한 요청을 보내면 완전한 응답을 받는다고 말했습니다.

나는 헤매고 있다.서비스 작성자의 실수로 실제로 그 쪽의 응답에 문제가 있거나, 내 요청에 뭔가 이상한 것이 있는 것 같습니다.

여기에 내가 놓친 해결책이 있나요?또한 여러 가지 다른 읽기 메커니즘(ReadString, ReadStrings, ReadBytes 등)을 사용했으며 모두 동일한 결과를 생성했습니다. 즉, 320KB 표시에서 이 특정 응답이 잘렸습니다.

코드는 관련성이 없을 수도 있지만 어쨌든 포함하겠습니다.죄송합니다. XML 요청에는 독점 정보가 포함되어 있으므로 포함할 수 없습니다.(ReadTimeout은 20초로 설정되어 있지만 1초 정도 후에 요청이 반환되므로 타임아웃 문제는 아닙니다.)

function TClient.GetResponse(PayloadCDS: TClientDataSet): String;
var
  s: String;
begin
  try
    try
      s := GetBody(PayloadCDS);
      IdTcpClient1.Host := Host;
      IdTcpClient1.Port := StrToInt(Port);
      IdTcpClient1.ReadTimeout := ReadTimeout;
      IdTcpClient1.Connect;
      IdTcpClient1.IOHandler.LargeStream := True;
      //IdTcpClient1.IOHandler.RecvBufferSize := 2000000;
      IdTcpClient1.IOHandler.Write(s);
      Result := IdTcpClient1.IOHandler.AllData;
    except
      on E: EIdConnClosedGracefully do
      begin
         //eat the exception
      end;
      on e: Exception do
      begin
        raise;
      end;
    end;
  finally
    if IdTcpClient1.Connected then
      IdTcpClient1.Disconnect;
  end;
end;
도움이 되었습니까?

해결책 2

원래 질문에서 언급했듯이 이 연결은 SSL을 사용합니다.이를 위해서는 IdTcpClient 구성 요소의 IOHandler 속성에 할당하는 IdSSLIOHandlerSocketOpenSSL 구성 요소를 사용해야 합니다.이 모든 것은 내 원래 디자인에 있었으며, 내가 언급한 것처럼 내 요청 중 많은 부분이 올바르게 응답되었습니다.

주말 동안 불완전한 응답을 반환하는 또 다른 요청을 발견했습니다.저는 원래 HTTP 요청을 캡처하고 SOAP UI라는 도구를 사용하여 해당 요청을 서버에 제출했습니다.SOAP UI를 사용하여 서버는 완전한 응답을 반환했습니다.분명히 서버가 아닌 내 클라이언트에 문제가 있는 것 같습니다.

다양한 속성을 살펴보며 마침내 해결책을 찾았습니다.최종적으로 문제를 수정한 속성은 IdSSLIOHandlerSocketOpenSSL 클래스의 SSLOptions 속성에 있었습니다.SSLOptions.Method의 기본값은 sslvSSLv2입니다.방법을 sslvSSLv23으로 변경하면 모든 응답이 완료되었습니다.

이 변경을 수행하기 전에 전체 응답이 아닌 일부 응답을 검색할 수 있었던 이유는 여전히 나에게 미스터리입니다.그럼에도 불구하고 IdSSLIOHandlerSocketOpenSSL.SSLOptions.Method를 sslvSSLv23으로 설정하면 문제가 해결되었습니다.

제안해 주신 Remy Lebeau에게 감사드립니다.

다른 팁

HTTP 요청을 보내므로 tidtcpclient 구성 요소 대신 직접 TIDHTTP 구성 요소를 사용해야합니다. TidHTTP가 직접 TIDTCPClient를 계속 사용하면 수동으로 처리 해야하는 HTTP 프로토콜에 대한 많은 세부 사항이 있습니다.

tidtcpclient를 계속 직접 사용하려는 경우 적어도 TidioAndler.allData () 메소드 사용을 중지해야합니다. 'Content-Length'답글 헤더를 추출 (헤더를 tstringlist 또는 tidheaderList에 캡처 한 다음 값을 사용한 다음 값을 사용한 다음 실제보고 된 바이트 카운트를 TidioAndler.ReadString () 또는 TidioAndler.ReadStream으로 전달합니다. (). 이는 응답이 끝날 때 서버의 연결이 끊기 때문에 읽기 I/O가 조기 읽기를 중단하지 않도록하는 데 도움이됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top