Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Connection Closed Gracefully. (https://www.delphipraxis.net/144976-connection-closed-gracefully.html)

RedShakal 21. Dez 2009 00:00


Connection Closed Gracefully.
 
Hallo, wie ein paar von euch wissen hab ich ja einen kleinen Server geschrieben der auf einen Linux Debian Vserver laufen soll. Da ich zu doof bin den Server für Linux zu kompilen, habe ich ihn bis jetzt immer mit Wine Emuliert. Das klappte bis jetzt auch sehr gut. Heute habe ich allerdings ein Logfile eingebaut und seitdem klappt er nichtmehr richtig. Okok er klappt garnicht mehr. Sobald jemand connected wird die Verbindung abgebrochen.

Ich poste einen Teil des Sourcecodes:

Delphi-Quellcode:
AssignFile(f, 'log\'+DateToStr(Date)+'.txt');
   if FileExists('log\'+DateToStr(Date)+'.txt') then
     begin
       Append(f)
     end
   else
     begin
       Rewrite(f);
     end;

Genau an der Rewrite stelle bleibt er stehen.


- Ich habe bereits versucht den Datein die Chmod rechte zu geben.
- Ich habe bereits allen Datein und Ordnern testweise 777 gegeben.
- ich habe versucht statt log\ einfach mal log/ zu machen
- ich habe versucht die Datei manuell zu erstellen. Er springt trozdem zu Rewrite
- Ich habe versucht das ganze als Root im Home verzeichnis auszuführen

Was kann ich noch tun?


P.S. Unter Windows läuft der Server übrigens Problemlos.


Edit: Auch wenn sich die Log Datein im gleichen Verzeichnis befinden wie der Server befinden, klappt es nicht.
"AssignFile(f, DateToStr(Date)+'.txt');"


Edit: Ich glaub ich hab den Fehler gefunden. Ich habe eine Debug Nachicht eingebaut die mir statt 21.12.09 folgendes ausgegeben hat:

"File log\12/21/2009.txt existiert nicht"


Edit:

So ich hab das Problem jetzt gelöst.

Delphi-Quellcode:
procedure TServer.IdTCPServer1Execute(AThread: TIdContext);
var
   f          : TextFile;
   Files      : string;
   myDate     : TDateTime;
   myYear, myMonth, myDay : Word;
begin
  myDate := Date;
  DecodeDate(myDate, myYear, myMonth, myDay);

   Files := ('log\'+IntToStr(myDay)+'-'+IntToStr(myMonth)+'-'+IntToStr(myYear)+'.txt');
   AssignFile(f, Files);
   if FileExists(Files) then
     begin
       Append(f)
     end
   else
     begin
       Rewrite(f);
     end;
Begründung:

Unter Windows gibt Date "21.12.09" aus. Unter Linux jedoch "12/21/2009". Dies führt zu komplikationen bei den Pfadangaben und damit zum Fehler.
Lösung: mit DecodeDate das Datum in die Einzelteile aufteilen und anschließend selbst zusammensetzen. Ich habe als Trennzeichen "-" benutzt.
Damit erhalte ich Datumsangaben im format "21-12-09".

Astat 21. Dez 2009 00:54

Re: Connection Closed Gracefully.
 
Zitat:

Zitat von RedShakal
Was kann ich noch tun?

Hallo RedShakal, womöglich liegts an der IO Prüfung?

Delphi-Quellcode:
 
  AssignFile(f, 'log\' + DateToStr(Date) + '.txt');
  if FileExists('log\' + DateToStr(Date) + '.txt') then
    {$I-} Append(f) else Rewrite(f); {$I+}

  if IOResult <> 0 then RaiseLastWin32Error;
Was gibt hier IOResult aus?

lg. Astat

RedShakal 21. Dez 2009 01:12

Re: Connection Closed Gracefully.
 
Das Problem ist doch noch nicht so gelöst wie ich dachte.

Delphi-Quellcode:
myDate := Date;
  DecodeDate(myDate, myYear, myMonth, myDay);

   Files := ('log\'+IntToStr(myDay)+'-'+IntToStr(myMonth)+'-'+IntToStr(myYear)+'.txt');
   AssignFile(f, Files);

   if FileExists(Files) then
     begin
       Append(f);
       WriteLn('ap');
     end
   else
     begin
       Rewrite(f);
       WriteLn('rw');
     end;
So sieht meine Konsole aus:

Delphi-Quellcode:
#######################
##                   ##
## Masterserver 0.03 ##
##                   ##
#######################

Server wurde initialisiert.
Server lauscht auf Port: 5000

ap
[2:10:00 AM] Account: fff existiert nicht.
ap
Beim ersten durchlauf klappt alles. ( Was mich wundert ist das er Append(f); 2x aufruft.
Beim zweiten durchlauf gibts wieder die Meldung "Connection Closed Gracefully."
Er scheint aber dennoch mind. bis "AssignFile(f, Files);" zu arbeiten. Wenn ich da eine WriteLn einbaue, wird diese trozdem noch aufgerufen.



Edit:

Die Datei wird ordnungsgemäß über Closefile geschlossen.
Beim zweiten durchlauf bleibt er bei "Append(f);" stehen.
Die Frage die sich stellt: Wieso ruft er "Append(f);" 2x auf. Nirgenswo ist eine schleife einprogrammiert...


Edit:

Ich poste am besten mal den kompletten Part:

Delphi-Quellcode:
procedure TServer.IdTCPServer1Execute(AThread: TIdContext);
var
  Data        : String;
  StrArr      : TDynStringArray;
  ini         : TIniFile;
   f          : TextFile;
   Files      : string;
   myDate     : TDateTime;
   myYear, myMonth, myDay : Word;
begin
 with AThread.Connection do
begin
  myDate := Date;
  DecodeDate(myDate, myYear, myMonth, myDay);

   Files := ('log\'+IntToStr(myDay)+'-'+IntToStr(myMonth)+'-'+IntToStr(myYear)+'.txt');
   AssignFile(f, Files);

   if FileExists(Files) then
     begin
       Append(f);
     end
   else
     begin
       Rewrite(f);
     end;

   Data := String(Socket.ReadLn);
   Data := Trim(Data);
   if Length(Data) > 0 then
     begin
       StrArr := Explode('|', Data);
       if StrArr[0] = 'login' then
         begin
             if StrArr[3] = Clientver then
               begin
                 if FileExists('accounts\'+StrArr[1]+'.ini') then
                   begin
                     ini := TIniFile.Create('accounts\'+StrArr[1]+'.ini');
                     try
                       if StrArr[2] = ini.ReadString('Data','Passwort','') then
                         begin
                           Socket.WriteLn('login');
                           WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' hat sich eingeloggt.');
                           WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' hat sich eingeloggt.');
                         end
                       else
                         begin
                           Socket.WriteLn('invalid');
                           WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' falsches Passwort.');
                           WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' falsches Passwort.');
                         end;
                     finally
                       ini.free;
                     end;
                   end
                 else
                   begin
                     Socket.WriteLn('na');
                     WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert nicht.');
                     WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert nicht.');
                   end;
               end
                 else
                   begin
                     Socket.WriteLn('version');
                   end;
         end;

       if StrArr[0] = 'register' then
         begin
           if FileExists('accounts\'+StrArr[1]+'.ini') then
             begin
               Socket.WriteLn('vorhanden');
               WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert bereits.');
               WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert bereits.');
             end
           else
             begin
               try
                 ini := TIniFile.Create('accounts\'+StrArr[1]+'.ini');
                 ini.WriteString('Data','Passwort',StrArr[2]);
                 ini.WriteString('Data','E-Mail',StrArr[3]);
               finally
                 Socket.WriteLn('erfolg');
                 ini.free;
                 WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' wurde registriert.');
                 WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' wurde registriert.');
               end;
             end;
         end;
     end;
 end;
  CloseFile(f);
end;


Zitat:

Zitat von Astat
Zitat:

Zitat von RedShakal
Was kann ich noch tun?

Hallo RedShakal, womöglich liegts an der IO Prüfung?

Delphi-Quellcode:
 
  AssignFile(f, 'log\' + DateToStr(Date) + '.txt');
  if FileExists('log\' + DateToStr(Date) + '.txt') then
    {$I-} Append(f) else Rewrite(f); {$I+}

  if IOResult <> 0 then RaiseLastWin32Error;
Was gibt hier IOResult aus?

lg. Astat

Also er zeigt mir in der Tat jetzt einen IO ERROR. Der Fehler tritt sowohl auf Windows als auch auf Linux auf.
"if IOResult <> 0 then RaiseLastWin32Error;" gibt garnichts aus.
Der Debugger sagt folgendes:

---------------------------
Debugger Exception Notification
---------------------------
Project Project1.exe raised exception class EInOutError with message 'I/O error 32'.
---------------------------
Break Continue Help
---------------------------

Astat 21. Dez 2009 02:02

Re: Connection Closed Gracefully.
 
Zitat:

Zitat von RedShakal
Das Problem ist doch noch nicht so gelöst wie ich dachte.

1. Das Problem mit dem Datumsseparator:
Delphi-Quellcode:
DateSeparator := '.';
2. Das Problem mit dem mehrfachen Aufruf:
Delphi-Quellcode:
procedure TServer.IdTCPServer1Execute(AThread: TIdContext);
Ist ein Serverthread, dieser wird auch mehrfach aufgerufen werden können.

Dh. Die Log-Schreiberei und Globalen Variablen müssen Threadsave sein, sonst knallts sowiso irgendwann.

Tip: Das Logging in eine Threadsave Funktion auslagern, und mit CriticalSections synchronisieren.

Delphi-Quellcode:
var
  _SyncLog: TRTLCriticalSection;

procedure LogWrite(const ALogfile, AMessage: string);
var
  f: TextFile;
begin
  EnterCriticalSection(_SyncLog);
  try
    AssignFile(f, ALogfile);
    try
      {$I-}
      if FileExists(ALogfile) then Append(f) else Rewrite(f);
      if IOResult <> 0 then Reset(f);
      {$I+}
      Writeln(f, AMessage);
    finally
      CloseFile(f);
    end;
  finally
    LeaveCriticalSection(_SyncLog);
  end;
end;

initialization
  InitializeCriticalSection(_SyncLog);
finalization
  DeleteCriticalSection(_SyncLog);
end.
lg. Astat

alzaimar 21. Dez 2009 06:30

Re: Connection Closed Gracefully.
 
Zitat:

Zitat von Astat
1. Das Problem mit dem Datumsseparator:
Delphi-Quellcode:
DateSeparator := '.';

Meinst Du nicht, man schießt mit Kanonen auf Spatzen und handelt sich u.U. unangenehme Seiteneffekte ein?
Eine einfache Funktion, die einen Dateinamen für Logdateien erstellt, ist doch ausreichend:
Delphi-Quellcode:
Function GetLogFilename() : String;
Var
  y,m,d : Word;

Begin
  DecodeDate(Now,y,m,d);
  Result := Format('log\%.2d-%.2d-%.2d.TXT',[y,m,d]);
End;

RedShakal 21. Dez 2009 10:56

Re: Connection Closed Gracefully.
 
Zitat:

Zitat von Astat
Zitat:

Zitat von RedShakal
Das Problem ist doch noch nicht so gelöst wie ich dachte.

1. Das Problem mit dem Datumsseparator:
Delphi-Quellcode:
DateSeparator := '.';
2. Das Problem mit dem mehrfachen Aufruf:
Delphi-Quellcode:
procedure TServer.IdTCPServer1Execute(AThread: TIdContext);
Ist ein Serverthread, dieser wird auch mehrfach aufgerufen werden können.

Dh. Die Log-Schreiberei und Globalen Variablen müssen Threadsave sein, sonst knallts sowiso irgendwann.

Tip: Das Logging in eine Threadsave Funktion auslagern, und mit CriticalSections synchronisieren.

Delphi-Quellcode:
var
  _SyncLog: TRTLCriticalSection;

procedure LogWrite(const ALogfile, AMessage: string);
var
  f: TextFile;
begin
  EnterCriticalSection(_SyncLog);
  try
    AssignFile(f, ALogfile);
    try
      {$I-}
      if FileExists(ALogfile) then Append(f) else Rewrite(f);
      if IOResult <> 0 then Reset(f);
      {$I+}
      Writeln(f, AMessage);
    finally
      CloseFile(f);
    end;
  finally
    LeaveCriticalSection(_SyncLog);
  end;
end;

initialization
  InitializeCriticalSection(_SyncLog);
finalization
  DeleteCriticalSection(_SyncLog);
end.
lg. Astat


Ehrlich gesagt ist mir der Code etwas zu kompliziert. Schon mein Lehrer hat damals immer gesagt kopiere nie was du nicht verstehst :stupid:




__________________________________________________ __________


Zitat:

Zitat von alzaimar
Zitat:

Zitat von Astat
1. Das Problem mit dem Datumsseparator:
Delphi-Quellcode:
DateSeparator := '.';

Meinst Du nicht, man schießt mit Kanonen auf Spatzen und handelt sich u.U. unangenehme Seiteneffekte ein?
Eine einfache Funktion, die einen Dateinamen für Logdateien erstellt, ist doch ausreichend:
Delphi-Quellcode:
Function GetLogFilename() : String;
Var
  y,m,d : Word;

Begin
  DecodeDate(Now,y,m,d);
  Result := Format('log\%.2d-%.2d-%.2d.TXT',[y,m,d]);
End;

Das klappt so leider auch nicht so ganz. Der IO Fehler besteht trozdem.
Es scheint so als würde er die Datei nicht richtig schließen, weil ich sie solang der Server läuft auch nicht im Windows öffnen kann.
Deshalb habe ich jetzt mal Testweise unter jedes WriteLn ein Closefile geschrieben. Leider ohne erfolg.

alzaimar 21. Dez 2009 12:01

Re: Connection Closed Gracefully.
 
Delphi-Quellcode:
Function GetLogFilename() : String;
Var
  y,m,d : Word;

Begin
  DecodeDate(Now,y,m,d);
  Result := IncludeTrailingPathDelimiter('log')+Format('%.2d-%.2d-%.2d.TXT',[y,m,d]);
End;
Sind bei Linux die Pfadbegrenzer nicht '/' anstatt '\' ?

RedShakal 21. Dez 2009 12:15

Re: Connection Closed Gracefully.
 
Das ganze dürfte durch Wine ausgeglichen werden.
Der Server läuft leider unter Windows genausowenig.

TurboMartin 21. Dez 2009 17:10

Re: Connection Closed Gracefully.
 
Bei deinem Pfad muss solltest Du darauf achten / als Ordnergrenze zu verwenden. Zudem, wenn Du von deinem eigenen Pfad ausgehst, musst fehlt davor ein ./, sodas letztendlich der Pfad folgendermaßen aussieht: ./log/Datum.txt.

himitsu 21. Dez 2009 17:22

Re: Connection Closed Gracefully.
 
Zitat:

Zitat von TurboMartin
Zudem, wenn Du von deinem eigenen Pfad ausgehst, musst fehlt davor ein ./, sodas letztendlich der Pfad folgendermaßen aussieht: ./log/Datum.txt.

Vorallem unter Windows (ich weiß nicht, wie es Linux/Wine mit relativen Pfaden hat) bringt das ./ garnichts, da es im Endefekt auf's Selbe hinausgeht.

Wobei man sowieso keine relativen Pfade nutzen sollte.

RedShakal 21. Dez 2009 17:27

Re: Connection Closed Gracefully.
 
Beim ersten durchlauf klappt unter beiden Systemen das ganze Problemlos. Probleme gibts erst im zweiten durchlauf.

Astat 21. Dez 2009 17:27

Re: Connection Closed Gracefully.
 
Zitat:

Zitat von RedShakal
Ehrlich gesagt ist mir der Code etwas zu kompliziert. Schon mein Lehrer hat damals immer gesagt kopiere nie was du nicht verstehst Das klappt so leider auch nicht so ganz. Der IO Fehler besteht trozdem.

Hallo RedShakal.

Zeig doch mal den umgebauten, Threadsaven Code, warum das nicht gehen soll ist mir ein Rätsel.
Der beschriebene Fehler mit IO tritt in Deinem Sample nur dann auf wenn was mit der Threadsynchronisierung nicht stimmt.

Du hast doch synchronisiert, oder?

lg. Astat

RedShakal 21. Dez 2009 17:33

Re: Connection Closed Gracefully.
 
Ich habe leider keine Ahnung von Threadsaving aber mein aktueller Code sieht so aus:

Delphi-Quellcode:
procedure TServer.IdTCPServer1Execute(AThread: TIdContext);
var
  Data        : String;
  StrArr      : TDynStringArray;
  ini         : TIniFile;
   f          : TextFile;
   Files      : string;
   y,m,d      : Word;
begin
 with AThread.Connection do
   begin
     DecodeDate(Now,d,m,y);
     Files := Format('log\%.2d-%.2d-%.2d.txt',[y,m,d]);

     AssignFile(f, Files);

     if FileExists(Files) then Append(f) else Rewrite(f);

     Data := String(Socket.ReadLn);
     Data := Trim(Data);

     if Length(Data) > 0 then
       begin
         StrArr := Explode('|', Data);
         if StrArr[0] = 'login' then
           begin
               if StrArr[3] = Clientver then
                 begin
                   if FileExists('accounts\'+StrArr[1]+'.ini') then
                     begin
                       ini := TIniFile.Create('accounts\'+StrArr[1]+'.ini');
                       try
                         if StrArr[2] = ini.ReadString('Login','Passwort','') then
                           begin
                             Socket.WriteLn('login');
                             WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' hat sich eingeloggt.');
                             WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' hat sich eingeloggt.');
                           end
                         else
                           begin
                             Socket.WriteLn('invalid');
                             WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' falsches Passwort.');
                             WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' falsches Passwort.');
                           end;
                       finally
                         ini.free;
                       end;
                     end
                   else
                     begin
                       Socket.WriteLn('na');
                       WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert nicht.');
                       WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert nicht.');
                     end;
                 end
                   else
                     begin
                       Socket.WriteLn('version');
                     end;
           end;

         if StrArr[0] = 'register' then
           begin
             if FileExists('accounts\'+StrArr[1]+'.ini') then
               begin
                 Socket.WriteLn('vorhanden');
                 WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert bereits.');
                 WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert bereits.');
               end
             else
               begin
                 try
                   ini := TIniFile.Create('accounts\'+StrArr[1]+'.ini');
                   ini.WriteString('Login','Passwort',StrArr[2]);
                   ini.WriteString('Login','E-Mail',StrArr[3]);
                 finally
                   Socket.WriteLn('erfolg');
                   ini.free;
                   WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' wurde registriert.');
                   WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' wurde registriert.');
                 end;
               end;
           end;
       end;
   end;
    CloseFile(f);
end;

Astat 21. Dez 2009 17:53

Re: Connection Closed Gracefully.
 
Hallo, als Brutalmethode kannst du folgendes verwenden!?

Delphi-Quellcode:
var
  _Sync: TRTLCriticalSection;

procedure TServer.IdTCPServer1Execute(AThread: TIdContext);
var
  Data        : String;
  StrArr      : TDynStringArray;
  ini         : TIniFile;
   f          : TextFile;
   Files      : string;
   y,m,d      : Word;
begin
  EnterCriticalSection(_Sync);
  try
    with AThread.Connection do
       begin
         DecodeDate(Now,d,m,y);
         Files := Format('log\%.2d-%.2d-%.2d.txt',[y,m,d]);

         AssignFile(f, Files);
         try
         if FileExists(Files) then Append(f) else Rewrite(f);

         Data := String(Socket.ReadLn);
         Data := Trim(Data);

         if Length(Data) > 0 then
           begin
             StrArr := Explode('|', Data);
             if StrArr[0] = 'login' then
               begin
                   if StrArr[3] = Clientver then
                     begin
                       if FileExists('accounts\'+StrArr[1]+'.ini') then
                         begin
                           ini := TIniFile.Create('accounts\'+StrArr[1]+'.ini');
                           try
                             if StrArr[2] = ini.ReadString('Login','Passwort','') then
                               begin
                                 Socket.WriteLn('login');
                                 WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' hat sich eingeloggt.');
                                 WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' hat sich eingeloggt.');
                               end
                             else
                               begin
                                 Socket.WriteLn('invalid');
                                 WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' falsches Passwort.');
                                 WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' falsches Passwort.');
                               end;
                           finally
                             ini.free;
                           end;
                         end
                       else
                         begin
                           Socket.WriteLn('na');
                           WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert nicht.');
                           WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert nicht.');
                         end;
                     end
                       else
                         begin
                           Socket.WriteLn('version');
                         end;
               end;

             if StrArr[0] = 'register' then
               begin
                 if FileExists('accounts\'+StrArr[1]+'.ini') then
                   begin
                     Socket.WriteLn('vorhanden');
                     WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert bereits.');
                     WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' existiert bereits.');
                   end
                 else
                   begin
                     try
                       ini := TIniFile.Create('accounts\'+StrArr[1]+'.ini');
                       ini.WriteString('Login','Passwort',StrArr[2]);
                       ini.WriteString('Login','E-Mail',StrArr[3]);
                     finally
                       Socket.WriteLn('erfolg');
                       ini.free;
                       WriteLn('['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' wurde registriert.');
                       WriteLn(f, '['+TimeToStr(Time)+']'+' Account: '+StrArr[1]+' wurde registriert.');
                     end;
                   end;
               end;
           end;
       end;
       finally
       CloseFile(f);
       end;
  finally
    LeaveCriticalSection(_Sync);
  end;
end;

initialization
  DateSeparator := '.';
  InitializeCriticalSection(_Sync);
finalization
  DeleteCriticalSection(_Sync);
end.
lg. Astat


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:23 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz