Autor Beitrag
Angelo
Hält's aus hier
Beiträge: 3


Delphi 7
BeitragVerfasst: Mi 14.01.09 22:29 
Hallo!

Ich programmiere zusammen mit einem Kollegen seit einiger Zeit an einem Chat Programm und dieses Programm lief auch immer stabil. Bis nach einigen Erweiterungen der Server, nachdem ein Client Disconnectet, einfach abstürtzt. Als Fehler wird angegeben, dass ein Pointer aus einem Bereich läuft. Das Problem ist nur, dasa dieser Fehler nur in der Schule auftritt aber leider bei mir selber zu Hause am PC bisher noch nicht. Deswegen stellen wir unser Programm hier rein in der Hoffnung, dass uns jemand helfen kann.
Ich werde das ganze Programm anhängen und falls wer lust hat dazu einen Kommentar zuschreiben darf dies natürlich auch tun wink:
Ach wir verwenden TClientSocket & TServerSocket für Delphi 7.
Für jeden Tipp sind wir sehr dankbar weil wir nicht mehr weiter wissen. :?

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
  var zeit : string;
      zaehler, pos,i : integer;
      vorhanden : boolean;
begin
// Überorüfung der Verbindung zum Server (disconnect?)
 pos := 0;
 Zeit := aktuellezeit;
 for zaehler := 0 to High(User) do
  begin
   If (Socket = TCustomWinSocket(User[zaehler,0])) and (User[zaehler,2] = 'vorhanden')
   then  vorhanden := true;
  end;
If not vorhanden then
 begin
 {---User aus Array löschen---}
 for zaehler := 0 to high(User) do
  begin
    If TCustomWinSocket(User[zaehler,0]) = Socket then
     begin
      pos := zaehler;
      username:= User[pos,2];                           // User wird ausgelesen
     end;
  end;
 for zaehler := pos to high(User)-1 do                 // Das Array wird aktualisiert
  begin
   User[zaehler,0] := User[zaehler+1,0];
   User[zaehler,1] := User[zaehler+1,1];
   User[zaehler,2] := User[zaehler+1,2];
  end;
 mem_ausgabe.lines.Add(zeit + ': ' + 'Verbindung mit Client ' + username + ' wurde beendet!');
 AddColoredString(mem_eingang, zeit + ' ' + 'Server: ' + 'Auf wiedersehen ' + username + '!'#13#10, clRed);
 Setlength(User,Length(User)-1);
 lb_chatuser.clear;
 for i:= 0 to high(user) do lb_chatuser.items.add(user[i,2]);
 {---Nachricht an alle User senden---}
 for zaehler := 0 to ServerSocket1.Socket.ActiveConnections-1 do
  begin
     editmessage('chat','Server',zeit + ' ' + 'Server' + ': ' + 'Auf wiedersehen ' + username);
    ServerSocket1.Socket.Connections[zaehler].SendBuf(cmessage, SizeOf(cmessage));
  {---Code zum löschen und aktualisieren der Listbox bei den Clients---}
    editmessage('updateusers',lb_chatuser.Items.CommaText,'');
    ServerSocket1.Socket.Connections[zaehler].SendBuf(cmessage, SizeOf(cmessage));
  end
 end;
end;
Einloggen, um Attachments anzusehen!
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 15.01.09 13:13 
Moin und :welcome: im Forum!

Ich gebe zu, bei dieser diffusen Fehlerbeschreibung und einem kompletten Quelltext habe ich jetzt nicht so die grandiose Motivation, das durchzugucken... :? Der Codeschnipsel oben reicht auch nicht wirklich, da man das Protokoll-Konzept darin nicht nachvollziehen kann. :nixweiss:

Deshalb schieße ich jetzt einfach mal ins Blaue: diesen FAQ-Eintrag schon gesehen und sicher, dass aus dieser Richtung keine Probleme kommen können? :les: :idea: ;)
Vermutlich nicht zutreffend, aber trotzdem auch nochmal hier reinsehen. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 15.01.09 13:35 
Also: ich konnte das Problem bei mir reproduzieren. Leider tritt es nicht immer auf.
Was passiert:
Server + 2 Clients gestartet, beide Clients disconnected, beim Ausschaltendes zweiten Clients kam die Fehlermeldung "Invald Pointer operation".

Ich schau es mir einmal an. ;-)

// EDIT:
Wie wäre es, das ganze sauber zu programmieren? :shock:
Der Socket nach String gecastet und in einem zweidimensionalen Array of String gespeichert? Und das nur um einen Record zu sparen, was dann aber sauber ohne Cast funktionieren würde?
Und statt Befehle als Chattexte zu schicken wäre ein richtiges Protokoll auch besser, aber das ist auch erstmal kein Problem das zu machen wie du jetzt. Aber das Array user... :eyes:

Jedenfalls wird Disconnect mehrfach aufgerufen, soweit ich das sehe, ich glaube weil du am Ende an alle Clients sendest. Dabei ist aber auch der Client, der gerade die Verbindung beendet hat. So löschst du dein Array user leer und dann gibts einen Fehler, wenn du dann wieder versuchst es um eins zu verkleinern.
Deine Logik in dem Programm ist mir aber auch nicht klar. Du prüfst in OnDisconnect, ob in user vorhanden drin steht. Und wenn ja, dann löschst du den Eintrag nicht?

Du solltest das einmal sauber umsetzen... Ohne solche Typecasts vor allem... Was spricht gegen einen einfachen Record?

// EDIT2:
Ach ja, aktiviere in den Projektoptionen unter Projekt --> Optionen --> Compiler mal die Bereichsüberprüfung (ganz rechts oben). Dann wird dir nämlich der Fehler angezeigt, wenn du dein Array verkleinerst. Dein Porinterfehler ist nur ein Folgefehler, weil du in falsche Speicherbereiche schreibst nehme ich an.
Angelo Threadstarter
Hält's aus hier
Beiträge: 3


Delphi 7
BeitragVerfasst: Do 15.01.09 22:46 
Vielen Dank schonmal für die schnellen Antworten ich werde mir dass alles mal genau angucken.

Nur die Sache bezüglich des Records und den Sockets habe ich nicht verstanden. Meinst du, dass ich die Sockets in ein Record schreiben soll? Wie genau meinst du das denn??

Ach und das mit dem Disconnect bezüglich vorhanden ist nur weil ich einen Client dessen Username schon vorhanden ist erst gar nicht ins Array und so schreibe deswegen muss der nicht die volle Prozedur aufrufen. War sone Sache die mir irgendwann Nachts mal eingefallen war und dementsprechend nicht besonders gut durchdacht sein kann. :D

Also dann werde ich schonmal die ersten Tipps befolgen und nach dem Fehler suchen. :wink:
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 15.01.09 22:50 
Moin!

user profile iconAngelo hat folgendes geschrieben Zum zitierten Posting springen:
Nur die Sache bezüglich des Records und den Sockets habe ich nicht verstanden. Meinst du, dass ich die Sockets in ein Record schreiben soll? Wie genau meinst du das denn??
Schau mal in dieses Tut, da wird die Userliste in einer Listbox abgebildet, das wäre auch noch eine Alternative. :idea:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 15.01.09 22:58 
user profile iconAngelo hat folgendes geschrieben Zum zitierten Posting springen:
Nur die Sache bezüglich des Records und den Sockets habe ich nicht verstanden. Meinst du, dass ich die Sockets in ein Record schreiben soll? Wie genau meinst du das denn??
Naja, statt
ausblenden Delphi-Quelltext
1:
  user: array of array [0..2of string;					
wäre wohl eher das sinnvoll:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
TUserInfo = record
  UserName, RemoteIP: String;
  Socket: TCustomWinSocket;
end;

user: array of TUserInfo;
Dann sparst du dir den String in TCustomWinSocket zu casten (TCustomWinSocket(User[zaehler,0])) und umgekehrt, denn das ist alles andere als sauber, insbesondere wenn es sich so einfach richtig lösen lässt. ;-)
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 15.01.09 23:02 
Moin!

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
TUserInfo = record
  UserName{, RemoteIP}String// unnötig, ist durch Socket.RemoteAddress bekannt ;)
  Socket: TCustomWinSocket;
end;
cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 15.01.09 23:11 
Schon, aber genau das hat er aus irgendeinem Grund darin noch einmal extra gespeichert. ;-)
Warum ist mir auch nicht wirklich klar, aber ich habe es einmal mit in den Record übernommen, damit es dem ursprünglichen Quelltext entspricht.
Angelo Threadstarter
Hält's aus hier
Beiträge: 3


Delphi 7
BeitragVerfasst: Do 15.01.09 23:18 
Man man ihr seit ja super gut drauf :wink: Super geil wie schnell ihr hier Antwortet.

Und ja ihr habt mir mit dem Record die Augen geöffnet. :) Naja ist wohl nen bissel sinnlos programmiert, aber das kommt davon wenn man einfach ohne großes Konzept immer mehr hinzufügt.

Ach und so wie ich das sehe ist ein Record zu versenden wohl nicht die beste Lösung. Nur müsste ich ja dann ne Menge neu machen und erstmal nen vernünftiges Protokoll schreiben ohne das Tutorial von dir Narses zu stark zu kopieren. Und ja ich habe mir das Binäre und auch das Terminatoren Tutorial schon einmal angeguckt.

Ach das mit der IP war auch wieder Basis einer vorherigen Version bevor wir die Sockets gespeichert haben. :)

Also nochmal Vielen Dank das ihr hier so schnell antwortet. :wink: