Hier mal ein Beispiel, wie man einen Portscann am besten machen sollte.
Dauernd Threads zu killen und neu zu erstellen halte ich persönlich nicht für sinnvoll, viel besser ist es die Anzahl der Threads konstant zu halten!
Das ganze System ist im Prinzip eine Art Automat zum Nummern ziehen. Solange Nummern vorhanden sind "zieht" sich jeder Thread eine und führt die Überprüfungen durch! Dadurch sind Konflike zwischen den Threads ausgeschlossen.
Hier im Test wird "localhost" gescannt, dadurch sind auch 1000 Überprüfungen gleichzeitig möglich (#ChecksAtSameTime)! Sollte der Code aber für das Internet umgebaut werden ist es unbedingt notwendig die Anzahl zu reduzieren, da es sonst zu Verbindungs-Überlastungen und Timeouts bei anderen Programmen kommen kann.
Code: Alles auswählen
;- PureFan's Critical Section
DisableDebugger
Structure Pure_CS
Cnt.l
EndStructure
Procedure Pure_InitCS(*PCS.Pure_CS)
*PCS\Cnt=0
EndProcedure
Procedure Pure_EnterCS(*PCS.Pure_CS)
!POP Edi ;POP/PUSH dient zum schnellen Einlesen des Parameters *PCS in das Register EDI
!PUSH Edi
!.loop:
Delay(1)
!MOV Esi,1
!XCHG [Edi],Esi ;Wir lesen den alten Wert aus und schreiben als neuen 1 rein!
!CMP Esi,0 ;Alter Wert war null, d.h. die vorige CS ist fertig
!JNE .loop ;Durch das XCHG haben wir automatisch wieder 1 im Speicher
EndProcedure
Procedure Pure_LeaveCS(*PCS.Pure_CS)
*PCS\Cnt=0
EndProcedure
EnableDebugger
;- Definitionen
#minPort = $0000
#maxPort = $FFFF
#ChecksAtSameTime = 1000
Global AktuellerPort: AktuellerPort=#minPort
Global CS.Pure_CS : Pure_InitCS(CS)
Global ThreadCount : ThreadCount = 0
NewList OpenPorts.l()
;- Thread ScanPorts
DisableDebugger
Procedure ScanPorts(OhneFunktion.l)
Repeat
;Jeder Thread zieht eine Nummer zum Überprüfen!
;Der Code hier darf nicht mehrfach gleichzeichtig ausgeführt werden!
;Dies wird durch die CriticalSection gewährleistet
Pure_EnterCS(CS)
If AktuellerPort > #maxPort
ThreadCount-1
Pure_LeaveCS(CS) ;<- WICHTIG! Sonst warten die anderen Threads unendlich
ProcedureReturn 1
EndIf
LokalerPort = AktuellerPort
AktuellerPort+1
Pure_LeaveCS(CS)
;=> Jeder Thread hat eine einmalige Nummer = Port!
;ACHTUNG: OpenNetworkConnection ist hier nur Threadsicher, da ein
;konstanter String verwendet wird!
check=OpenNetworkConnection("localhost",LokalerPort)
If check
CloseNetworkConnection(check)
;=> Der Port ist offen => LL eintragen
Pure_EnterCS(CS)
AddElement(OpenPorts())
OpenPorts()=LokalerPort
Pure_LeaveCS(CS)
EndIf
ForEver
EndProcedure
EnableDebugger
;- Main
InitNetwork()
;1. Starte alle Threads! Es kann passieren, dass das Starten manchmal fehlschlägt,
; daher müssen wir mitzählen
For I=1 To #ChecksAtSameTime
If CreateThread(@ScanPorts(),0)
Pure_EnterCS(CS)
ThreadCount+1
Pure_LeaveCS(CS)
EndIf
Next I
;2. Die Hauptschleife! Sie kann dazu genutzt werden den aktuellen Status
; anzuzeigen
Repeat
Delay(1000)
;Berechne den Status in Prozent und zeige ihn an
Pure_EnterCS(CS)
Cur.l=(AktuellerPort-#minPort)*100/(#maxPort-#minPort)
Debug Str(Cur)+"%"
Pure_LeaveCS(CS)
Until ThreadCount=0 ;=> Bis kein Thread mehr offen ist!
Debug "DONE!"
;3. Ergebnisse auswerten!
ForEach OpenPorts()
Debug OpenPorts()
Next
End
Mfg,
PureFan
EDIT: Ganz kleiner Rechtschreibfehler korrigiert, der jedoch keinen Einfluss auf die Funktionsweise hat
EDIT2: Eine weitere kleine Modifikation durchgeführt, die das ganze möglicherweise etwas stabiler macht.