sudo lsof -i -P | grep -i LISTEN
Ohne das vorangestellte „sudo“, das eine Eingabe des Administrator-Kennworts erfordert, liefert der Befehl nur Prozesse des aktuell angemeldeten Nutzers. Ergebnis ist in jedem Fall eine Liste der folgenden Art:
]]>COM ist lange, lange Jahre Microsofts Objektmodell gewesen und was die Menge an existierendem COM-Code anbelangt auch sehr erfolgreich. Das später dazugekommene DCOM zur verteilten Komponentenentwicklung (als Gegenstück zu CORBA) war aus mancherlei Gründen weniger erfolgreich und Microsoft bastelte bald an einer neuen Variante. Diese neue Variante entwickelte sich intern schnell weiter und es wurde daraus das, was wir heute unter der „.Net-Plattform“ kennen. Es ist also kein Wunder, daß Microsoft einige Anstrengung unternommen hat, die alte COM-Welt nicht einfach zu vergessen und damit die unzähligen existierenden Komponenten unbrauchbar zu machen. Stattdessen ist tief in .Net die Möglichkeit integriert, COM-Objekten (beinahe) so zu verwenden wie native .Net-Komponenten. Dieser Mechanismus wird „COM Interop“ genannt.
Es gibt jedoch einen entscheidenden Unterschied zwischen beiden Modellen: .Net-Code ist sogenannter „managed Code“, wird von einer Runtime, der sogenannten CLR (Common Language Runtime) verwaltet, was in etwa der Java VM entspricht. Zu den Aufgaben dieser Runtime gehört unter anderem die Speicherverwaltung, auch Garbage Collection (GC) genannt. In .Net (wie in Java) hat man als Entwickler wenig Kontrolle darüber, wie, wann und ob überhaupt der GC nicht mehr benötigte Objekte freigibt und damit auch von diesen benutzte Ressourcen. Ganz anders bei COM. Der überwiegende Teil der COM-Komponenten wurde sicher in C/C++ erstellt, also in unmanaged Code. Hier ist der Entwickler selbst für Speicher-Allokation und -Freigabe zuständig. Treffen diese beiden Welten aufeinander stellt sich die Frage, wer denn nun die Verwaltung der COM-Objekte übernimmt. Nach wie vor kann man das als Entwickler von .Net-Code der CLR bzw. dem GC überlassen. Aber da sind wir auch schon bei dem nächsten Problem:
Wenn man in .Net eine Referenz auf eine COM-Bibliothek anlegt, wird ein sogenannter RCW (Runtime Callable Wrapper) erstellt, eine Art Proxy für das COM-Objekt. Hier findet das Marshalling der Daten statt. Pro COM-Objekt gibt es immer nur einen RCW, unabhängig von der Anzahl der Instanzen. Hierbei spielt das sogenannte „Appartment Model“ eine Rolle. Unter COM gibt es verschiedener solcher Modelle, im wesentlichen die beiden MTA und STA, Multi Threaded Appartment und Single Threaded Appartment. Das Appartment besagt, ob eine COM-Komponente von verschiedenen Threads (MTA) oder nur von einem einzigen (STA) angesprochen werden kann. Um diese beiden Varianten in .Net abzubilden, hat dort jeder Thread ebenfalls eines der beiden Appartments, default ist „MTA“. Durch ein Attribut an der Main()-Methode wird das Appartment aber eigentlich immer auf STA gestellt, um Probleme mit eben diesen STA-COM-Objekten zu vermeiden.
Solange man direkt aus dem Haupt-Thread mit COM-Objekten arbeitet und das nicht exzessiv, hat man eigentlich keine Probleme. Die eigentliche Arbeit wird einem von der CLR bzw. dem RCW abgenommen. Fängt man jedoch an, etwas komplexere Aufgaben zu erledigen und dies auch durch Einsatz von Multi-Threading wird es schnell unangenehm. Bei den ersten etwas umfangreicheren Tests einer unserer WinForms-Anwendungen zeigte sich, daß es zu sehr unschönen Effekten kommen kann. In bestimmten Fällen werden dort zwei Hintergrund-Threads erzeugt, die jeweils über COM Outlook fernsteuern. Leider stürzte die Anwendung dabei auf einigen Rechnern regelmäßig nach einigen hundert Aktionen ab. Manchmal mit einer „MemoryAccessViolation“ und manchmal einfach ohne irgendeine Nachricht, da war die Anwendung einfach mal eben weg. Wenn wir das Glück hatten, zumindest eine Fehlermeldung zu bekommen, deutete der Stacktrace auf ein Problem in der Anzeigekomponente, genauer gesagt im TreeView hin. Tagelange Suche nach Problemen dort zeigte aber keinerlei Auffälligkeiten in diesem Teil des Codes.
Da das Problem auf zumindest einem Rechner mehr oder weniger deterministisch auftrat deutete das Bauchgefühl relativ schnell auf COM-Interop hin. Nach tagelangen Recherchen ergaben folgende Maßnahmen eine Lösung:
Ich hoffe, diese Informationen werden irgendwann einmal jemandem helfen, die Fehler, die wir gemacht haben, zu vermeiden. Vielleicht helfen sie ja mir selbst beim nächsten Projekt…
]]>Der folgende Code-Snippet erzeugt für einen gegebenen Dateinamen genau solche einen eindeutigen Namen mit der kleinstmöglichen Zahl.
public static String getUniqueFileName(String tempFileName, String extension, String extensionSeparator, String suffixSeparator) { String tempFileNameNew; if (extension == null || extension.length() == 0) { tempFileNameNew = tempFileName; } else { tempFileNameNew = tempFileName + extensionSeparator + extension; } File file = new File(tempFileNameNew); int suffix = 1; while (file.isFile()) { if (extension == null || extension.length() > 0) { tempFileNameNew = tempFileName + suffixSeparator + String.valueOf(suffix); } else { tempFileNameNew = tempFileName + suffixSeparator + String.valueOf(suffix) + extensionSeparator + extension; } file = new File(tempFileNameNew); suffix++; } return tempFileNameNew; }
Möglicher Aufruf wäre also:
String newFilename = getUniqueFileName("Neues Textdokument", "txt", ".", "~");]]>
netstat -ano | find /i „Abhören“
In meinem Fall resultiert daraus die folgende Ausgabe:
C:\Programme\Support Tools>netstat -ano | find /i "Abhören"
TCP 0.0.0.0:21 0.0.0.0:0 ABHÖREN 1408
TCP 0.0.0.0:25 0.0.0.0:0
ABHÖREN 1408
TCP 0.0.0.0:80 0.0.0.0:0
ABHÖREN 1408
TCP 0.0.0.0:135 0.0.0.0:0
ABHÖREN 1048
TCP 0.0.0.0:443 0.0.0.0:0
ABHÖREN 1408
TCP 0.0.0.0:445 0.0.0.0:0
ABHÖREN 4
TCP 0.0.0.0:987 0.0.0.0:0
ABHÖREN 11344
TCP 0.0.0.0:1048 0.0.0.0:0
ABHÖREN 1408
TCP 0.0.0.0:2869 0.0.0.0:0
ABHÖREN 1924
TCP 0.0.0.0:3389 0.0.0.0:0
ABHÖREN 992
TCP 0.0.0.0:5051 0.0.0.0:0
ABHÖREN 1832
TCP 0.0.0.0:19226 0.0.0.0:0
ABHÖREN 3952
TCP 0.0.0.0:23761 0.0.0.0:0
ABHÖREN 664
TCP 127.0.0.1:1082 0.0.0.0:0
ABHÖREN 3308
TCP 127.0.0.1:1118 0.0.0.0:0
ABHÖREN 2948
TCP 127.0.0.1:4664 0.0.0.0:0
ABHÖREN 4020
TCP 127.0.0.1:6083 0.0.0.0:0
ABHÖREN 3592
TCP 127.0.0.1:31595 0.0.0.0:0
ABHÖREN 304
TCP 192.168.136.1:139 0.0.0.0:0
ABHÖREN 4
TCP 192.168.154.1:139 0.0.0.0:0
ABHÖREN 4
TCP 192.168.213.22:139 0.0.0.0:0
ABHÖREN 4
Unter englischem Betriebssystem muß man „abhören“ durch „listening“ ersetzen. Die letzte Spalte der Ausgabe gibt dabei (Windows XP oder höher vorausgesetzt) die ID des Prozesses an, der den jeweiligen Port blockiert. Um nun herauszufinden, welche Anwendung dahintersteckt, öffnet man den Taskmanager (taskmgr) und läßt sich auf dem Tab „Prozesse“ die Prozess-ID mit ausgeben. Dazu wählt man im Menü „Ansicht“ den Punkt „Spalten auswählen“ und markiert „PID“. So läßt sich im obigen Beispiel herausfinden, daß hinter der PID 1408 der Prozess „inetinfo.exe“ steckt, also der Micosoft IIS. Wer hätte das gedacht…
UPDATE: Für Mac-Nutzer gibt es ebenfalls eine Lösung: „Belegte Ports anzeigen – Mac Version„
]]>Eine mögliche Anwendung ist die Umkreissuche innerhalb einer Datenbank, z.B. Filialen eines Unternehmens im Umkreis von 15 km von meinem Wohnort. Der im angehängten Beispielprojekt umgesetzte Algorithmus ist allerdings sehr(, sehr) einfach und geht jeweils die komplette Liste aller Postleitzahlen durch, was auf einer Website mit vielen Anfragen dieser Art zu Performance-Problemen führen kann.
Das angehängte Projekt ist in C# unter .Net 2.0 realisiert und dient nur Demonstrationszwecken, es gibt keine Dokumentation, keine Fehlerbehandlung und (natürlich) keine Gewährleistung. Der Code wird „as-is“ angeboten und kann in eigenen Projekten verwendet werden.
]]>