17. august 2007 - 13:18Der er
15 kommentarer og 2 løsninger
Socket uden svar
Jeg har lavet følgende klasse der laver en socket til en server for at hente data. Den sender fint men socket'ens OnReceive event bliver ikke kaldt. Hvad er der galt?
Skal jeg selv loope efter kaldet og vente på OnReceive kaldes eller hvad?
fSocket.Open; try Stream := TMemoryStream.Create; try Stream.WriteBuffer(Req,sizeof(TRequestRec)); Stream.Seek(0,soFromBeginning); if fSocket.Connected then begin fSocket.SendStream(Stream); // Fire away! result := true; end; finally Stream.Free; end; finally fSocket.Close; end; end;
// Never called! procedure TOpslag.SocketReply(aSender: TObject; aBuf: pchar; var aDataLen: integer); var i : integer; Found : boolean; ReplyRec : PReplyRec; RepError : integer; ErrorRec : TErrorRec; begin ReplyRec := PReplyRec(aBuf);
RepError := StrToInt(ReplyRec^.RepError);
fLastErrorRec := ErrorRecs[0]; // OK is standard for i := low(ErrorRecs) to high(ErrorRecs) do if ErrorRecs[i].Nr = RepError then begin fLastErrorRec := ErrorRecs[i]; break; end;
if assigned(fOnReceive) then fOnReceive(aSender, aBuf, aDataLen); end;
function DoRequest(aKey, aServer, aPort : pchar) : integer; var Opslag : TOpslag; begin Result:=-4;
if (StrLen(aServer) = 0) or (StrLen(aPort) = 0) then Exit;
Opslag := TOpslag.Create(aServer, aPort); try try // Opslag.LastErrorRec er altid "Undefined" da dens OnReceive aldrig udføres // Kommer der et svar som jeg bare ikke venter på?
if Opslag.SendRequest(aCpr) then begin if Opslag.LastErrorRec.Nr = 0 then Result := 0; end;
with Opslag.LastErrorRec do Log.Add(Format('Fejlkode %d: %s',[Nr,Text])); except on e: exception do MessageDlg(e.Message, mtError, [mbOK], 0); end; finally Opslag.Free; end; end;
Ja du skal på en eller anden måde vente med at kalde fSocket.Close indtil du har modtaget data i SocketReply eller til der er gået så lang tid at du ikke mener der kommer data.
Du kunne evt. benytte blocking socket for at undgå at skulle loope, jeg syntes det at skulle loope for at vente på data virker lidt fusket.
Også jeg, men jeg fandt ikke nogle gode eksempler der passede mig. Desuden troede jeg det var en blocking socket. Jeg forventede jo at eventen OnReceive blev kaldt automatisk.
Nu har jeg sat denne linje ind
fSocket.BlockMode := bmBlocking;
og min SendRequest ser sådan ud:
fSocket.Open; try Stream := TMemoryStream.Create; try Stream.WriteBuffer(Req,sizeof(TRequestRec)); Stream.Seek(0,soFromBeginning); if fSocket.Connected then begin fSocket.SendStream(Stream); result := fLastErrorRec.Nr = 0; end; finally Stream.Free; end; finally fSocket.Close; end;
... men i dokumentationen står at bmBlocking er default.
Nu fandt jeg TTcpClient i min Delphi 7 og jeg kan mindes at dengang jeg skiftede fra D4 til D7 og prøvede at bruge TTcpClient og TTcpServer men fik det aldrig til at virke. Derfor installerede jeg TServerSocket og TClientSocket som jeg kendte fra D4 og det virkede fint, jeg har dog kun brugt TServerSocket og TClientSocket som NonBlocking. De få gange jeg har haft brug for blocking socket har jeg brugt Indy.
Når du bruger blocking skal du i din SendRequest lige efter: fSocket.SendStream(Stream); have en linie der læser fSocket.ReceiveStream(Stream, timeout); // eller hvad den nu hedder
og fSocket.OnReceive skal slet ikke benyttes når det er blocking socket vil jeg mene.
Der er en ReceiveBuf som så ud til at kunne bruges, men ved at kigge i koden kan jeg se at den selv trigger en fSocket.OnReceive hvis bare result <> SOCKET_ERROR. Der burde altså ikke være forskel der.
Nu er det altså ligefør jeg dropper koden projektet og kører over i Indy. Tanken var ellers en low-level implementering uden tredjeparts pakker.
Jeg mener også at kunne huske at Indy eller ICS er et langt bedre bud, med mindre du vil lave det hele selv, Delphi's implementering er skod, men de valgte jo også at sende en Indy pakke med ud, sikkert fordi de ikke gad bruge til på en ordenlig impl. :)
Jeg har selv brugt ICS's componenter som forøvrigt også er freeware og med source ( http://www.overbyte.be )
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.