Entwickler-Ecke
Internet / Netzwerk - Belegten Socket (#10048), frei machen?
Piranha - Mi 06.08.08 23:43
Titel: Belegten Socket (#10048), frei machen?
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.)
GTA-Place - Mi 06.08.08 23:44
OnFormDestroy hilft auch nicht?
Piranha - Mi 06.08.08 23:49
Oh man das geht hier aber schnell :D
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 - 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
Narses - Mi 06.08.08 23:57
Titel: Re: Belegten Socket (#10048), frei machen?
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... :gruebel: sondern nur annehmen. :nixweiss:
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. :arrow: 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. :idea:
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)
Piranha - 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 :D
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
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:
| 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).
Narses - 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. :idea:
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 [
http://www.delphi-forum.de/topic_TNBFPA+SocketKompos+mit+Protokollfunktionen_71223.html]? 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. :nixweiss:
cu
Narses
Piranha - 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.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!