Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Access Violation bei "end."???


MrSaint - So 16.11.03 22:10
Titel: Access Violation bei "end."???
Hi!

Ich hab hier n Programm (soll mal n Proxy-Server werden), welches mir kuriose Fehlermeldungen generiert! Ich benutz die Indy Komponenten (TIdTCPServer, TIdTCPClient TIdThreadMngrDefault) und ich bekomm bei "end." ne AccessViolation!!!!!!!!!!!!!

Also das is so: ich start mein programm, dann ruf ich ne seite im Browser auf. der schickt meinem programm auch korrekt alles zu und mein programm fängt an zu arbeiten. Dann bekommich aber ganz plötzlich hier ne AV:


Delphi-Quelltext
1:
2:
3:
4:
5:
begin
  Application.Initialize;
  Application.CreateForm(TFrmMain, FrmMain);
  Application.Run;
end.  // <===========

und ich weiß absolut net, was ich damit anfangen soll... wo is denn jetzt der blöde fehler? und genau die gleiche AV kommt gleich danach wieder. Und dann is sense: mein programm reagiert nemme und ich muss es per Strg+F2 aus Delphi raus abschießen... Wenn ich dann nochmal auf F9 drück und das programm nommal start, dann kommen wirklich die kuriosesten Fehlermeldungen... irgendwo im Source (auch im Indy Source) kommen auf einmal irgendwelche AVs etc. Wenn ich dann Delphi neustart und dann F9 drück, dann kommen wieder nur die 2 AVs von oben (nich die hundert anderen in den Indys). Also irgendwas geht da grande schief...

hab das Problem schon länger und bekomm es einfach nich in den Griff... Hab dann heftige Logging-Funktionen engebaut (bei jeder Procedure die aufgerufen wird werdn die ewichtigsten daten in ne datei ausgegeben) und da is mir aufgefallen, dass (ich glaub) immer diese Funktion als letzter Aufruf vor dem Nicht-mehr-reagieren meines Programms aufgerufen wurde:


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:
procedure TTCPThread.DeleteFromList;
var i:integer;
    ThreadWorkHelp:PThreadWork;
    TCPThreadInList:TTCPThread;
begin
  tolog:='TCPThread.DeleteFromList - ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AThreadClient.ThreadID);
  Synchronize(log);  // tolog in logdatei schreiben
  i:=-1;
  try
    with ThreadWork.LockList do
    begin
      while (i<Count-1do
      begin
        inc(i);
        ThreadWorkHelp:=Items[i];
        TCPThreadInList:=ThreadWorkHelp.TCPThread;
        if TCPThreadInList.ThreadID=ThreadID then
        begin
          tolog:='TCPThread.DeleteFromList - Deleted Thread #'+inttostr(i)+'; ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AthreadClient.ThreadID);
          Synchronize(log);
          Delete(i);
          break;
        end;
      end;
    end;
  finally
    ThreadWork.UnlockList;
  end;
  tolog:='TCPThread.DeleteFromList - ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AThreadClient.ThreadID)+' DONE';
  Synchronize(log);
end;

n bissl erklärung dazu: Diese Procedure löscht einen Eintrag aus der Liste ThreadWork (TThreadList). In ThreadWork sind Pointer auf das hier gespeichert:

Delphi-Quelltext
1:
2:
3:
4:
  TThreadWork=record
    AThread:TIdPeerThread;
    TCPThread:TTCPThread;
  end;

nun wird da überprüft, welcher der TCPThreads aus der Liste mit dem eigenen (das ganze is ne Funktion aus ner Thread-Klasse) übereinstimmt und der Eintrag wird dann aus der Liste gelöscht.
Also das ganze Prog is Multi-thread-based...


Naja.. und ich weiß jetzt absolut nemme weiter :bawling: und hoff, dass ihr mir helfen könnt! In der DeleteFromList kann ich kein Fehler finden! Ich glaub der steigt schon bei dem "with ThreadWork.Locklist" aus... aber: WARUM??? und warum bekomm ich dann ne AV bei "end."?????


MrSaint

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.


Delete - So 16.11.03 23:08

Die AV tritt bei Applictaion.Run auf. Da läuft was beim Initialisieren falsch.


MrSaint - So 16.11.03 23:12

beim initialisieren?!?!?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TFrmMain.FormCreate(Sender: TObject);
begin
  HandleDisconnect:=true;
  TCPServer.Active:=True;
  ThreadWork:=TThreadList.Create;
  Application.OnException:=ErrorHandler;
  path:=extractfilepath(application.exename);
  if path[length(path)]<>'\' then path:=path+'\';
end;

Was soll da falsch laufen?


MrSaint

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.


Delete - So 16.11.03 23:25

Keine Ahnung. So spontan wüede ich sagen es liegt an dieser Zeile:

Delphi-Quelltext
1:
TCPServer.Active:=True;                    

Kommentier die mal aus.


Motzi - Mo 17.11.03 10:05

Also wenn ganz am Ende des Progs irgendwelche Fehler auftreten, dann liegt das meistens daran, dass du dir den Stack zerschossen hast oder über irgendwelche Array/Speichergrenzen rausgegangen bist... bei den Compiler-Optionen gibt es eine Möglichkeit diese "Range-Exceptions" einzuschalten (weiß jetzt aber nicht genau wie die heißt), schau mal ob du die findest...


mstuebner - Mo 17.11.03 14:18

Motzi hat folgendes geschrieben:
Also wenn ganz am Ende des Progs irgendwelche Fehler auftreten, dann liegt das meistens daran, dass du dir den Stack zerschossen hast oder über irgendwelche Array/Speichergrenzen rausgegangen bist... bei den Compiler-Optionen gibt es eine Möglichkeit diese "Range-Exceptions" einzuschalten (weiß jetzt aber nicht genau wie die heißt), schau mal ob du die findest...

Wobei es wesentlich besser ist die Ursache für den Fehler zu beseitigen, als dessen Anzeige. Ein Arzt gibt Dir hoffentlich auch keine lange Hose um Deinen offenen Beinbruch zu kaschieren. :shock:


Motzi - Mo 17.11.03 14:30

Das wollte ich damit auch nicht sagen, ich wollte damit andeuten, dass er diese Option einschalten soll, damit solche Grenz-Überschreitungen schon zur Laufzeit erkannt werden und eine entsprechende Exception ausgelöst wird! Damit kann man dann die entsprechende Fehlerquelle finden und beseitigen..!


MrSaint - Mo 17.11.03 15:27

hmmm... also ich hab nun die "bereichsprüfung" angeschaltet... jetzt bekomm ich ne "External Exception C000001D". Laut http://www.delphifaq.com/fq/q1061.shtml heißt das "STATUS_ILLEGAL_INSTRUCTION"... :?!?:
das is bei dieser Zeile:


Delphi-Quelltext
1:
  TCPClient.WriteLn(request);                    


aber ich glaub die zeile is nur zufall... weil ich hab davor genau vor dieser zeile noch ein

Delphi-Quelltext
1:
    repeat until TCPClient.Connected;                    

gehabt und da war der Fehler dann bei der Zeile...

Danach bekomm ich dann noch n Fehler im Indy-Source, der aber wohl mit der External Exception was zu tun hat, weil er bei einer Zeile passiert, wo er die TCPServerExecute aufruft (und das WriteLn von vorher steht in der TCPServerExecute)...
Und dann kommen wieder die beiden AVs auf das "end." und dann is wieder aus... reagiert nemme..


und ich glaub ihr habt mich irgendwie n bissl falsch verstanden! Der Fehler passiert net, wenn ich in Delphi auf F9 drückt, also wenn ich das programm start, sondern erst, wenn das Programm was zum Arbeiten (vom Browser) bekommt...


ich versteh das alles net...



MrSaint


Motzi - Mo 17.11.03 16:14

Arbeitest du irgendwo mit Pointern/dyn. alloziertem Speicher/dyn. Arrays oder ähnlichem?


MrSaint - Mo 17.11.03 16:17

jo, ne menge.... aber wenn ich net weiß, wo der fehler steckt, dann is das wie ne suche nach der stecknadel im heuhaufen! :(



MrSaint


Motzi - Mo 17.11.03 16:31

Was davo jetzt? Pointer oder dyn. Arrays oder beides? Bei dyn. Arrays hilft dir das "RangeChecking": Projekt-Optionen->Compiler->Runtime errors->Range checking (das ist die Überprüfung die ich oben gemeint hab). Bei Pointern wirds ein bisschen mühsamer... ich hatte auch schon das Problem, dass ich für einen Pointer unabsichtlich zuwenig Speicher reserviert hab und daher über die Grenzen des reservierten Speichers hinausgeschrieben hab. Dieser Fehler hat sich ebenfalls erst beim "end." bemerkbar gemacht. Check mal alle Routinen in denen du dyn. Speicher allozierst ob auch wirklich genug Speicher reserviert wird und dann schau was du so alles in diesen Speicher reinschreibst und ob sich das überhaupt ausgeht...


MrSaint - Mo 17.11.03 16:34

hmmm... also ich hab halt ne menge pointer drin... keine dyn. arrays... ich guck das dann heut noch durch...



MrSaint


barfuesser - Mo 17.11.03 17:48

MrSaint hat folgendes geschrieben:
hmmm... also ich hab nun die "bereichsprüfung" angeschaltet... jetzt bekomm ich ne "External Exception C000001D". Laut http://www.delphifaq.com/fq/q1061.shtml heißt das "STATUS_ILLEGAL_INSTRUCTION"... :?!?:
das is bei dieser Zeile:


Delphi-Quelltext
1:
  TCPClient.WriteLn(request);                    


aber ich glaub die zeile is nur zufall... weil ich hab davor genau vor dieser zeile noch ein

Delphi-Quelltext
1:
    repeat until TCPClient.Connected;                    

gehabt und da war der Fehler dann bei der Zeile...


das deutet darauf hin, daß der Fehler eventuell in der vorhergehenden Zeile zu suchen ist (oder nicht der Fehler sondern der Crash), da bei Delphi Exceptions oftmals erst in der Folgezeile angezeigt werden.
Wie lautet denn die benannte Zeile?

barfuesser


MrSaint - Mo 17.11.03 17:58


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:
  if not exists then
  begin
    TCPClient:=TIdTCPClient.Create(Self);
    TCPClient.Host:=server;
    TCPClient.Port:=Port;

    TCPThread:=TTCPThread.Create(True);
    TCPThread.FreeOnTerminate:=true;
    TCPThread.TCPClient:=TCPClient;
    TCPThread.AThreadClient:=AThread;
//    TCPThread.OnTerminate:=TCPThread.TCPThreadTerminate;

    GetMem(ThreadWorkHelp,sizeof(TThreadWork));
    ThreadWorkHelp.AThread:=AThread;
    ThreadWorkHelp.TCPThread:=TCPThread;
    try
      with ThreadWork.Locklist do
      begin
        Add(ThreadWorkHelp);
        log('Created new thread #'+inttostr(Count-1));
      end;
    finally
      ThreadWork.UnlockList;
    end;

    TCPThread.Resume;
  end else
  begin
    TCPThread:=ThreadWorkHelp.TCPThread;
    TCPClient:=TCPThread.TCPClient;         // Wenn Client <-> Proxy schon existiert, soll die bestehende Verbiundung genutzt werden!
  end;

  log('REQUEST: '+url+' ['+server+':'+inttostr(Port)+']');
  

  if not TCPClient.Connected then
  begin
    TCPClient.Connect;
//    repeat until TCPClient.Connected;
  end;
  TCPClient.WriteLn(request);
end;


exists ist true, wenn der Thread schon existiert. wenn so, dann wird auch der existierende TCPThread und TCPClient genutzt, ansonsten werden die beiden neu erzeugt...


also in der Zeile davor ist ein "TCPCLient.Connect;"... das fällt aber wohl net in meinen "Zuständigkeitsbereich", das sollte Indy machen... und ich glaub net, dass da so ein massiver bug drin is...



MrSaint


barfuesser - Mo 17.11.03 18:08

Falls TCPThread schon auf einen laufenden Thread verweist, dann weistTCPThread:=ThreadWorkHelp.TCPThread;diesem Zeiger einen neuen Thread zu. Keine Ahnung ob so etwas überhaupt funktionieren kann, aber ich halte dies zumindest für äußerst gewagt.

barfuesser


MrSaint - Mo 17.11.03 18:14

TCPThread is ne lokale Variable, die immer gesetzt werden muss (das da oben is n Auszug aus der TCPServerExecute)... ich muss TCPThread setzen, damit ich auf den Thread zugreifen kann (auch wenn der schon im Hintergrund läuft)... und in einer schleife vorher setz ich das ThreadWorkHelp, falls der Thread schon existiert => TCPThread:=ThreadWorkHelp.TCPThread macht den Thread, der im Hintergrund schon laüft und dessen Pointer in ThreadWorkHelp.TCPThread steckt nur für diese procedure (TCPServerExecute) zugänglich...



MrSaint


barfuesser - Mo 17.11.03 18:19

Also exists heißt dann nicht TCPThread existiert sondern ThreadWorkHelp.TCPThread existiert? Ist das so richtig?

barfuesser


MrSaint - Mo 17.11.03 18:28

ich hätt vielleicht gleich den code von der ganzen procedure posten sollen:



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:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
procedure TFrmMain.TCPServerExecute(AThread: TIdPeerThread);
var buf:TStrings;
    server,url,request,hlp:string;
    port,r,i:integer;
    TCPClient:TIdTCPClient;
    TCPThread:TTCPThread;
    ThreadWorkHelp:PThreadWork;
    exists:boolean;
    List:TList;
begin
  if AThread.Terminated or (not AThread.Connection.Connected) then exit;        // wenn Thread beendet -> exit;
  log('TCPServer.Execute');
  buf:=TStringList.Create;
  request:='';
  AThread.Connection.ReadStrings(buf,1);
  repeat
    request:=request+buf[0]+#13+#10;
//    log('reuqest read: '+buf[0]);
    buf.Clear;
    AThread.Connection.ReadStrings(buf,1);
  until length(buf[0])=0;
  request:=request+#13+#10+#13+#10;  // jetzt hab ich das request und nun wird das verarbeitet -> es wird in verscheidene variablen aufgeteilt... HIER UNINTERESSANT
  buf.Free;
  url:=copy(request,pos(' ',request)+1,length(request));                        // alles vor dem ersten " " (inklusive) wegschneiden
  url:=copy(url,0,pos(' ',url)-1);                                              // alles nach dem ersten " " (inklusive) wegschneiden
  if lowercase(copy(url,0,7))<>'http://' then                                   // wenn Protokoll <> http
  begin
    send_error(AThread,'<b>PROXY ERROR:</b> Es wird nur das HTTP Protokoll unterstützt!');
    AThread.Connection.Disconnect;
    exit;
  end;
  server:=copy(url,8,length(url));                                              // "http://" wegschneiden
  if pos('/',server)<>0 then server:=copy(server,0,pos('/',server)-1);
  if pos(':',server)<>0 then
  begin
    hlp:=copy(server,pos(':',server)+1,length(server));
    val(hlp,port,r);
    log('Port: '+hlp);
    if r<>0 then
    begin
      send_error(AThread,'<b>PROXY ERROR:</b> Port-Fehler!');
      AThread.Connection.Disconnect;
      exit;
    end;
    server:=copy(server,0,pos(':',server)-1);
  end else port:=80;
  if not IsIPAddr(server) then server:=GetIPFromHost(server);
//  log('real REQUEST: '+request);

// HIER WIRDS WIEDER INTERESSANTER. Variablen sind alle ausgelesen und gesetzt

  exists:=false;
  i:=-1;
  try
    with ThreadWork.LockList do
    begin
      while (i<Count-1do
      begin
        inc(i);
        ThreadWorkHelp:=Items[i];
        if ThreadWorkHelp.AThread=AThread then
        begin
          log('Reusing Thread #'+inttostr(i));
          exists:=true;                 // Verbindung Client <-> Proxy existiert schon...
          break;
        end;
      end;
    end;
  finally
    ThreadWork.UnlockList;
  end;

  if not exists then
  begin
    TCPClient:=TIdTCPClient.Create(Self);
    TCPClient.Host:=server;
    TCPClient.Port:=Port;

    TCPThread:=TTCPThread.Create(True);
    TCPThread.FreeOnTerminate:=true;
    TCPThread.TCPClient:=TCPClient;
    TCPThread.AThreadClient:=AThread;
//    TCPThread.OnTerminate:=TCPThread.TCPThreadTerminate;

    GetMem(ThreadWorkHelp,sizeof(TThreadWork));
    ThreadWorkHelp.AThread:=AThread;
    ThreadWorkHelp.TCPThread:=TCPThread;
    try
      with ThreadWork.Locklist do
      begin
        Add(ThreadWorkHelp);
        log('Created new thread #'+inttostr(Count-1));
      end;
    finally
      ThreadWork.UnlockList;
    end;

    TCPThread.Resume;
  end else
  begin
    TCPThread:=ThreadWorkHelp.TCPThread;
    TCPClient:=TCPThread.TCPClient;         // Wenn Client <-> Proxy schon existiert, soll die bestehende Verbiundung genutzt werden!
  end;

  log('REQUEST: '+url+' ['+server+':'+inttostr(Port)+']');
  

  if not TCPClient.Connected then
  begin
    TCPClient.Connect;
//    repeat until TCPClient.Connected;
  end;
  TCPClient.WriteLn(request);
end;


(den teil von "HIER UNINTERESSANT" bis "HIER WIRDS WIEDER INTERESSANNT" könnt ihr überspringen... da wird nur der request vom browser auseinanderklamausert...)

Also exists bedeuted, dass der AThread (der ja der Proceudre TCPServerExecute von indy her übergeben wir) existiert....

mein Porgramm acht das so:

Browser ==> TCPServer (AThread) -> TCPClient (TCPThread) ==> Webserver

und in der Funktion TCPServerExecute hab ich ja erst mal bloß das AThread gegeben. also guck ich, ob solch ein AThread schon in meiner Liste is. Wenn ja weiß ich, dass der AThread schon existiert und dann auch ein dazugehöriger TCPThread (es komm immer 1 TCPThread auf 1 AThread). Den weis ich dann zu. Und dieser TCPThread hat ne property "TCPClient" in der der Pointer für den zugehörigen TCPClient hält. Den weis ich dann auch noch zu und dann wird die Message (request) gesendet....


MrSaint


P.S.: sorry, dass ich mich hier a bissl blöd angestellt hab mit dem posten... hätte gleich die ganze procedure posten sollen :oops:


Motzi - Mo 17.11.03 21:06

Und der Fehler tritt nur auf wenn diese Routine durchlaufen wird..? Wie ist TThreadWork deklariert?


MrSaint - Mo 17.11.03 21:19
Titel: Re: Access Violation bei "end."???
MrSaint hat folgendes geschrieben:

Delphi-Quelltext
1:
2:
3:
4:
  TThreadWork=record
    AThread:TIdPeerThread;
    TCPThread:TTCPThread;
  end;




Ja, also es passiert zumindest net, wenn ich das programm einfach nur starte... und wenn ich dann ne seite im browser aufruf (mein programm also daten an den TCPServer geschickt bekommt, dann wird die Methode aufgerufen, ja! da das alles multi-threaded is eiß ich eben net genau ob da der fehler liegt, aber wie ich ja schon geschrieben hab: der debugger packt mich da bei der External Exception hin! Für das durchgucken wegen dem "über den Speicherbereich rausschreiben" muss ich noch gucken, aber eigentlich kann ich's mir net vorstellen... ich reservier eigentlich bloß einmal per hand speicher und das is, wenn ich n neuen eintrag in die ThreadWork reinschreib.. und das mach ich so, wie oben in dem Quelltext drin steht (da mit dem GetMem)... das is alles...

Moment! mir kommt da gerade ein Gedanke! wenn ich den Speicher per GetMem reservier sollte ich den Speicher doch, wenn ich den eintrag aus der liste rauslösche auch wieder freigeben, oder? :idea: Ich test das mal...



MrSaint


Motzi - Mo 17.11.03 21:33

Also freigeben sollte man ihn schon, aber eigentliche Fehlerursache dürfte das nicht sein (wenn das wirklich das einzige ist wo du dyn. Speicher reservierst)...

Was ist TTCPThread für eine Klasse? Von dir oder von den Indys? (bin in Internet/Netzwerk-Programmierung nicht so bewandert). Wenn es eine Klasse von dir ist, wie schaut diese aus (Code)..?

BTW: was ist/macht das ganze eigentlich?


MrSaint - Mo 17.11.03 22:09

hmmm... also ich hab nun n freemem an entsprechender stelle drin, haat aber net wirklich was gebracht :(

TTCPThread is ne Klasse von mir, die von TThread abgeleited is. Das ganze soll mal ein ProxyServer werden. Dazu brauch ich ein TidTCPServer, der die Verbindungen Browser <-> Mein Programm. Dann brauch ich noch nen TIdTCPClient der die Verbindung Mein Programm <-> Webserver.
Wenn der Browser also ne anfrage schickt springt mein TCPServer ein. Da wird dann die Procedue OnExecute aufgerufen. Die klamausert bei mir dann die daten aauseinander und "bestückt" einen TCPClient damit... so weit so gut.
wenn jetzt der Webserver antwortet, muss mein TCPClient einspringen. Da gibts aber kein Ereignis dazu (OnServerWrite oder sowas), also muss man das mit nem Thread abfangen. Das macht mein TTCPThread. und da gibts dann für jede Instanz von TCPClient einen TCPThread der dann immer diese Verbindung auf neue Nachrichten überprüft. und wie schon gesagt gibts für jeden Thread vom TCPServer (Verbindung Browser <-> mein Programm) (das is der AThread) einen TCPThread und einen TCPClient.



jetzt poste ich hier mal die unit "thread.pas", die bei mir den kompletten TTCPThread beinhaltet (is nun nich auskommentiert und auch nich "schöngemacht [ also auskommentierte Linien entfernt etc.] ).


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:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
unit thread;

interface

uses Classes, IdTCPClient, IdTCPServer;

type    TTCPThread = class (TThread)
        private
          Buf:array [1..10240of byte;                 // Puffer
          BufSize,SizeToWrite:int64;                    // Puffergröße, Größe, die an Browser geschrieben werden soll
          FTCPClient:TIdTCPClient;                      // der TCPClient
          FAThreadClient:TIdPeerThread;                 // der TCPServer-Thread (Browser <-> Proxy)
          tolog:string;                                 // Hilfsvariable für's logging
          TerminateOK:boolean;                          // ist das TCPThread.Terminate OK?
          DisconnectOK: boolean;                        // Ist der Disconnect vom Webserver OK?
          procedure HandleInput;                        // schickt daten an Browser
          procedure log;                                // gibt inhalt von tolog aus
          procedure DeleteFromList;                     // löscht einen eintrag aus ThreadWork (den eigenen)
          procedure TCPThreadTerminate(Sender:TObject);
          procedure TCPClientDisconnect(Sender:TObject);
        protected
          procedure Execute; override;
        published
          property AThreadClient: TIdPeerThread read FAThreadClient write FAThreadClient;
          property TCPClient:TIdTCPClient read FTCPClient write FTCPClient;
          procedure EndWork;
        end;

implementation

uses mainFrm, SysUtils;

function ArrToStr(arr: array of byte;high:integer):string;
var i:integer;
begin
  result:='';
  i:=-1;
  while (i<high) do
  begin
    inc(i);
    result:=result+chr(arr[i]);
  end;
end;

procedure TTCPThread.Execute;
begin
  TerminateOK:=false;
  DisconnectOK:=false;
  OnTerminate:=TCPThreadTerminate;
  FTCPClient.OnDisconnected:=TCPClientDisconnect;
  tolog:='New Thread ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AthreadClient.ThreadID);
  Synchronize(log);
  while not Terminated do
  begin
    if not FTCPClient.Connected then
    begin
      EndWork;
//      FTCPClient.Connect;
    end else
    begin
      try
        FTCPClient.ReadBuffer(buf,1);
        BufSize:=FTCPClient.InputBuffer.Size;
        SizeToWrite:=1;
//        HandleInput;
        synchronize(HandleInput);
        if BufSize>0 then
        begin
          if BufSize>10240 then
          begin
            SizeToWrite:=10240;
            repeat
              FTCPClient.ReadBuffer(Buf,10240);
              Dec(BufSize,10240);
//              HandleInput;
              Synchronize(HandleInput);                                               // verarbeiten
            until BufSize<10240;
            if BufSize>0 then
            begin
              SizeToWrite:=BufSize;
              FTCPClient.ReadBuffer(Buf,BufSize);
              BufSize:=0;
//              HandleInput;
              Synchronize(HandleInput);
            end;
          end else
          begin
            SizeToWrite:=BufSize;
            FTCPClient.ReadBuffer(Buf,BufSize);
            BufSize:=0;
//            HandleInput;
            Synchronize(HandleInput);
          end;
        end else SizeToWrite:=0;
      except
//        EndWork;
      end;
    end;
  end;
end;

procedure TTCPThread.log;
begin
  FrmMain.log(tolog);
end;

procedure TTCPThread.HandleInput;                                               // PUFFER-VERARBEITUNG
begin
  if SizeToWrite=0 then exit;
  AThreadClient.Connection.WriteBuffer(Buf,SizeToWrite);
//  FrmMain.log('Writing: '+ArrToStr(buf,SizeToWrite));
end;

procedure TTCPThread.DeleteFromList;
var i:integer;
    ThreadWorkHelp:PThreadWork;
    TCPThreadInList:TTCPThread;
begin
//  FrmMain.log('TCPThread.DeleteFromList');
  tolog:='TCPThread.DeleteFromList - ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AThreadClient.ThreadID);
  Synchronize(log);
  i:=-1;
  try
    with ThreadWork.LockList do
    begin
      while (i<Count-1do
      begin
        inc(i);
        ThreadWorkHelp:=Items[i];
        TCPThreadInList:=ThreadWorkHelp.TCPThread;
        if TCPThreadInList.ThreadID=ThreadID then
        begin
          tolog:='TCPThread.DeleteFromList - Deleted Thread #'+inttostr(i)+'; ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AthreadClient.ThreadID);
          Synchronize(log);
          FreeMem(ThreadWorkHelp);
          Delete(i);
          break;
        end else
        begin
//          tolog:='TCPThread.DeleteFromList - Checking Thread #'+inttostr(i)+' - no match';
//          Synchronize(log);
//          FrmMain.log('TCPThread.DeleteFromList - Checking Thread #'+inttostr(i)+' - No match');
        end;
      end;
    end;
  finally
    ThreadWork.UnlockList;
  end;
  tolog:='TCPThread.DeleteFromList - ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AThreadClient.ThreadID)+' DONE';
  Synchronize(log);
end;

procedure TTCPThread.EndWork;
begin
  tolog:='TCPThread.EndWork - ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AthreadClient.ThreadID);
  Synchronize(log);
  try
//    Synchronize(DeleteFromList);
    DeleteFromList;
  except
  end;
  try
    FTCPClient.Free;
{    DisconnectOK:=true;
    try
      FTCPClient.Disconnect;
    except
    end;
    repeat until not FTCPClient.Connected;
    try
      FTCPClient.Free;
    except
    end;
{    if AThreadClient.Data<>nil then
    try                     // damit nicht beide Seiten sich gegenseitig disconnecten!
      tolog:='TCPThread.EndWork - AThread.Connection.Disconnect';
      Synchronize(log);
      AThreadClient.Connection.Disconnect;
    except
    end;}

  except
  end;
  TerminateOK:=true;
  Terminate;
end;

procedure TTCPThread.TCPThreadTerminate(Sender:TObject);
begin
  //Dummy
  if not TerminateOK then EndWork;
end;

procedure TTCPThread.TCPClientDisconnect(Sender:TObject);
begin
  //dummy
{  if not DisconnectOK then
  begin}

    tolog:='TCPClient.Disconnect - ID: TCPThread: '+inttostr(ThreadID);
    synchronize(log);
    try
      AThreadClient.Connection.Disconnect;
    except
    end;
//  end;
end;

end.



Ich hoff, dass das irgendwas hilft...


hab nun bald den kompletten source hier gepostet.-.. könnte demnächst eigentlich auch den ganzen Project-Source ins Netz stellen ;)



MrSaint


Motzi - Mo 17.11.03 23:47

Ich hab mir das mal angeschaut und zum besseren Verständnis auch gleich mal an meinen Stil angepasst.. ;)

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:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
unit thread;

interface

uses
  Classes, IdTCPClient, IdTCPServer;

const
  MAX_COUNT = 10240;

type
  TTCPThread = class (TThread)
    private
      Buf: array [1..MAX_COUNT] of Byte;   // Puffer
      SizeToWrite: Int64;                  // Puffergröße, Größe, die an Browser geschrieben werden soll
      FTCPClient: TIdTCPClient;            // der TCPClient
      FAThreadClient: TIdPeerThread;       // der TCPServer-Thread (Browser <-> Proxy)
      ToLog: String;                       // Hilfsvariable für's logging
      TerminateOK: Boolean;                // ist das TCPThread.Terminate OK?
      DisconnectOK: Boolean;               // Ist der Disconnect vom Webserver OK?
      procedure HandleInput;               // schickt daten an Browser
      procedure log;                       // gibt inhalt von tolog aus
      procedure DeleteFromList;            // löscht einen eintrag aus ThreadWork (den eigenen)
      procedure TCPThreadTerminate(Sender: TObject);
      procedure TCPClientDisconnect(Sender: TObject);
    protected
      procedure Execute; override;
    published
      property AThreadClient: TIdPeerThread read FAThreadClient write FAThreadClient;
      property TCPClient:TIdTCPClient read FTCPClient write FTCPClient;
      procedure EndWork;
    end;

implementation

uses
  mainFrm, SysUtils;

function ArrToStr(arr: array of byte; high: Integer): String;
var
  i: Integer;
begin
  Result := '';
  i := -1;
  while (i < high) do
  begin
    inc(i);
    Result := Result + Chr(arr[i]);
  end;
end;

procedure TTCPThread.Execute;
var
  BufSize: Int64;
begin
  TerminateOK := False;
  DisconnectOK := False;
  OnTerminate := TCPThreadTerminate;
  FTCPClient.OnDisconnected := TCPClientDisconnect;
  ToLog := 'New Thread ID: TCPThread: ' + IntToStr(ThreadID) +
           '; AThread: ' + IntToStr(AthreadClient.ThreadID);
  Synchronize(log);

  while not Terminated do
  begin
    if not FTCPClient.Connected then
    begin
      Terminate;
//      FTCPClient.Connect;
    end else
    begin
      try
        FTCPClient.ReadBuffer(Buf, 1);
        BufSize := FTCPClient.InputBuffer.Size;
        SizeToWrite := 1;
        Synchronize(HandleInput);

        SizeToWrite := 0;
        if BufSize > 0 then
        begin
          if BufSize > MAX_COUNT then
          begin
            SizeToWrite := MAX_COUNT;
            repeat
              FTCPClient.ReadBuffer(Buf, MAX_COUNT);
              Dec(BufSize, MAX_COUNT);
              Synchronize(HandleInput); // verarbeiten
            until BufSize < MAX_COUNT;
          end;

          if BufSize > 0 then
          begin
            SizeToWrite := BufSize;
            FTCPClient.ReadBuffer(Buf, BufSize);
            BufSize := 0;
            Synchronize(HandleInput);
          end;
        end;
      except
//        EndWork;
      end;
    end;
  end;
end;

procedure TTCPThread.log;
begin
  FrmMain.log(ToLog);
end;

procedure TTCPThread.HandleInput; // PUFFER-VERARBEITUNG
begin
  if SizeToWrite <> 0 then
    AThreadClient.Connection.WriteBuffer(Buf, SizeToWrite);
//  FrmMain.log('Writing: '+ArrToStr(buf,SizeToWrite));
end;

procedure TTCPThread.DeleteFromList;
var
  i: Integer;
  ThreadWorkHelp: PThreadWork;
  TCPThreadInList: TTCPThread;
begin
//  FrmMain.log('TCPThread.DeleteFromList');
  ToLog := 'TCPThread.DeleteFromList - ID: TCPThread: ' + IntToStr(ThreadID) +
           '; AThread: ' + IntToStr(AThreadClient.ThreadID);
  Synchronize(log);

  i := -1;
  try
    with ThreadWork.LockList do
    begin
      while (i < Count-1do
      begin
        Inc(i);
        ThreadWorkHelp := Items[i];
        TCPThreadInList := ThreadWorkHelp.TCPThread;
        if TCPThreadInList.ThreadID = ThreadID then
        begin
          ToLog := 'TCPThread.DeleteFromList - Deleted Thread #' + IntToStr(i) +
                   '; ID: TCPThread: '+ IntToStr(ThreadID) +
                   '; AThread: ' + IntToStr(AthreadClient.ThreadID);
          Synchronize(log);
          FreeMem(ThreadWorkHelp);
          Delete(i);
          break;
        end else
        begin
//          tolog:='TCPThread.DeleteFromList - Checking Thread #'+inttostr(i)+' - no match';
//          Synchronize(log);
//          FrmMain.log('TCPThread.DeleteFromList - Checking Thread #'+inttostr(i)+' - No match');
        end;
      end;
    end;
  finally
    ThreadWork.UnlockList;
  end;
  ToLog := 'TCPThread.DeleteFromList - ID: TCPThread: ' + IntToStr(ThreadID) +
           '; AThread: ' + IntToStr(AThreadClient.ThreadID) + ' DONE';
  Synchronize(log);
end;

procedure TTCPThread.EndWork;
begin
  ToLog := 'TCPThread.EndWork - ID: TCPThread: ' + IntToStr(ThreadID) +
           '; AThread: ' + IntToStr(AthreadClient.ThreadID);
  Synchronize(log);
  try
    DeleteFromList;
  except
  end;
  try
    FTCPClient.Free;
{    DisconnectOK:=true;
    try
      FTCPClient.Disconnect;
    except
    end;
    repeat until not FTCPClient.Connected;
    try
      FTCPClient.Free;
    except
    end;
{    if AThreadClient.Data<>nil then
    try                     // damit nicht beide Seiten sich gegenseitig disconnecten!
      tolog:='TCPThread.EndWork - AThread.Connection.Disconnect';
      Synchronize(log);
      AThreadClient.Connection.Disconnect;
    except
    end;}

  except
  end;
  TerminateOK := True;
  Terminate;
end;

procedure TTCPThread.TCPThreadTerminate(Sender:TObject);
begin
  //Dummy
  if not TerminateOK then
    EndWork;
end;

procedure TTCPThread.TCPClientDisconnect(Sender:TObject);
begin
  //dummy
{  if not DisconnectOK then
  begin}

    ToLog := 'TCPClient.Disconnect - ID: TCPThread: ' + IntToStr(ThreadID);
    Synchronize(log);
    try
      AThreadClient.Connection.Disconnect;
    except
    end;
//  end;
end;

end.

Hab ein paar Sachen ein bisschen geändert/optimiert, aber ob es wirklich was gebracht hat weiß ich nicht... aber nachdem du ja eh alles mitlogst.. wie schaut den nun die Ausgabe in so einer Log-Datei aus? Vielleicht kann man daraus Rückschlüsse ziehen...


MrSaint - Di 18.11.03 15:20

hmmmm... äußerst komisch... hab zuerst deinen code hier bei mir reingepackt (von der unit) und dann ausgeführt... wegen fehler / AV hat sich nix gebessert... aber dann hab ich delphi neugestartet und nochmal probiert (wegen logdatei) und da hab ich jetzt gar keinen Fehler bekommen, mein Programm is aber trotzdem "eingefroren".... hab jetzt leider keine zeit, nach dem grund zu suchen, warum da jetzt kein fehler kam, weil ich gleich wieder weg muss.... hier aber mal die log-datei:


LOG hat folgendes geschrieben:
14:16:01 TCPServer.Execute
14:16:02 Created new thread #0
14:16:02 REQUEST: http://www.delphi-forum.de/ [217.160.166.23:80]
14:16:02 New Thread ID: TCPThread: 4294071443; AThread: 4294073091
14:16:02 TCPServer.Execute
14:16:04 TCPClient.Disconnect - ID: TCPThread: 4294071443
14:16:04 TCPThread.EndWork - ID: TCPThread: 4294071443; AThread: 4294073091
14:16:04 TCPThread.DeleteFromList - ID: TCPThread: 4294071443; AThread: 4294073091
14:16:04 TCPThread.DeleteFromList - Deleted Thread #0; ID: TCPThread: 4294071443; AThread: 4294073091
14:16:04 TCPThread.DeleteFromList - ID: TCPThread: 4294071443; AThread: 4294073091 DONE
14:16:04 TCPServer.Disconnect
14:16:04 TCPServer.Disconnect - ThreadWork empty!
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 Created new thread #0
14:16:04 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-02.gif [217.160.166.23:80]
14:16:04 Created new thread #1
14:16:04 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-03.gif [217.160.166.23:80]
14:16:04 Created new thread #2
14:16:04 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-04.gif [217.160.166.23:80]
14:16:04 Created new thread #3
14:16:04 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-05.gif [217.160.166.23:80]
14:16:04 Created new thread #4
14:16:04 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-09.gif [217.160.166.23:80]
14:16:04 Created new thread #5
14:16:04 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-10.gif [217.160.166.23:80]
14:16:04 Created new thread #6
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-14.gif [217.160.166.23:80]
14:16:04 Created new thread #7
14:16:04 TCPServer.Execute
14:16:04 TCPServer.Execute
14:16:04 Created new thread #8
14:16:05 TCPServer.Execute
14:16:05 TCPServer.Execute
14:16:05 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-01.gif [217.160.166.23:80]
14:16:05 New Thread ID: TCPThread: 4217591655; AThread: 4217669219
14:16:05 New Thread ID: TCPThread: 4217590351; AThread: 4217667811
14:16:05 TCPServer.Execute
14:16:05 New Thread ID: TCPThread: 4217590995; AThread: 4217668531
14:16:05 New Thread ID: TCPThread: 4217589691; AThread: 4217683459
14:16:05 New Thread ID: TCPThread: 4217589047; AThread: 4217682723
14:16:05 New Thread ID: TCPThread: 4217588387; AThread: 4217681987
14:16:05 New Thread ID: TCPThread: 4217587727; AThread: 4217681267
14:16:05 New Thread ID: TCPThread: 4217587051; AThread: 4217670427
14:16:05 New Thread ID: TCPThread: 4217586407; AThread: 4217669783
14:16:04 TCPServer.Execute
14:16:04 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-27.gif [217.160.166.23:80]
14:16:05 Created new thread #9
14:16:05 TCPServer.Execute
14:16:05 TCPServer.Disconnect
14:16:05 TCPServer.Execute
14:16:05 TCPServer.Disconnect
14:16:05 TCPServer.Disconnect
14:16:05 TCPServer.Disconnect
14:16:05 TCPServer.Execute
14:16:05 TCPServer.Execute
14:16:05 REQUEST: http://www.delphi-forum.de/graphics/slices/slice-11.gif [217.160.166.23:80]
14:16:06 New Thread ID: TCPThread: 4217599323; AThread: 4217585671
14:16:06 TCPClient.Disconnect - ID: TCPThread: 4217591655
14:16:06 TCPClient.Disconnect - ID: TCPThread: 4217590351
14:16:06 TCPClient.Disconnect - ID: TCPThread: 4217589691
14:16:06 TCPClient.Disconnect - ID: TCPThread: 4217589047
14:16:05 TCPServer.Execute
14:16:06 TCPClient.Disconnect - ID: TCPThread: 4217588387
14:16:05 TCPServer.Execute
14:16:06 TCPClient.Disconnect - ID: TCPThread: 4217590995
14:16:06 TCPServer.Disconnect - Client-Disconnect Thread #0; ID: TCPThread: 4217591655; AThread: 4217669219
14:16:06 TCPServer.Disconnect
14:16:06 TCPServer.Disconnect
14:16:06 TCPClient.Disconnect - ID: TCPThread: 4217587727
14:16:06 TCPThread.EndWork - ID: TCPThread: 4217590995; AThread: 4217668531
14:16:06 TCPThread.DeleteFromList - ID: TCPThread: 4217590995; AThread: 4217668531


...Aber es wurde wieder die DeleteFromList als letztes aufgerufen.... irgendwie is das alles sehr verwirrend :eyecrazy:

MrSaint