Einzelnen Beitrag anzeigen

Arnulf

Registriert seit: 28. Okt 2004
Ort: Wien
271 Beiträge
 
#2

Re: UDP -> Vom Server Daten lesen

  Alt 1. Sep 2005, 21:27
Hi
naja das event wird ausgelöst, wenn du receivebuffer aufrufst.
Ist irgendwie nicht der sinn der sache.

Ich nehm mal an du willst von einem GameServer oder sowas ähnliches infos holen.
Genau das mach ich in meinem programm.
Jedenfalls kann ich dir sagen wie du das über indy machen würdest.
Wenn es dich interessiert, ich hab das auf 2 varianten gemacht.
1. ohne thread
hier liegt der vorteil in der linearität des programms, allerdings glaub ich verteufeln die methode viele .
2. mit thread
hier gibts auf jeden fall stress, wenn man noch nie mit threads gearbeitet hat.

In meiner Server application arbeite ich ohne thread weil ich ein sehr lineares programm hab, daß auf jeden fall auch auf den thread warten müsste, und das geht dann am sinn vom thread vorbei:

Delphi-Quellcode:
function GameServerExec( cmd : string ) : string;
         var ret : string;
             tryctr : integer;

         begin
               if fMain.cbxLogGS.Checked then
                  AddLogEntry( 'GameServerExec: send:' + cmd );
               cmd := 'rcon ' + fMain.edtRConPasswd.Text + #32 + cmd;

               tryctr := 0;
               ActiveSleep (5);

               fMain.UDPClient.Active := TRUE;
               ActiveSleep (5);

               ret := '';

               while (tryctr < 3)
               do
                     begin
                     try
                     fMain.UdpClient.Send( #255 + #255 + #255 + #255 + #2 + cmd );
                     except
                           AddLogEntry('Error on UDP Send');
                     end;

                     ActiveSleep (10);
                     try
                     ret := fMain.UdpClient.ReceiveString(); /// receive hängt
                     except
                           AddLogEntry('Error on UDP Receive');
                           ret := '';
                     end;

                     if ret = 'then
                     begin inc(tryctr);
                           if fMain.cbxLogGS.Checked then
                              AddLogEntry ('udp rsv failed trying again ' + InttoStr (tryctr));
                           ret := '';
                           ActiveSleep (20);
                     end
                     else tryctr := 3;

                     end; (* while *)

               fMain.UDPClient.Active := FALSE;

               if fMain.cbxLogGS.Checked then
                  AddLogEntry( 'GameServerExec response:' + ret );

               Application.ProcessMessages;
               GameServerExec := Copy( ret, 6, Length(ret)-5 );
        end;
Wichtig zu wissen ist wohl was ActiveSleep macht:

Delphi-Quellcode:
procedure ActiveSleep( MS : integer );
          var T : TDateTime;
              i : integer;

          begin //T := incmillisecond( Time, MS );
                For i := 1 to MS do
                    begin
                    application.ProcessMessages;
                    sleep (100)
                    end;

          end;
ActiveSleep ist eine routine die man immer wieder mal brauchen kann - immer wenn man keinen thread haben will, aber die application noch reagieren soll (auf events oder windows messages).

Die Variante mit thread ist wohl ungleich komplizierter.
Da ich mich selbst mit threads nicht gut auskenne, hab ich hier nur gebastelt - also bitte nicht schlagen, wenn das schrott ist .
Jedenfalls verwende ich das bei meinem Anticheat Client, da ich dort listen von gameserver verwalte und ich praktisch alle 1-2 sekunden ein update vom gameserver haben will:

Der Thread selbst:
Delphi-Quellcode:
function updatethread(p: Pointer): Integer;
var
  bShutDown: Boolean;
  s : string;
  i : integer;
begin
  bShutDown := False;
  while not bShutDown do
  begin
    // auf Client-Event warten
    WaitForSingleObject(EventReQuestSubmitted, INFINITE);
    bShutDown := UdpThreadCommand = UDPSHUTDOWN;
    UdpThreadCommand := '';
    if not bShutDown then
      begin
            fMain.udp.Active := TRUE;
            try
            fMain.udp.Send(#255 + #255 + #255 + #255 + #2 + 'getstatus');
            for i := 1 to 15 do
            begin if UdpThreadCommand = 'nextthen begin UdpThreadCommand := ''; s := ''; break; end;
                  s := fMain.udp.ReceiveString();
                  if s <> 'then break;
            end;
            except
            s := '';
            end;
            fMain.udp.Active := FALSE;
            if s = 'then s := 'TIMEOUT';
            SharedBuffer := s;
      end;
    // Client mitteilen, dass Request bearbeitet wurde
    InterLockedExchange(g_DataDelivered, 1);
  end;
  InterLockedExchange(g_DataDelivered, 1);
  result := 0;
end;
Hier sorgt ein Timer dafür, daß der thread immer wieder aktuallisiert, und im timer prüfe ich auch ob schon neue daten da sind:

Delphi-Quellcode:
procedure TfMain.tmrUpdateTimer(Sender: TObject);
begin
    if fMain.ClientSocket.Active then begin fMain.tmrUpdate.Enabled := FALSE; exit; end; // speziall für mein programm
    if (GsIp <> udp.Host) or (GsPort <> udp.Port) then // checken ob sich ip port ändern soll vom gameserver
    begin udp.Host := GsIp; // ist auch eher für mein programm wichtig
          udp.Port := GsPort; // weiß ja nicht was du vor hast
          exit;
    end;
    if ThreadID = 0 then // wenn der thread nicht läuft, darf auch der timer nicht laufen.
        begin tmrUpdate.Enabled := FALSE; exit; end;
    if InterLockedExchange(g_DataDelivered, 0) = 1 then // abfragen ob daten da sind
    begin
    UpdateForm; // update Form schreibt die daten in ein listview
    SetEvent(EventRequestSubmitted); // das event, daß den thread dazu bewegen soll daten abzurufen
    end;
end;
Ich hoffe das hilft dir - ich hab ziemlich lange gebraucht, daß alles hinzubekommen - naja ich hab damit auch angefangen mit Delphi zu programmieren

Arnulf
  Mit Zitat antworten Zitat