| Autor |
Beitrag |
Piranha
      
Beiträge: 31
|
Verfasst: Mi 06.08.08 23:43
Ich programmiere grade an einem Programm welches mit TServersocket eine Verbindung aufbaut. Testbedingt läuft die Anwendung nicht 100% stabil, was dazu führt, das diese manchmal abstürzt und so der Socket nicht mehr geschlossen werden kann (FormClose Ereignis tritt ja nicht mehr ein).
Jetzt kann ich die Anwendung auch nicht mehr auf dem Port testen, da der Socket ja belegt ist.
Meine bisherige Notlösung war, das ich mich bei Windows abgemeldet und wieder angemeldet habe.
Da dies bei meinem System allerdings äußerst kontraproduktiv ist (Platten werden nachträglich gemounted) suche ich nach einer anderen Lösung:
1. Wie kriege ich den Port/Socket wieder frei (egal wie)? (Ich nehme in kauf, dafür ein kleines Programm schreiben zu müssen)
2. Wie kann ich es schaffen, dass auch wenn eine Anwedung den Bach runter geht, dass der Socket noch umbedingt geschlossen wird?
(Antworten wie "Anwendung fehlerfrei schreiben" werde ich ignorieren, da das in der Entwicklungphase mehr oder weniger unmöglich ist.)
Zuletzt bearbeitet von Piranha am Mi 06.08.08 23:44, insgesamt 1-mal bearbeitet
|
|
GTA-Place
      

Beiträge: 5248
Erhaltene Danke: 2
WIN XP, IE 7, FF 2.0
Delphi 7, Lazarus
|
Verfasst: Mi 06.08.08 23:44
OnFormDestroy hilft auch nicht?
_________________ "Wer Ego-Shooter Killerspiele nennt, muss konsequenterweise jeden Horrorstreifen als Killerfilm bezeichnen." (Zeit.de)
|
|
Piranha 
      
Beiträge: 31
|
Verfasst: Mi 06.08.08 23:49
Oh man das geht hier aber schnell
Erstmal danke für die zügige Antwort.
Ich hab diese Methode noch nicht ausprobiert.
Gut möglich das es so funktioniert, ich werde es Testen...
doch im Moment ist mein betroffener Port immernoch gesperrt, weswegen
eine Lösung zu Frage 1. auchnoch sehr wichtig ist.
Danke schonmal....
|
|
alias5000
      
Beiträge: 2145
WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
|
Verfasst: Mi 06.08.08 23:53
Interessante Frage. OnFormDestroy sollte da nicht helfen, wenn es richtig fest abschmiert. Kannst du die Fehler irgendwie so abfangen, dass die Anwendung noch eine Fehlerbehandlung machen kann (try...finally/try...except, TApplicationEvents.OnEcxeption,...)
Gruß
alias5000
_________________ Programmers never die, they just GOSUB without RETURN
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mi 06.08.08 23:57
Moin!
Piranha hat folgendes geschrieben: | | Ich programmiere grade an einem Programm welches mit TServersocket eine Verbindung aufbaut. |
Mit TServerSocket kann man gar keine Verbindungen aufbauen...  sondern nur annehmen.
Piranha hat folgendes geschrieben: | | diese manchmal abstürzt und so der Socket nicht mehr geschlossen werden kann (FormClose Ereignis tritt ja nicht mehr ein). |
Wenn der Prozess, der das Handle auf den Socket hält, terminiert, dann gibt die WSA den Socket automatisch wieder frei.  Deine Anwendung läuft noch oder du versuchst mehrfach den Socket zu öffnen. Mal im Taskmanager geschaut, ob der Prozess wirklich weg ist? Das würde nämlich erklären, warum eine Abmeldung da hilft...  Oder beim TServerSocket in der IDE die Eigenschaft .Active auf TRUE gesetzt?
Beendest du die Anwendung im Fehlerfall möglicherweise per Strg+F2? Dann könnte es nötig sein, die IDE zu beenden und neu zu starten.
Wie immer bei sowas: zeig mal Code, der das Verhalten reproduzierbar vorführt, dann kann man auch nach Lösungen (oder Alternativen) suchen; so ist das doch nur im-Trüben-fischen.
cu
Narses
//EDIT: Grad nochmal getestet, Server.exe aus dem TermCharTut gestartet und per Taskmanager/Prozesse gekillt, der Socket wird korrekt geschlossen ( netstat -a an der Kommandozeile zum Prüfen nehmen)
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Piranha 
      
Beiträge: 31
|
Verfasst: Do 07.08.08 00:26
Hallo Narses
Okay, beim ersten Satz hab ich wohl nicht richtig drüber nachgedacht. Ist wohl das "geh mal Computer spielen" Phänomen. Bei beidem weis man was gemeint ist, aber sonst grundsätzlich falsch
Btt:
Die Anwendung läuft definitiv nicht mehr. Als ich das erstemal den Fehler hatte hab ich solche grundlegenden Dinge erstmal selber nachgeschaut. Das lässt sich alleine deswegen ausschließen das das Programm normalerweise zickenterror macht, wenn es 2 Mal gestart wird.
Den teil mit dem Active hab ich nicht so ganz verstanden, aber ja, ich verwende Active um den Socket an und Abzuschalten (ist das vielleicht der Fehler?).
Ich programmiere mit Delphi erst seit 2 Wochen, deswegen nach möglichkeit Schlagwörter nennen, das ich Entsprechendes selber recherchieren kann und nicht 10 mal dumm und dämlich nachfragen muss.
Ich weis nicht inwiefern der Code weiterhilft, da letztendlich eine Drittsoftware
den Crash verursacht.
Es handelt sich bei dem meinem Programm um einen Netzwerk-Compiler für die Source-Engine (Spiele Engine) bei der ich lediglich eine Oberfläche erstelle (die Compiler sind Commandozeile) um das Compilen zu erleichtern und einige Bugs der Compiler zu umgehen.
Um es auf den Punkt zu bringen: Die Software sammelt vom User informationen startet dann, mit diesen Informationen, den Compiler welcher über DosCommand gestartet wird, und alle Ausgaben landen in einem Memo.
Ich denke mal die Entscheidende Stelle ist die hier
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:
| procedure TForm1.bRunClick(Sender: TObject); var _ToolPath: string; _GamePath: string; step: string; i: integer; en: string;
_mpi: string; _mpig: string; _mpiw: string; _mpis: string; _mpil: string; _mpilw: string; _mpin1: string; _mpils: string; _mpin2: string; _mpiport: string; begin
if coGames.Items.Count >= 1 then begin
WriteCFG;
if rEngineEP1.Checked then begin _ToolPath := EP1_ToolPath; end; if rEngineEP2.Checked then begin _ToolPath := OB_ToolPath; end;
step := GameList[coGames.ItemIndex]; i := Pos('#', step); Delete(step, 1, i); _GamePath := step;
if cMPISingle.Checked then begin _mpi := ''; _mpig := ''; _mpiw := ''; _mpis := ''; _mpil := ''; _mpilw := ''; _mpin1 := ''; _mpils := ''; _mpin2 := ''; _mpiport:= ''; end else begin
_mpi := '-mpi ';
if cMPIGraphics.Checked then _mpig := '-mpi_Graphics ' else _mpig := ''; if cMPIWait.Checked then _mpiw := '-mpi_TimingWait ' else _mpiw := ''; if cMPIStats.Checked then _mpis := '-mpi_ShowDistributeWorkStats ' else _mpis := ''; if cLazyMaster.Checked then _mpil := '-mpi_NoMasterWorkerThreads ' else _mpil := ''; if cMPIWorker.Checked then begin _mpilw := '-mpi_WorkerCount '; _mpin1 := fMaxWorkers.Text + ' '; end else begin _mpilw := ''; _mpin1 := ''; end; if cSpeedLimit.Checked then begin _mpils := '-mpi_FileTransmitRate '; _mpin2 := fMaxSpeed.Text + ' '; end else begin _mpils := ''; _mpin2 := ''; end;
_mpiport:= '-mpi_Port ' + fMPIPort.Text;
end;
mCom.Clear; mLog.Lines.Add(TimeToStr(now) + ' : compiling started...'); Cmd.CommandLine := _ToolPath + '\vbsp.exe -game "' + _GamePath + '" "' + fVMFPath.Text + '\' + liVMF.Items[liVMF.ItemIndex] + '"'; Cmd.Execute; repeat Application.ProcessMessages; until Cmd.IsRunning=false;
if NOT cMPISingle.Checked then begin if rEngineEP1.Checked then en := 'EP1'; if rEngineEP2.Checked then en := 'EP2';
i := 0; while i <> Server.Socket.ActiveConnections do begin Server.Socket.Connections[i].SendText('WORK#VIS#' + en +#13#10); Inc(i); end; end;
Cmd.CommandLine := '"' + _ToolPath + '\vvis.exe" ' + _mpi + _mpig + _mpiw + _mpis + _mpil + _mpilw + _mpin1 + _mpils + _mpin2 + _mpiport + ' -game "' + _GamePath + '" "' + fVMFPath.Text + '\' + liVMF.Items[liVMF.ItemIndex] + '"'; Cmd.Execute; repeat Application.ProcessMessages; until Cmd.IsRunning=false;
if NOT cMPISingle.Checked then begin i := 0; while i <> Server.Socket.ActiveConnections do begin Server.Socket.Connections[i].SendText('WORK#RAD#' + en +#13#10); Inc(i); end; end;
Cmd.CommandLine := '"' + _ToolPath + '\vrad.exe" ' + _mpi + _mpig + _mpiw + _mpis + _mpil + _mpilw + _mpin1 + _mpils + _mpin2 + _mpiport + ' -game "' + _GamePath + '" "' + fVMFPath.Text + '\' + liVMF.Items[liVMF.ItemIndex] + '"'; Cmd.Execute; repeat Application.ProcessMessages; until Cmd.IsRunning=false;
end; end;
procedure TForm1.ServerClientRead(Sender: TObject; Socket: TCustomWinSocket); var rc: string; Liste: TStringList;
o, i , j: integer; step: string; begin Liste := TStringList.Create; try rc := Socket.ReceiveText;
Liste.Text := rc;
o := Liste.Count; while o >= 1 do begin i := Pos('ADDME#',Liste[0]); if i <> 0 then begin Inc(id); step := Liste[0]; Delete(step, 1, 6);
liWorkers.AddItem(step + 'Worker ID:' + IntToStr(id) , Socket); Socket.Sendtext('ADDED#' + #10); end;
i := Pos('QUIT#',Liste[0]); if i <> 0 then begin step := Liste[0]; i := 0; while i <> Server.Socket.ActiveConnections -1 do begin if Socket = Server.Socket.Connections[i] then j := i; Inc(i); end;
liWorkers.Items.Delete(j); Socket.Close;
end;
Liste.Delete(0); Dec(o); end;
finally Liste.Free; end; end; |
Ich weiss nicht genau welche Stellen relevant sind. Allerdings geht die Anwendung flöten wenn vvis.exe oder vrad.exe zicken machen. (Was bei den Dingern normal ist).
Zuletzt bearbeitet von Piranha am Do 07.08.08 00:28, insgesamt 1-mal bearbeitet
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Do 07.08.08 00:54
Moin!
Piranha hat folgendes geschrieben: | | Die Anwendung läuft definitiv nicht mehr. |
Wenn der Fall eingetreten ist, was sagt netstat -a (bitte mal die Ausgabe hier reinkopieren). Noch besser wäre fport.exe von sysinternals (mal danach googlen). Hast du XP? Dann bitte auch die Ausgabe von Tasklist.exe dazu tun (z.B. als Anhang). Der ProcessExplorer von denen ist auch ganz nützlich, um sowas auf die Spur zu kommen.
Piranha hat folgendes geschrieben: | | Das lässt sich alleine deswegen ausschließen |
Der Socket ist nach deiner Aussage belegt, also muss es noch ein Handle darauf geben - das würde ich mal eher nicht ausschließen.
Piranha hat folgendes geschrieben: | | Den teil mit dem Active hab ich nicht so ganz verstanden, aber ja, ich verwende Active um den Socket an und Abzuschalten (ist das vielleicht der Fehler?). |
Nein, das ist kein Fehler, das ist (grundsätzlich erstmal) OK so. Die Frage ist: hast du die Eigenschaft .Active des TServerSockets in der IDE auf TRUE stehen?
Piranha hat folgendes geschrieben: | | Ich programmiere mit Delphi erst seit 2 Wochen, deswegen nach möglichkeit Schlagwörter nennen, das ich Entsprechendes selber recherchieren kann und nicht 10 mal dumm und dämlich nachfragen muss. |
Hm, da du mit TServerSocket und einem selbstgebastelten Protokoll arbeitest: hast du dir das hier mal angesehen? Vereinfacht die Netzwerkkommunikation mit den Sockets deutlich...
Piranha hat folgendes geschrieben: | | Ich weis nicht inwiefern der Code weiterhilft, da letztendlich eine Drittsoftware den Crash verursacht. |
Tja, da wird es auf jeden Fall einen Zusammenhang geben.
Piranha hat folgendes geschrieben: | | Die Software sammelt vom User informationen startet dann, mit diesen Informationen, den Compiler welcher über DosCommand gestartet wird, und alle Ausgaben landen in einem Memo. |
Das scheint mir noch ein möglicher Ansatz für weitere Forschung (AFAIK wird da das CreateProcess in einem Thread gekapselt, damit die GUI nicht blockiert - was auch gut so ist, sonst hast du fett Probleme mit den Socket-Kompos, weil die Ereignisse nicht zeitnah abgearbeitet werden - allerdings ist diese Warte-Geschichte in deinem Ansatz auch nicht soo toll über die APM-Schleife gelöst, naja). Wenn diese Kommandozeilenanwendung noch als Zombie an dem Thread hängt, kann das schonmal komische Effekte geben. Hier kann aber wohl nur ein WinAPI-Experte (wie z.B. Luckie) mit qualifizierten Aussagen weiterhelfen; da hab ich auch nicht genug Erfahrung mit.
Piranha hat folgendes geschrieben: | | Ich denke mal die Entscheidende Stelle ist die hier |
Da leider weitere Software in Spiel ist, nutzt der Coder nur wenig, so kann ich´s ja nicht nachstellen.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Piranha 
      
Beiträge: 31
|
Verfasst: Do 07.08.08 01:33
Okay ich denke ich hab es jetzt.
Unter bestimmten umständen wartet die Software auf antworten von den Workern bis ein Tastendruck entsteht (wartet auf Port 23311). Wenn nun ein neuer Compile gestartet wird, kann dieser nicht durchgeführt werden da er im Hintergrund immernoch auf selbigem Port wartet. Schließst man das Programm jetzt, muss wohl etwas dermaßen verkorksen, das selbst der Server von mir der auf Port 15250 horcht (vvis, bzw. vrad wie gesagt auf 23311) auch nicht mehr geschlossen wird.
Schieße ich nachträglich den Prozess ab (vvis/vrad), funktionieren wieder mein Socket und der Socket von der Drittsoftware
Das heisst, ich muss mich jetzt nurnoch informieren wie man effizient Prozesse abschießt.
Danke an alle
Wenn jemand trotzdem eine Lösung hat wie man Sockets mit einem Drittprogramm wieder "frei" machen kann, kann er das gerne posten.
|
|
|