09. november 2009 - 09:57Der er
32 kommentarer og 1 løsning
TIdTCPServer
Jeg sidder og roder med at lave et program der kan modtage kommandoer via TCP. Til det bruger jeg Indy TIdTCPServer og det virker som sådan også fint. Dog mangler jeg at finde ud af at svar fra serveren kun skal gå til 1 bestemt klient - den der har sendt forespørgslen. Jeg har ikke kunnet finde den røde tråd i nogle af de eksempler jeg har kunnet opstøve på nettet, så hvis du ligger inde med et eksempel, så er jeg meget interesseret.
I dens OnExecute event skulle der gerne være et object der hedder AContext. Det er det som du skal bruge til at læse bufferen og svare med, fx:
procedure TMainForm.TestServerExecute(AContext: TIdContext); var strRequest: String; begin strRequest := AContext.Connection.IOHandler.ReadLn(); if (strRequest='ping') then AContext.Connection.IOHandler.WriteLn('pong'); end;
Det er på plads det hele - men jeg ville gerne kunne se hvem der sender beskeder og så kun svare til den. Men det er ikke sikkert at det er muligt. I så fald må jeg bare begrænse det til en 1 bruger version.
Jeg har et andet issue med at jeg gerne vil have slået standard reply helt fra - det kan jeg ikke lige se hvordan jeg gør. Jeg har fjernet alle de steder jeg kan se det, men uden held.
Det kan sagtens lade sig gøre. Tilknyt en client struct til AContext.Data når forbindelsen bliver oprettet. Bare husk at slette den igen når de disconnecter. :)
type PClient = ^TClient; TClient = packed record // Basic information IP: String; DNS: String; LastAction: TDateTime; ConnectedAt: TDateTime; // ... andet information du måske ville bruge end;
procedure TMainForm.ServerExecute(AContext: TIdContext); var strRequest: String; Client: PClient; begin Client := PClient(AContext.Data); if not (Client<>nil) then Exit; Client.LastAction := Now;
strRequest := AContext.Connection.IOHandler.ReadLn(); if (strRequest='ping') then AContext.Connection.IOHandler.WriteLn('pong'); end;
procedure TMainForm.ServerDisconnect(AContext: TIdContext); var Client: PClient; begin Client := PClient(AContext.Data); FreeMem(Client); AContext.Data := nil; end;
Dog har jeg droppet ideen om kun at sende til 1 klient - det kan man vist ikke. Jeg har i stedet begrænset det til 1 bruger ad gangen som også er rigeligt i mit tilfælde.
Man kan sagtens lave det så du kan klare en masse klienter på én gang. Giv mig et specifikt eksempel på hvad du er ved at lave, så laver jeg noget du kan bygge videre på. :)
Jeg har en 'server' der står og lytter En klient connecter sig og afsender nogle fjernstyringskommandoer. Disse behandler serveren og sender svar tilbage til klienten. Efterfølgende disconnecter serveren forbindelsen.
Ja og en af de væsentlige forskelle så vidt jeg kan se er TIdPeerThread som ikke er i 10'eren at jeg kan finde. Det må være på en anden måde det er lavet.
Jeg sidder lidt og undre mig over hvordan du har fået idTCPServer til kun at virke som "enkeltbruger", idTCPServer er jo en server og kan uden noget extra kode klare mange brugere på samme tid. Jeg bruger selv komponenten og har op til 40 brugere logget på på samme tid som sender kommandoer til serveren og får svar retur, det eneste man skal gøre er at modtage kommandoen i ServerExecute og sende svaret til klienten i ServerExecute som preppydude også har givet et eks. på.
Ja, OnExecute kaldes kun for den klient som har sendt noget til serveren, og det er kun den klient du svarer. Alle andre bliver kørt seperart i et andet event, da IdTcpServer er multi-threaded.
Det er da fordi jeg har siddet og rodet med den forkerte komponent hele tiden. Jeg har brugt den der hedder idCmdTCPServer i stedet for idTCPServer. Det giver noget helt andet resultat. idTCPServer kan styres lidt strammere i kode.
Det synes jeg også at jeg gør. Men det kan da være der er en eller anden fiks måde at sikre det på.
Men rent faktisk sker det også hvis programmet kører og jeg lukker uden at der har været logget nogen på. Men fjerner jeg den AntiFreeze komponent, så virker det tilsyneladende.
Er AntiFreeze ikke kun beregnet til at bruges hvis man kalder nogle Indy funktioner i main tråden for at undgå at programmet fryser mens data overføres?
Er ikke helt inde i den, men mener generelt den bare gør så programmet ikke fryser overhovedet. Men prøv det jeg sagde og fortæl mig om det ikke hjalp på det - evt kan du prøve at lukke uden der er nogen klienter på serveren.
Du har sandsynligvis ret i at det er fordi connection ikke er afbrudt til klienter for jeg kan se at hvis jeg connecter fra en klient og så prøver at lukke programmet, så går det galt.
Hvordan kan jeg force alle connections til at close?
Try If idTCPServer.Contexts <> Nil Then Begin With idTCPServer.Contexts.LockList Do Try For intX := 0 To Count - 1 Do Begin TIdContext(Items[intX]).Connection.IOHandler.WriteLn(conCode_Status_Disconnected); TIdContext(Items[intX]).Connection.Disconnect(False); End; Finally idTCPServer.Contexts.UnlockList; End; End; Sleep(idTCPServer.TerminateWaitTime); idTCPServer.Active := False; Finally End;
procedure TMainForm.FormDestroy(Sender: TObject); var List: TList; begin List := Server.Contexts.LockList; try Application.ProcessMessages; while (List.Count>0) do begin try TIdContext(List.Items[0]).Connection.Disconnect; except on E:Exception do TIdContext(List.Items[0]).Destroy; end; end; finally Server.Contexts.UnlockList; end; Sleep(Server.TerminateWaitTime); Server.Active := False; end;
Synes godt om
Ny brugerNybegynder
Din løsning...
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.