Un peu d'optimisation par ici

sinon on est encore dans 100 ans...

Le problème exposé dans ce sujet a été résolu.

Bonsoir à tous, mon problème est très simple: je suis en train de faire une serie d'utilitaires pour le localHost en java et je souhaite pouvoir utiliser une commande qui liste tout appareils dans un réseau local et ensuite pouvoir choisir l'appareil avec lequel on souhaite interagir. Seulement voila, juste pour la commande, j'ai décidé d'utiliser un ping loop, j'ai donc tenté ça mais il lui faut pour de 3 minutes pour tester toutes les adresses avec seulement les 3 derniers chiffres de l'adresse IP, je prends donc peur pour la suite. Quelles sont les perfs de la boucle for par rapport aux autres? voila mon code:

 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
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;


/**
 * Created by white on 09/09/2015.
 */
public class main {
    static final String IP = "192.168.0.51";

    public static void main(String[] args) throws IOException  {
        String ping = "192.168.0.";
        long time = System.currentTimeMillis();
        try {


            for (int i = 0; i < 255; i++) {
                {
                    InetAddress test = InetAddress.getByName(ping + i);
                    if (test.isReachable(5000))
                        System.out.println(test + " is reachable");
                    else
                        System.out.println("nothing found " + i);

                }


            }
        }catch( UnknownHostException e){
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis() - time + " ms");
    }
}

le code est très mal optimisé… ça va juste donner des temps indécents(reforcé en plus par ce 5000 de pingout)

Merci beaucoup les zamis, GouleFutée

+0 -0

Le gros problème, c'est bien le timeout de 5s. Cela veut dire que si l'appareil que tu essayes de contacter ne répond pas, java va essayer pendant 5s avant de passer au suivant. Puisqu'il est plus que probable que la plupart des ip ne soient pas associés à des machines, tu perds énormément de temps pour rien.

Le plus simple pour commencer serait de réduire le timeout. Tu es sur un réseau local, il est donc peu probable qu'une machine ne réponde pas dans les 10ms, tu peux monter à 30ms si tu veux être vraiment sûr, ce qui divise déjà par plus de 100 le temps que tu vas passer dans ta boucle.

Ensuite, il n'est pas nécessaire de tester les adresses dans l'ordre, il pourrait donc être intéressant de créer un certain nombre de thread (potentiellement plus que le nombre de cœurs de la machine, tester une ip ne nécessite que peu de CPU et la majorité du temps est passé à attendre) qui testeraient chacun en parallèle un intervalle d'ip.

Pour rebondir sur ce que j'ai dit un peu plus haut sur le fait que la majorité du temps est passé à attendre que la machine cible réponde, on peut tirer un énorme avantage des calculs asynchrones. Je ne suis pas particulièrement familier avec le Java, mais il semblerait qu'il existe ExecutorService qui permette de faire ça relativement facilement. Ça te permettra d'éviter de manipuler des threads et ça permettra probablement aussi d'éviter de perdre du temps à les créer.

+1 pour olzd, j'ai pas un très bon niveau en réseau, mais l'idée me semble pas mal.

Par-contre, je souligne également la solution de Berdes. En effet, j'avais également testé le multi-thread avec du réseau et après différents test il s'averrait que 32 threads était le nombre idéal de threads que je devais lancer pour faire le plus de requète. De plus, je suis du même avis 5s sur un réseau local, c'est trop long.

+1 -0

La solution de olzd est idéale en théorie, mais dans la pratique presque tous les systèmes d'exploitation bloquent les broadcast pings par défaut.

Je crois que la meilleure solution est, comme proposée plus haut, de paralléliser les pings. Et clairement avec un timeout de moins que 5 secondes (même une seconde c'est assez long sur un réseau local).

Merci pour toutes vos reponses^^ et c est justement la conclusion a laquelle je suis arrivé. Un dernier petit probleme: un processeur peu agé(un vieux pentium) peut il tenir la charge de 32 threads? Je dis ça pour la compatibilité. Je ne pense vu que c est juste des interations de boucles et un ping par un. Merci beaucoup encore, je teste tout ça et je vous fera part de l optimisation max que j aurais atteint ^^

Et si un appareil est conecté mais ne répond volontairement pas au ping ? Ca peut arriver et éventuellement ça se configure.

En vérité, les logiciels (et l'OS lui-même) qui listent les appareils disponibles sur le réseau local font plutôt de l'UPNP. Ca permet non seulement de récupérer les IP mais aussi d'obtenir d'autres informations générales: type d'appareil (PC, smarphone, TV, console de jeu, routeur, NAS, etc.), ses capacités en terme de multimédia et de stockage (lecture de films et de musique, accès SMB, FTP, etc.) , et autres.

Il faut se renseigner sur l'UPNP pour en savoir plus. C'est un protocole qui fonctionne via UDP. La requête de départ pour demander qui est connecté se fait en broadcast, mais il y a beaucoup moins de chances que l'OS et/ou le routeur et/ou le firewall bloque un broadcast de couche 4 plutôt qu'un ping qui est dans la couche 3…

+1 -0

Et si un appareil est conecté mais ne répond volontairement pas au ping ? Ca peut arriver et éventuellement ça se configure.

QuentinC

Je vais peut-être dire une bêtise, mais si c'est le cas, c'est probablement que la machine veut être "invisible" sur le réseau, non ?

Si c'est le cas, l'utilitaire pourrait prévoir un prompt pour saisir une adresse à la main pour les opérations suivantes sans trop de soucis à priori.

Tu pings toutes les adresses et lit la table ARP de la machine host ?
Tu peux eventuellement utiliser nmap pour faire de la decouverte de reseau, incluant d'autres protocoles et du scan de ports.

J'utilise ces deux techniques en local et je n'ai jamais eu de probleme particulier. Notamment, c'est la seule possibilite que j'ai lorsqu'une nouvelle machine est branchee et se connecte au reseau, sans etre initialisee pour mon reseau domestique (comprendre mettre en place l'UPNP ou autre).

+0 -0

J'utilise Python mais peu importe. Par contre, je n'utilise pour OS sur la machine host que Linux.
La table se trouve dans /proc/net/arp. Je verifie son existence, l'ouvre, la parse et retourne un joli tableau avec en prime le type de hardware, protocole et tout le tintouin.

Pour Windows, je ne sais pas ou elle se situe.

+0 -0

Lorsqu'une machine se retrouve a communiquer avec une autre sur le reseau (ce qui arrive a peu pres tout le temps - il suffit d'un paquet en broadcast), elle va enregistrer dans sa table ARP, temporairement, des informations recues (ip, type de harware, interface, adresse MAC notamment).

De fait, lorsque tu pings une machine, de toute maniere si celle-ci repond, l'information sera disponible dans la table ARP. L'avantage est alors de disposer d'information supplementaire. Dans mon cas, je m'en sers pour essayer de reveiller en Wake-On-Lan des machines de mon reseau qui ne ping plus: lorsque mon service de monitoring s'appercoit qu'une machine ne ping plus alors que'elle se trouve encore dans le cache ARP, j'envoie un paquet magique avec l'adresse MAC pour essayer de la reveiller.

L'avantage evident que j'y vois c'est surtout qu'en Python, parser cette table est fait en une ligne, alors qu'extraire l'information de la reponse du ping est (un tout petit peu) plus chiant. :)

Mais un des soucis, c est que parser cette table il faut donner sa localisation exacte et elle change en fonction de l os… donc il faudrait changer le chemin de la table a chaque initialisation du programme … ce qui est très fastidieux. A moins de trouver un fonction qui donne ce chemin en java, je crois que cette solution peut devenir très vite lourde à mettre en place. Donc je ne sais pas trop quelle technique utiliser :/

C'est bien pour ca que j'ai precise que je considerais que l'OS de la machine hote etait un Unix.
Ceci dit, sous Windows comme sous Unix, tu as le commande arp que tu peux utiliser directement et parser son resultat.

Apres, peut etre que si tu n'as besoin que de savoir si la machine repond, le resultat d'un ping est suffisant en effet.

par contre il n'arrive pas a ping avec une durée < 5000 ms (avec isReachable), mais je resume: j'initialize une variable String ip = "196.168.0." puis je lance mes 32 threads qui testent chacun disons 10 test dans des boucles for puis je recupere les addresses qui repondent dans une arrayList<InetAdresses> pour les conserver Voila je crois que mon pseudo code est fait^^. Merci à tous pour vos aides

P.S: mon ping marche pour mon NAS, ma free , mon pc mais pas les autres pc connectés en réseau c'est étrange, je n'ai pourtant pas fais de configuration particulière :/

+0 -0

Attend. Quand j'ai dis 32 threads, c'était pour ma machine !

Vérifie que pour ta machine ce soit également le nombre de threads optimal. ( Augmente au fur et a mesure le nombre de threads et vérifie que le nombre de ping que tu puisses effectuer augmente également ).

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte