OpenNetworkConnection : Comment ça marche ?

Programmation d'applications complexes
Avatar de l’utilisateur
ZapMan
Messages : 460
Inscription : ven. 13/févr./2004 23:14
Localisation : France
Contact :

OpenNetworkConnection : Comment ça marche ?

Message par ZapMan »

La fonction OpenNetworkConnection(AdrIP$, PortC) est une véritable merveille. Mais.... elle bloque mon poste pendant 1 à 2 secondes s'il n'y a personne à AdrIP$.
Je comprends pourquoi : l'adresse est testée, puis re-testée, puis re-re-testée dans l'espoir que quelqu'un finisse pas répondre.
L'ennui, c'est que tout ça prend du temps. Moi, je voudrais faire une exploration de mon réseau pour voir qui est connecté, et cette méthode d'exploration est beaucoup trop lente.
Est-ce que quelqu'un sait :
1- s'il est possible de changer un paramètre pour que cette boucle d'attente soit moins longue

OU

2- qu'elles sont les fonctions API utilisées par OpenNetworkConnection (je n'ai pas réussi à trouver)
Tout obstacle est un point d'appui potentiel.

Bibliothèques PureBasic et autres codes à télécharger :https://www.editions-humanis.com/downlo ... ads_FR.htm
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Message par fweil »

ZapMan,

Utiliser l'API ne changera pas le fait qu'un timeout assez long est toujours nécessaire pour tester une connection.

Le truc à faire pour ne pas rester planté devant le PC pendant des heures si on veut tester une classe IP complète, c'est d'utiliser des threads ... il n' y a que ça !

Et alors là c'est tout de suite moins simple, bien sûr.

Entre autres parce que le multi-threading pose des tas de problèmes de fiabilité et de stabilité.

De plus, pour tester une suite d'adresses IP, il est nécessaire de créer une boucle qui fait varier les octets de l'adresse IP dans une incrémentation pas simple. En effet une adresse IP est une chaine de caractères (y compris pour la commande OpenNetworkConnection()), mais elle est constituée de valeurs octets non signés, dans l'ordre des poids croissants de gauche à droite.

Or chacun sait que les octets d'un entier long sont placés de droite à gauche etc ...

Donc faire une incrémentation d'une valeur dans une boucle ne marche pas pour pointer une série d'IPs successives.

Alors c'est le binz !

Bon mais, une fois résolus tous ces petits problèmes, on peut arriver à des résultats intéressants quand même.

Le code qui vient n'est pas commenté, mais bon !

Il reste quelques bugs dans la transmission des résultats au ListIcon, à cause du multi-threading que je ne maîtrise pas assez bien pour empêcher l'apparition intempestive de morceaux de chaines de caractères de temps en temps.

...

J'espère néanmoins que cela te donnera plein d'indications sur la méthode et les outils.

Je commenterai mieux ce code dans une prochaine version.

Code : Tout sélectionner

Enumeration
  #Window_Main
  #StatusBar
  #Gadget_Text_Start
  #Gadget_Text_End
  #Gadget_Button_OK
  #Gadget_Button_Cancel
  #Gadget_IP_Start
  #Gadget_IP_End
  #Gadget_ListIcon
EndEnumeration

#MaxThreads = 1000

NewList Threads.l()

Global StartAddress.l, EndAddress.l, sStartAddress.s, sEndAddress.s
Global Run.l
Global TotalConnections.l, TotalThreads.l, CurrentConnection.s
Global OldTotalConnections.l, OldTotalThreads.l, OldCurrentConnection.s
Global hListIconGadget.l

Procedure UpdateListIcon(String.s)
EndProcedure

Procedure TestConnectionToIP(IPAddress.l)
  sIPAddress.s = IPString(IPAddress)
  #PING_TIMEOUT = 1000
  strMessage.s
  Echo.ICMP_ECHO_REPLY
  EchoMessage.s = "Hello there " + Space(20)
  tz = GetTickCount_()
  hFile = IcmpCreateFile_()
  lngResult = IcmpSendEcho_(hFile, IPAddress, EchoMessage, Len(EchoMessage), 0, Echo, SizeOf(ICMP_ECHO_REPLY), #PING_TIMEOUT)
  If lngResult = 0
      PingResult = Echo\Status * -1
    Else
      PingResult = Echo\RoundTripTime
  EndIf
  lngResult = IcmpCloseHandle_(hFile)
  If PingResult >= 0
      While WindowEvent() : Wend
      CurrentConnection = "Scanning " + sIPAddress + " OK"
      If CountList(Threads()) > #MaxThreads
          While CountList(Threads()) > #MaxThreads / 2
            ResetList(Threads())
            NextElement(Threads())
            WaitThread(Threads())
            Sleep_(2500)
            DeleteElement(Threads())
            TotalThreads - 1
          Wend
      EndIf
      AddGadgetItem(#Gadget_ListIcon, -1, sIPAddress + Chr(10) + Str(GetTickCount_() - tz))
      While WindowEvent() : Wend
  EndIf
  TotalConnections - 1
  TotalThreads - 1
EndProcedure

Procedure RunScan()
  Sleep_(500)
  StartAddress.l = GetGadgetState(#Gadget_IP_Start)
  EndAddress.l = GetGadgetState(#Gadget_IP_End)
  iStartAddress = IPAddressField(StartAddress, 0) << 24 + IPAddressField(StartAddress, 1) << 16 + IPAddressField(StartAddress, 2) << 8 + IPAddressField(StartAddress, 3)
  iEndAddress = IPAddressField(EndAddress, 0) << 24 + IPAddressField(EndAddress, 1) << 16 + IPAddressField(EndAddress, 2) << 8 + IPAddressField(EndAddress, 3)
  For iIPAddress = iStartAddress To iEndAddress
    IPAddress = MakeIPAddress(IPAddressField(iIPAddress, 3), IPAddressField(iIPAddress, 2), IPAddressField(iIPAddress, 1), IPAddressField(iIPAddress, 0))
    sIPAddress.s = IPString(IPAddress)
    CurrentConnection = "Scanning " + sIPAddress
    ParameterString.s = Str(IPAddress)
    TotalConnections + 1
    ThreadID = CreateThread(@TestConnectionToIP(), IPAddress)
    TotalThreads + 1
    Delay(50)
  Next
  Run = #FALSE
  TotalThreads - 1
EndProcedure

Procedure Stop(ThreadID)
  Run = #FALSE
  CurrentConnection = "Canceling ..."
  If ThreadID <> 0
      CurrentConnection = "Canceling " + Str(ThreadID)
      KillThread(ThreadID)
      TotalThreads - 1
  EndIf
  ResetList(Threads())
  While NextElement(Threads())
    CurrentConnection = "Canceling " + Str(Threads())
    KillThread(Threads())
    TotalThreads - 1
  Wend
  ClearList(Threads())
  CurrentConnection = "Done"
EndProcedure

Procedure DoWeRun(ThreadID.l)
  If ThreadID <> 0
      Stop(ThreadID)
      SendMessage_(hListIconGadget, #LVM_DELETEALLITEMS, 0, 0)
  EndIf
  Run = #TRUE
  CurrentConnection = "Scanning ..."
  ThreadID = CreateThread(@RunScan(), 0)
  TotalThreads + 1
  ProcedureReturn ThreadID
EndProcedure

;
;
;
  sStartAddress.s = "194.79.120.0"
  sEndAddress.s = "194.79.120.255"
  StartAddress.l
  EndAddress.l
  Quit = #FALSE
  Run = #FALSE
  WindowXSize = 640
  WindowYSize = 480
  If InitNetwork()
      If OpenWindow(#Window_Main, 0, 0, WindowXSize, WindowYSize, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "Ip sniffer")
          AddKeyboardShortcut(#Window_Main, #PB_Shortcut_Escape, #PB_Shortcut_Escape)
          AddKeyboardShortcut(#Window_Main, #PB_Shortcut_Return, #PB_Shortcut_Return)
          AddKeyboardShortcut(#Window_Main, #PB_Shortcut_Delete, #PB_Shortcut_Delete)
          If CreateStatusBar(#StatusBar, WindowID())
              AddStatusBarField(400)
              AddStatusBarField(120)
              AddStatusBarField(120)
          EndIf
          If CreateGadgetList(WindowID(0))
              TextGadget(#Gadget_Text_Start, 10, 10, 80, 20, "Start address")
              TextGadget(#Gadget_Text_End, 10, 30, 80, 20, "End address")
              ButtonGadget(#Gadget_Button_OK, 230, 10, 60, 20, "Go")
              ButtonGadget(#Gadget_Button_Cancel, 230, 30, 60, 20, "Cancel")
              IPAddressGadget(#Gadget_IP_Start, 100, 10, 120, 20)
              IPAddressGadget(#Gadget_IP_End, 100, 30, 120, 20)
              hListIconGadget = ListIconGadget(#Gadget_ListIcon, 10, 50, WindowXSize - 20, WindowYSize - 80, "Server found", 120)
              AddGadgetColumn(#Gadget_ListIcon, 1, "Time", 80)
          EndIf
          SetGadgetState(#Gadget_IP_Start, MakeIPAddress(Val(StringField(sStartAddress, 1, ".")), Val(StringField(sStartAddress, 2, ".")), Val(StringField(sStartAddress, 3, ".")), Val(StringField(sStartAddress, 4, "."))))
          SetGadgetState(#Gadget_IP_End, MakeIPAddress(Val(StringField(sEndAddress, 1, ".")), Val(StringField(sEndAddress, 2, ".")), Val(StringField(sEndAddress, 3, ".")), Val(StringField(sEndAddress, 4, "."))))
          StartAddress = GetGadgetState(#Gadget_IP_Start)
          EndAddress = GetGadgetState(#Gadget_IP_End)
          Repeat
            Select WindowEvent()
              Case #PB_Event_CloseWindow
                Quit = #TRUE
              Case #PB_Event_Menu
                Select EventMenuID()
                  Case #PB_Shortcut_Escape
                    If Run
                        Stop(ThreadID)
                      Else
                        Quit = #TRUE
                    EndIf
                  Case #PB_Shortcut_Return
                    ThreadID = DoWeRun(ThreadID)
                  Case #PB_Shortcut_Delete
                    Stop(ThreadID)
                EndSelect
              Case #PB_Event_Gadget
                Select EventGadgetID()
                  Case #Gadget_IP_Start
                    sStartAddress = GetGadgetText(#Gadget_IP_Start)
                    StartAddress = GetGadgetState(#Gadget_IP_Start)
                  Case #Gadget_IP_End
                    sEndAddress = GetGadgetText(#Gadget_IP_End)
                    EndAddress = GetGadgetState(#Gadget_IP_End)
                  Case #Gadget_Button_OK
                    ThreadID = DoWeRun(ThreadID)
                  Case #Gadget_Button_Cancel
                    Stop(ThreadID)
                EndSelect
            EndSelect
            If OldCurrentConnection <> CurrentConnection
                OldCurrentConnection = CurrentConnection
                StatusBarText(#StatusBar, 0, CurrentConnection)
            EndIf
            If OldTotalConnections <> TotalConnections
                OldTotalConnections = TotalConnections
                StatusBarText(#StatusBar, 1, Str(TotalConnections))
            EndIf
            If OldTotalThreads <> TotalThreads
                OldTotalThreads = TotalThreads
                StatusBarText(#StatusBar, 2, Str(TotalThreads))
            EndIf
            Sleep_(1)
          Until Quit
          Stop(ThreadID)
      EndIf
  EndIf
  TerminateProcess_(GetCurrentProcess_(), 0)
End
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
Avatar de l’utilisateur
ZapMan
Messages : 460
Inscription : ven. 13/févr./2004 23:14
Localisation : France
Contact :

Message par ZapMan »

Super ! C'est quand même beaucoup plus rapide qu'avec la fonction PB. Ca répond pile poil à mon besoin (je dois scanner mon réseau d'entreprise pour savoir qui est connecté et je n'ai qu'une petite plage d'adresses à explorer).
Merci d'avoir répondu aussi vite et aussi bien. :D
Tout obstacle est un point d'appui potentiel.

Bibliothèques PureBasic et autres codes à télécharger :https://www.editions-humanis.com/downlo ... ads_FR.htm
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Message par fweil »

Comme on dit :

le code qui compile, c'est bien plus facile, et plus rigolo, que le code qu'est pas beau !

Ben je suis bien content de t'avoir rendu service.

Si tu l'utilises mon programme, tu mets mon nom dedans, comme ça on ne m'oublieras plus jamais :wink:
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.
Répondre