Dass die Verbindung geschlossen wurde, erkennst du daran, dass
recv() die Länge 0 zurückgibt.
Deswegen ja meine Änderung des Codes in die
repeat
-Schleife auf Basis des MS-Beispiels. Problem dabei: der zweite Schleifendurchlauf bleibt bei Aufruf der recv-Funktion stehen, d.h. die Verbindung wird eben nicht geschlossen, und der Aufruf von recv ist offensichtlich blockierend.
-----
Aber ich bin einen Schritt weiter. Mir ist aufgefallen, dass bei einem verkleinerten Sleep trotzdem teilweise noch Informationen ankommen, und zwar solche, die mittels POST in einem
SOAP-Envelope angefragt wurden. Ein Blick in den Code offenbarte dann, dass bei solchen POST-Anfragen mit
SOAP kein KeepAlive gesetzt wird, bei allen anderen schon:
Delphi-Quellcode:
function THTTPRequest.SendHeader: UTF8String;
[...]
if Length(FHTTPSend.Soap.Namespace) = 0 then begin
LHeader.Add(Format('Keep-Alive: %d', [KEEP_ALIVE]));
LHeader.Add('Connection: Keep-Alive');
end
else
LHeader.Add('Connection: Close');
Testweise habe ich die if-Bedingung auskommentiert und siehe da: es kommen alle Informationen an, auch mit einem
Sleep(20);
in TClient.ReceiveBuffer. Meine Schlussfolgerung: dem Server wurde im Header der Anfrage mitgeteilt, er soll die Verbindung offenhalten, was er offenbar auch tut. Deswegen wartet recv bis zum Empfang von Daten - also vermutlich "endlos".
Ich verstehe auch gar nicht, warum da ein KeepAlive angefordert wird. In THTTPRequest.Execute wird die Instanz von TClient unmittelbar nach dem Empfang der Daten sowieso zerstört - und der Socket damit ebenfalls geschlossen. Auszüge aus dem Code:
Delphi-Quellcode:
function THTTPRequest.Execute: Boolean;
[...]
SendStr := SendHeader + Params;
LClient := TClient.Create;
try
if LClient.Connect then begin
LClient.SendBuffer(SendStr, Length(SendStr));
if (LClient.ReceiveBuffer > 0) then begin
RcvdHeader(LClient.Header);
RcvdContent(LClient.Content);
end;
end;
finally
LClient.Free;
end;
destructor TClient.Destroy;
begin
if FConnected then
Disconnected;
inherited;
end;
function TClient.Disconnected: Boolean;
begin
Result := WinSock.shutdown(FSocket, SD_BOTH) = 0;
if Result then begin
FConnected := False;
Result := WinSock.CloseSocket(FSocket) = 0;
end;
end;
Wozu die Verbindung über KeepAlive offenhalten, wenn gleich danach der Socket geschlossen werden soll bzw. geschlossen wird
Grüße
Dalai