PDA

View Full Version : [C] scanner internet


misterx
02-01-2020, 11:50
scrivere uno scanner per testare indirizzi IP su internet oggi è alla portata di molti però, fatti due conti mi sono detto: se testo un indirizzo ad esempio sulla porta 80 ed impiego 1 secondo, per 2^32 indirizzi impiegherei 136 anni circa e allora, come risolvere un simile problema se si vuole concludere una intera scansione in poco tempo?
Se usassi 136 PC impiegherei 1 anno, improponibile in quanto costoso.
Se usassi n thread su un singolo PC sino a saturare la banda della scheda di rete, dovrei stabilire quanti thread ci vogliono per arrivare a saturzione ma credo sempre meno di 136 quindi, impiegherei oltr 1 anno.

Idee?

Kaya
07-01-2020, 14:37
Scusa ma cosa pensi di saturare facendo una socket.open ? passano 4 byte in croce ( o meglio, 28 byte se prendi un pacchetto udp).
Diciamo quindi che hai banda da 1 Megabit -> 1024 KBytes = 1.024.024 bytes -> /28= 36 mila pacchetti circa (pacchetto più pacchetto meno).
Questo per quanto concerne la banda ovviamente.
Diciamo pure che un secondo va bene come limite superiore, ma anche da considerare che una chiamata possa rispondere in pochi millisecondi, facciamo una media a 500 ms e manteniamo valido un valore di 30.000 pacchetti (check) al secondo.
2^ 32 sono circa 4 miliardi di ip, che diviso 30.000 fa 143mila secondi e spicci, ovvero circa 40 ore. Che non mi sembra male come tempo.
Ma poniamo che 30.000 pacchetti siano troppi e facciamone invece un quarto, quindi 7.500 avremo come stima 160 ore che è nemmeno una settimana.

Se vuoi un test molto più empirico che teorico, fai qualche test con nmap e metti dentro una classe IP e vedi come si comporta / quanto tempo impiega.

!fazz
07-01-2020, 15:01
purtroppo il calcolo non è così semplice o meglio non bisogna calcolare di saturare la banda ma bensì calcolare sulla base del tempo e del numero di connessioni concorrenti che il tuo s.o. supporta (mi pare 20 per windows 7 / 8.1)
inanzitutto un'apertura di socket impiega pochissimo tempo, altro che 500 ms direi molto più plausibile 5-10 ms ma le connessioni concorrenti comunque rimangono quindi secondo me il tuo sistema deve usare un numero di thread leggermente inferiore al massimo consentito dal tuo s.o. 19 ad esempio per windows 7

per aumentare l'efficienza non puoi assegnare a priori un numero di ip ad ogni thread visto la notevole differenza di tempo tra apertura e timeout ma direi che puoi sviluppare il tuo software con un ulteriore thread di dispatcher che carichi gli indirizzi ip nei vari thread di esecuzione bilanciandone il carico

Kaya
07-01-2020, 16:40
Mi ripeto: dai un occhio all'implementazione di nmap su questa cosa.

Ad ogni modo, non mi risulta proprio che il numero di thread massimo sia 19.
Giusto il primo link saltato fuori: https://eknowledger.wordpress.com/2012/05/01/max-number-of-threads-per-windows-process/

!fazz
08-01-2020, 10:35
Mi ripeto: dai un occhio all'implementazione di nmap su questa cosa.

Ad ogni modo, non mi risulta proprio che il numero di thread massimo sia 19.
Giusto il primo link saltato fuori: https://eknowledger.wordpress.com/2012/05/01/max-number-of-threads-per-windows-process/

non ho parlato di un limite nei thread ma di un limite nel numero di connessioni tcp concorrenti

Kaya
08-01-2020, 13:39
Guarda che secondo me confondi. Sono 20 e riguardo le connessioni in ingresso (rif: https://community.spiceworks.com/topic/980907-windows-10-maximum-connection-limits )
Interessante come il problema quindi sia più nel file descriptor che non nello stck tcp ( https://stackoverflow.com/questions/2332741/what-is-the-theoretical-maximum-number-of-open-tcp-connections-that-a-modern-lin )

misterx
08-01-2020, 13:48
grazie ad entrambi per i vostri interventi.
Quindi istanziare più di 20 thread non avrebbe senso, viste le limitazioni imposte dall'SO.

Kaya
08-01-2020, 14:21
Quindi istanziare più di 20 thread non avrebbe senso, viste le limitazioni imposte dall'SO.
Scusa ma non hai capito ciò che abbiamo scritto.
I thread sono una cosa, le connessioni TCP/UDP un altra.
Thread puoi averne diciamo "quanti ne vuoi", finchè non finisci la memoria

https://superuser.com/questions/1469924/maximum-threads-limit-per-process-in-windows-10
My system runs out of memory a little after testlimit64 -t passes 270,000 threads created.
Il limite di 20 è un limite di LICENZA che impone Microsoft e riguarda solo le connsessioni in ingresso. (sotto linux non c'è https://unix.stackexchange.com/questions/477122/max-no-of-tcp-connections-on-a-linux-system )

misterx
08-01-2020, 14:46
Scusa ma non hai capito ciò che abbiamo scritto.
I thread sono una cosa, le connessioni TCP/UDP un altra.
Thread puoi averne diciamo "quanti ne vuoi", finchè non finisci la memoria

Il limite di 20 è un limite di LICENZA che impone Microsoft e riguarda solo le connsessioni in ingresso. (sotto linux non c'è https://unix.stackexchange.com/questions/477122/max-no-of-tcp-connections-on-a-linux-system )


mi riferivo appunto alle licenze di microsoft.
Se al massimo posso avere 20 connessioni TCP contemporaneamente è inutile istanziare più di 20 thread, giusto?

Kaya
08-01-2020, 14:59
Scusa ma leggi quello che scrivo?
Si parla di CONNESSIONI IN INGRESSO, non in uscita.

!fazz
08-01-2020, 15:02
mi riferivo appunto alle licenze di microsoft.
Se al massimo posso avere 20 connessioni TCP contemporaneamente è inutile istanziare più di 20 thread, giusto?

dipende come imposti l'architettura del software io di thread ne farei ad esempio 21 se lavorassi su windows 7
1 dispatcher che carica e bilancia il carico sui diversi thread di scansione
19 thread di scansione
1 thread che raccoglie e analizza i risultati sulla base di quello che vuoi fare
devi gestire bene le strutture di memoria e i lock per aumentare l'efficienza

misterx
08-01-2020, 15:04
Scusa ma leggi quello che scrivo?
Si parla di CONNESSIONI IN INGRESSO, non in uscita.

ops, colpa mia: pensavo in generale.
Quindi il limite è per un applicativo server e non client.
Ok, meglio così, grazie.

misterx
08-01-2020, 15:12
dipende come imposti l'architettura del software io di thread ne farei ad esempio 21 se lavorassi su windows 7
1 dispatcher che carica e bilancia il carico sui diversi thread di scansione
19 thread di scansione
1 thread che raccoglie e analizza i risultati sulla base di quello che vuoi fare
devi gestire bene le strutture di memoria e i lock per aumentare l'efficienza

ci sto già lavorando e per lo sviluppo sto usando Embarcadero di Borland. Ho già scritto tempo fa un applicativo server ma mai uno Client che istanziasse n thread quindi, devo capire bene come sincronizzare le risorse comuni.
Embarcadero ha un thread principale e se si vogliono usare i metodi che mette a disposizione tra i quali send e receive dei socket, questi devono essere sinconizzati per evitare eccezioni in maniera randomica.

Poi di problemi ne ho individuati anche molti altri, ma un passo alla volta.

Grazie 1000

Mettiu_
08-01-2020, 18:28
Domanda: ma se bypassi del tutto l'interfaccia dei socket fornita dal SO e spari direttamente i pacchetti nella scheda di rete (ovviamente devi generarti a mano i vari header necessari per generare un ping).
In questo modo hai più libertà ma devi interfacciarti col driver di più basso livello (anche per leggere tutto il traffico di risposta che arriva)...

misterx
08-01-2020, 19:50
Domanda: ma se bypassi del tutto l'interfaccia dei socket fornita dal SO e spari direttamente i pacchetti nella scheda di rete (ovviamente devi generarti a mano i vari header necessari per generare un ping).
In questo modo hai più libertà ma devi interfacciarti col driver di più basso livello (anche per leggere tutto il traffico di risposta che arriva)...


intendi con le winsock?

forse intendeva by-passando l'SO e magari usando direttamente il driver della scheda.

WarDuck
25-01-2020, 20:13
scrivere uno scanner per testare indirizzi IP su internet oggi è alla portata di molti però, fatti due conti mi sono detto: se testo un indirizzo ad esempio sulla porta 80 ed impiego 1 secondo, per 2^32 indirizzi impiegherei 136 anni circa e allora, come risolvere un simile problema se si vuole concludere una intera scansione in poco tempo?
Se usassi 136 PC impiegherei 1 anno, improponibile in quanto costoso.
Se usassi n thread su un singolo PC sino a saturare la banda della scheda di rete, dovrei stabilire quanti thread ci vogliono per arrivare a saturzione ma credo sempre meno di 136 quindi, impiegherei oltr 1 anno.

Idee?

Beh messo così il problema è abbastanza vago.

In primis, di che protocollo stiamo parlando? Come vorresti testare le porte? Sia su UNIX che su Windows puoi usare le RAW socket per bypassare un po' di stack di rete e forse ti conviene (nota che tipicamente per usarle hai bisogno dei privilegi di root).

Proverei prima un prototipo con uno/due thread e proverei ad usare socket non bloccanti, ovvero intanto spari tutte le richieste senza aspettare, dopodiché vedi chi risponde.

Ad esempio nel caso di TCP, usando le raw socket puoi mandare pacchetti SYN a raffica con un thread e usarne un altro per leggere chi risponde (oppure banalmente usare lo stesso dopo aver finito di sparare i SYN).

Chiaramente qui non stiamo considerando eventuali monitor di sicurezza che beccano questi scanner.

misterx
27-01-2020, 10:35
Beh messo così il problema è abbastanza vago.

In primis, di che protocollo stiamo parlando? Come vorresti testare le porte? Sia su UNIX che su Windows puoi usare le RAW socket per bypassare un po' di stack di rete e forse ti conviene (nota che tipicamente per usarle hai bisogno dei privilegi di root).

Proverei prima un prototipo con uno/due thread e proverei ad usare socket non bloccanti, ovvero intanto spari tutte le richieste senza aspettare, dopodiché vedi chi risponde.

Ad esempio nel caso di TCP, usando le raw socket puoi mandare pacchetti SYN a raffica con un thread e usarne un altro per leggere chi risponde (oppure banalmente usare lo stesso dopo aver finito di sparare i SYN).

Chiaramente qui non stiamo considerando eventuali monitor di sicurezza che beccano questi scanner.

ciao,
il protocollo che sto usando è TCP. Uso socket bloccanti in quanto nel caso di socket non bloccanti poi dovrei gestire anche gli eventi.
A quanto ne ho capito, usando socket bloccanti il processo, nel mio caso il thread, si ferma sino a quando non arriva un qualche dato ma poi devo continuare a leggere sino alla fine di quello che mi interessa, ad esempio, nel caso di una pagina http. sino a "\r\n\r\n\".
Se istanzio fino a 30 thread e relative socket con ovviamente 30 IP diversi, mi arrivano dati, se vado oltre non mi arriva più nulla. Non mi è chiaro cosa o chi blocchi i dati in arrivo visto che sono client e gà mi è stato detto che non ci sono limitazioni in questo senso.
Quando apro una connessione invio un semplice "GET / \r\n" ed attendo risposta, se non arriva si ha timeout.
Anche l'invio dei dati non è banale, si deve capire se e quanti dati sono stati inviati ed in caso contrario inviare nuovamente.
Insomma, un bel programmino banale solo in apparenza e che fa spremere le meningi :D

WarDuck
27-01-2020, 12:17
ciao,
il protocollo che sto usando è TCP. Uso socket bloccanti in quanto nel caso di socket non bloccanti poi dovrei gestire anche gli eventi.
A quanto ne ho capito, usando socket bloccanti il processo, nel mio caso il thread, si ferma sino a quando non arriva un qualche dato ma poi devo continuare a leggere sino alla fine di quello che mi interessa, ad esempio, nel caso di una pagina http. sino a "\r\n\r\n\".

Se stai usando socket SOCK_STREAM normali con TCP, funzioni come read() e write() sono bloccanti. Ad esempio read() blocca se il buffer della socket è vuoto quindi non hai effettivamente dati da leggere, mentre write() non blocca mai a meno che il buffer di scrittura della socket non sia pieno.

Effettivamente più che usare socket non bloccanti una alternativa potrebbe essere quella di usare select(), poll() o nel caso di Linux epoll() che ti consentono di monitorare contemporaneamente più socket, quindi ti viene restituito il descrittore di una delle socket pronte per leggere ad esempio. Tieni presente che è proprio quello che fanno i web server più avanzati come lighttpd o nginx per gestire le connessioni.


Se istanzio fino a 30 thread e relative socket con ovviamente 30 IP diversi, mi arrivano dati, se vado oltre non mi arriva più nulla. Non mi è chiaro cosa o chi blocchi i dati in arrivo visto che sono client e gà mi è stato detto che non ci sono limitazioni in questo senso.

Non mi è chiaro se stai usando Windows o Linux, comunque io credo che ai thread bisognerebbe arrivarci il più tardi possibile, perché solo con quelli la vedo difficile scalare più di tanto. Io proverei ad usare 1 thread solo e funzioni come select(), poll() o epoll() per capire quante socket riesci a gestire con tempi ragionevoli.


Quando apro una connessione invio un semplice "GET / \r\n" ed attendo risposta, se non arriva si ha timeout.
Anche l'invio dei dati non è banale, si deve capire se e quanti dati sono stati inviati ed in caso contrario inviare nuovamente.
Insomma, un bel programmino banale solo in apparenza e che fa spremere le meningi :D

Quindi deduco tu stia in realtà cercando di scansionare se dall'altro lato ci sono server HTTP, quindi è un po' più complicato di un semplice port scanner.

Quello che in generale ti consiglio è dato un set di connessioni attive (connesse) è di mandare quante più "GET" senza aspettare la risposta, in maniera da aumentare il throughput.

Ad esempio, dato un array di socket descriptor connessi:

int num_sockets; /* numero effettivo di socket connesse */
int opened_socket[NUM_SOCKETS];

for (int i = 0; i < num_sockets; ++i)
write(opened_socket[i], "GET ...", sizeof..);


E poi aspettare le risposte in batch con una delle funzioni che ti ho indicato prima.

Non ho ben chiaro lo scenario comunque, devi scoprire quali porte diverse dalla 80 hostano HTTP? Oppure basta semplicemente provarti a collegare alla 80 e vedere cosa ti rispondono?

Tieni presente anche che ad oggi credo che la maggioranza dei server web usi HTTPS, che sarebbe un altro bel casino.

misterx
27-01-2020, 12:41
sto programmando in Windows con Borland Builder.

Inviando quel GET desidero scoprire quanti server HTTP attivi ci sono in internet e di quale tipologia, una sorta di censimento/esperimento web.

Ero partito col singolo thread usando un solo socket ma il tempo per risolvere il problema legato ai 2^32 indirizzi IP mi ha fermato, è eccessivo; da questo limite calcolato in 136 anni è nato questo 3d.

WarDuck
27-01-2020, 13:25
sto programmando in Windows con Borland Builder.

Inviando quel GET desidero scoprire quanti server HTTP attivi ci sono in internet e di quale tipologia, una sorta di censimento/esperimento web.

Ero partito col singolo thread usando un solo socket ma il tempo per risolvere il problema legato ai 2^32 indirizzi IP mi ha fermato, è eccessivo; da questo limite calcolato in 136 anni è nato questo 3d.

Mi sembra un po' ambizioso in effetti farlo con una singola macchina usando la semplice forza bruta. :sofico:

In ogni caso sarebbe interessante capire se e dove puoi arrivare prima di saturare la banda, quindi appoggio comunque la pazzia :D.

In realtà di quei 2^32 indirizzi ne dovresti esplorare un po' di meno perché dal mio punto di vista andrebbero escluse tutte le classi private (ad esempio il range di indirizzi tipicamente assegnati alle reti LAN). Diciamo ti risparmi poco più di 16 milioni di indirizzi, certo non sono niente in confronto ai 4 miliardi, ma comunque sempre meglio di niente.

Dopodiché partirei più in piccolo ad esempio restringendo gli IP a quelli Italiani o presunti tali. Inutile fare un censimento degli IP cinesi :read: anche perché più ti allontani e più ti costa in termini di tempo.

Io procederei poi per passi, ad esempio, se tanto pensi di connetterti alla porta 80, tanto vale fare prima un censimento di quanti ti rispondono su quella porta.

Dal momento che tipicamente la connect() aspetta che il 3-way handshake di TCP sia completato, forse potrebbe valere la pena usare i socket raw per mandare prima un arbitrario numero di TCP SYN e vedere quanti rispondono con SYN ACK.

Cioè dal mio punto di vista come ti dicevo prima, la strategia migliore è quella di generare ed avere un numero di pacchetti in volo molto alto. Per fare questo non devi necessariamente aspettare che ti rispondano subito, ma lanciarne quanti più ne puoi e aspettare in seguito.

Il tempo di risposta del server non dipende da te, ma il tempo di generazione del pacchetto e l'invio si.

In alternativa, più semplice che usare i socket raw, puoi fare quello che ti dicevo prima quindi avere in volo tante "GET".

Non ho memoria dei socket Windows ma penso esistano funzioni che ti permettano di ascoltare gli eventi da più socket in contemporanea, stile select() o poll().

PS: mi sembra di ricordare che Windows abbia un limite per le connessioni half-opened (ovvero connessioni con SYN in attesa di SYN-ACK) quindi potrebbe essere per questo che hai problemi con più di 30 threads.

misterx
27-01-2020, 14:06
Mi sembra un po' ambizioso in effetti farlo con una singola macchina usando la semplice forza bruta. :sofico:

In ogni caso sarebbe interessante capire se e dove puoi arrivare prima di saturare la banda, quindi appoggio comunque la pazzia :D.

In realtà di quei 2^32 indirizzi ne dovresti esplorare un po' di meno perché dal mio punto di vista andrebbero escluse tutte le classi private (ad esempio il range di indirizzi tipicamente assegnati alle reti LAN). Diciamo ti risparmi poco più di 16 milioni di indirizzi, certo non sono niente in confronto ai 4 miliardi, ma comunque sempre meglio di niente.

Dopodiché partirei più in piccolo ad esempio restringendo gli IP a quelli Italiani o presunti tali. Inutile fare un censimento degli IP cinesi :read: anche perché più ti allontani e più ti costa in termini di tempo.

Io procederei poi per passi, ad esempio, se tanto pensi di connetterti alla porta 80, tanto vale fare prima un censimento di quanti ti rispondono su quella porta.

Dal momento che tipicamente la connect() aspetta che il 3-way handshake di TCP sia completato, forse potrebbe valere la pena usare i socket raw per mandare prima un arbitrario numero di TCP SYN e vedere quanti rispondono con SYN ACK.

Cioè dal mio punto di vista come ti dicevo prima, la strategia migliore è quella di generare ed avere un numero di pacchetti in volo molto alto. Per fare questo non devi necessariamente aspettare che ti rispondano subito, ma lanciarne quanti più ne puoi e aspettare in seguito.

Il tempo di risposta del server non dipende da te, ma il tempo di generazione del pacchetto e l'invio si.

In alternativa, più semplice che usare i socket raw, puoi fare quello che ti dicevo prima quindi avere in volo tante "GET".

Non ho memoria dei socket Windows ma penso esistano funzioni che ti permettano di ascoltare gli eventi da più socket in contemporanea, stile select() o poll().

PS: mi sembra di ricordare che Windows abbia un limite per le connessioni half-opened (ovvero connessioni con SYN in attesa di SYN-ACK) quindi potrebbe essere per questo che hai problemi con più di 30 threads.


capisco che l'idea è folle ma interessante :D
Poi oramai sono lanciato e credo sia solo una questione di regolazioni del tutto. Come già detto, funzionicchia con 30 thread ed impiega un tempo abbastanza umano rispetto a quando aprivo un aolo socket ed attendevo, ora è una pacchia. Nella prima versione avevo messo un timer per chiudere la socket anzi tempo (dopo 2 secondi) in quanto, esiste una sorta di attesa di 21 secondi se dall'altra parte non risponde nessuno ed è un tempo che ho letto, non è modificabile almeno, io non ci sono riuscito.
Avevo provato anche col ping ma mi sono detto: e se ci sono server che se ne fregano del ping? questi non li vedo.
Diciamo che in questa prima versione testo solo la porta 80 ma nella successiva, intendo testare anche qualche porta in più se la 80 non mi risponde.

WarDuck
27-01-2020, 16:21
capisco che l'idea è folle ma interessante :D
Poi oramai sono lanciato e credo sia solo una questione di regolazioni del tutto. Come già detto, funzionicchia con 30 thread ed impiega un tempo abbastanza umano rispetto a quando aprivo un aolo socket ed attendevo, ora è una pacchia. Nella prima versione avevo messo un timer per chiudere la socket anzi tempo (dopo 2 secondi) in quanto, esiste una sorta di attesa di 21 secondi se dall'altra parte non risponde nessuno ed è un tempo che ho letto, non è modificabile almeno, io non ci sono riuscito.
Avevo provato anche col ping ma mi sono detto: e se ci sono server che se ne fregano del ping? questi non li vedo.
Diciamo che in questa prima versione testo solo la porta 80 ma nella successiva, intendo testare anche qualche porta in più se la 80 non mi risponde.

Se usi una connect() TCP con socket bloccanti, la chiamata blocca fino a quando non viene stabilita una connessione (o il timeout scade), che nel caso TCP significa aspettare il 3-way handshake.

Anche abbreviando il timeout sulle connect() sull'ordine delle centinaia di millisecondi (assumendo IP Italiani) un eventuale ciclo di connect() il tuo throughput sarebbe comunque limitato ad una frequenza di 1/timeout tentativi di connessione al secondo.

Se assumi un timeout di 1s, un singolo thread tenterà 1 connessione al secondo, assumendo che tu abbia 30 thread e non ci siano overhead di gestione particolarmente significativi, 30 connessioni al secondo.

Come puoi vedere più abbassi il timeout e più aumenta il throughput, inteso come numero di tentativi che puoi fare nell'unità di tempo.

Infatti la cosa ideale è avere timeout=0 che è quello che ti suggerisco io :D.

Con socket non bloccanti o con le raw socket, puoi lanciare N SYN in parallelo a più server senza dover necessariamente aspettare che questi rispondano.

Questo significa che anche un thread singolo può lanciare in brevissimo tempo tanti tentativi di connessione.

Il motivo è che non sei più limitato dal tuo codice quanto dai cicli di clock della CPU (inteso anche come overhead del SO) e dalla banda di rete.

misterx
28-01-2020, 09:29
grazie per le info.
Sto provano con 65535 thread e si ferma a 1519 thread in esecuzione, molto probabilmente si esaurisce lo stack.
Mi chiedevo chi gestiche la concorrenza sulla scheda tra le varie connessioni: ci pensa l'SO visto che io istanzio tutti i thread e non me ne occupo?
Non vedendo messaggi di errore, a parte quelli delle connessioni mancate, devo pensare che sia l'SO a gestire la concorrenza.

WarDuck
28-01-2020, 11:46
grazie per le info.
Sto provano con 65535 thread e si ferma a 1519 thread in esecuzione, molto probabilmente si esaurisce lo stack.
Mi chiedevo chi gestiche la concorrenza sulla scheda tra le varie connessioni: ci pensa l'SO visto che io istanzio tutti i thread e non me ne occupo?
Non vedendo messaggi di errore, a parte quelli delle connessioni mancate, devo pensare che sia l'SO a gestire la concorrenza.

Si, ci pensa il SO :D. O meglio il driver della scheda di rete ;).

misterx
28-01-2020, 12:00
Si, ci pensa il SO :D. O meglio il driver della scheda di rete ;).

meglio, un problema di meno grazie 1000

Tra una send ed una receive io imposto un certo tempo di attesa, non sto usando gli eventi in quanto ero convinto che se si usano socket bloccanti questi non erano necessari, ma ho idea che mi sto sbagliando. Se setto 250 ms tra send e receive mi arrivano dati, se setto 1000 ms non arriva più nulla, come se il thread successivo o precedente svuoti la cache per lascar posto alle successive chiamate.
Cioè è come se il sistema mi stesse dicendo: se ti svegli prendi i dati altrimenti li perdi.
Ho idea che la miglior soluzione sia settare gli eventi ed è meglio che non mi chieda come fa il sistema a gestire tutte queste chiamate, che casotto :D

WarDuck
28-01-2020, 12:59
meglio, un problema di meno grazie 1000

Tra una send ed una receive io imposto un certo tempo di attesa, non sto usando gli eventi in quanto ero convinto che se si usano socket bloccanti questi non erano necessari, ma ho idea che mi sto sbagliando. Se setto 250 ms tra send e receive mi arrivano dati, se setto 1000 ms non arriva più nulla, come se il thread successivo o precedente svuoti la cache per lascar posto alle successive chiamate.
Cioè è come se il sistema mi stesse dicendo: se ti svegli prendi i dati altrimenti li perdi.
Ho idea che la miglior soluzione sia settare gli eventi ed è meglio che non mi chieda come fa il sistema a gestire tutte queste chiamate, che casotto :D

La send() come detto non blocca mai a meno che il buffer della socket (lato SO) non sia pieno, mentre la receive() blocca fino a quando non ricevi almeno N bytes richiesti.

Quindi non hai bisogno di timers in questo caso a meno che appunto non vuoi forzare un timeout dopo un certo tempo che non ricevi nulla.

A quanto imposti la size della receive()? Tieni presente che appunto se chiedi di ricevere 100 bytes, la receive blocca fino a quando il buffer lato SO non contiene 100 bytes. Il che significa che se la risposta della GET è di 99 bytes, non vieni svegliato.

Questo mediamente, poi bisognerebbe capire se Windows ha qualche euristica particolare per cui magari si sveglia comunque dopo un certo tempo.

PS: con TCP non può mai succedere che perdi i dati ;) a meno di leggerli e scartarli volontariamente.

misterx
28-01-2020, 13:52
La send() come detto non blocca mai a meno che il buffer della socket (lato SO) non sia pieno, mentre la receive() blocca fino a quando non ricevi almeno N bytes richiesti.

Quindi non hai bisogno di timers in questo caso a meno che appunto non vuoi forzare un timeout dopo un certo tempo che non ricevi nulla.

A quanto imposti la size della receive()? Tieni presente che appunto se chiedi di ricevere 100 bytes, la receive blocca fino a quando il buffer lato SO non contiene 100 bytes. Il che significa che se la risposta della GET è di 99 bytes, non vieni svegliato.

Questo mediamente, poi bisognerebbe capire se Windows ha qualche euristica particolare per cui magari si sveglia comunque dopo un certo tempo.

PS: con TCP non può mai succedere che perdi i dati ;) a meno di leggerli e scartarli volontariamente.

nel mio caso non imposto nessun size, anzi, chiamo il metodo ReceiveLength() il quale mi dice se ci sono dati da leggere ed in base a questo setto il buffer. Poi continuo a leggere sino a quando non trovo i caratteri \r\n\r\n che il protocollo HTTP, a quanto ho letto, usa per segnalare la fine dei dati; quindi, sino a quando non leggo \r\n\r\n tengo impegnato il socket con un while.
Se ad un certo punto non arriva nulla esco dal while per evitare deadlock.

Di TCP sapevo che non perdi nulla, di sicuro sbaglio io qualcosa nrl mio codice. Però ho notato se i thread si fermano a 10, non perdo alcun dato.
Molto probabilmente il ciclo che ho settato io per la lettura ha qualche problema quando tutto diventa più lento per via del maggior traffico enerato da molti thread.

Comunque, ottimi consigli, grazie.

WarDuck
28-01-2020, 18:12
nel mio caso non imposto nessun size, anzi, chiamo il metodo ReceiveLength() il quale mi dice se ci sono dati da leggere ed in base a questo setto il buffer. Poi continuo a leggere sino a quando non trovo i caratteri \r\n\r\n che il protocollo HTTP, a quanto ho letto, usa per segnalare la fine dei dati; quindi, sino a quando non leggo \r\n\r\n tengo impegnato il socket con un while.
Se ad un certo punto non arriva nulla esco dal while per evitare deadlock.


Ok, non avevo mai sentito quel metodo, dev'essere custom dell'ambiente Borland. Tuttavia tieni presente che potrebbe non essere molto preciso, perché chiaramente nel frattempo possono arrivare altri dati.

Riguardo al timeout, di regola puoi impostarlo direttamente sulla socket usando la funzione setsockopt() abbinata al parametro SO_RCVTIMEO. Probabilmente ci sarà l'analoga funzione Borland.


Di TCP sapevo che non perdi nulla, di sicuro sbaglio io qualcosa nrl mio codice. Però ho notato se i thread si fermano a 10, non perdo alcun dato.
Molto probabilmente il ciclo che ho settato io per la lettura ha qualche problema quando tutto diventa più lento per via del maggior traffico enerato da molti thread.

Comunque, ottimi consigli, grazie.

Mi sta venendo un dubbio: il buffer di ricezione è unico per tutti i thread o ne stai usando uno diverso per ogni thread? :mbe:

Cioè da quello che ho capito io gestisci ogni socket con 1 thread, corretto? Ovvero, non hai niente di condiviso tra i thread, giusto?

Può darsi pure che ad un certo punto rallenta la rete e quindi ti trovi a ricevere i dati più tardi.

misterx
28-01-2020, 18:30
Ok, non avevo mai sentito quel metodo, dev'essere custom dell'ambiente Borland. Tuttavia tieni presente che potrebbe non essere molto preciso, perché chiaramente nel frattempo possono arrivare altri dati.

Riguardo al timeout, di regola puoi impostarlo direttamente sulla socket usando la funzione setsockopt() abbinata al parametro SO_RCVTIMEO. Probabilmente ci sarà l'analoga funzione Borland.



Mi sta venendo un dubbio: il buffer di ricezione è unico per tutti i thread o ne stai usando uno diverso per ogni thread? :mbe:

Cioè da quello che ho capito io gestisci ogni socket con 1 thread, corretto? Ovvero, non hai niente di condiviso tra i thread, giusto?

Può darsi pure che ad un certo punto rallenta la rete e quindi ti trovi a ricevere i dati più tardi.


è come hai intuito, ogni thread ha il suo buffer e socket personale, quindi non dovrebbero darsi fastidio in alcun modo cioè, l'unica risorsa in concorrenza è la scheda di rete ma mi hai detto che ci pensa l'SO e meno male che è così.

WarDuck
02-02-2020, 11:33
Volevo segnalare questo:

https://zmap.io/

:read:

misterx
02-02-2020, 18:00
Volevo segnalare questo:

https://zmap.io/

:read:

molto interessante soprattuttto al momento, questo:

ZMap
ZMap è un veloce scanner di rete a pacchetto singolo ottimizzato per sondaggi di rete su Internet. Su un computer con una connessione Gigabit, ZMap può eseguire la scansione dell'intero spazio degli indirizzi IPv4 pubblico in meno di 45 minuti. Con una connessione 10gigE e PF_RING, ZMap può scansionare lo spazio degli indirizzi IPv4 in 5 minuti.


Comunque il mio progetto va avanti e istanziando n thread risulta piuttosto veloce, i 136 anni sono solo un ricordo lontano. Tempo di ottimizzarlo e se interessa vi dico le tempistiche che ottengo.

misterx
07-02-2020, 12:29
sto provando con 50 thread ma qualcuno mi ha detto che non ha senso superare il numero di core della CPU in quanto i thread vengono messi in attesa ma qui, secondo me, entra in ballo la statistica o sbaglio?

Potrei avere 50 thread in attesa oppure 50 che lavorano ma in questo caso è impossibile perchè non ho una CPU con 50 core, oppure la maggior parte che stanno fermi o viceversa. Quale strategia migliore?

Scusate, ho buttato li alcuni pensieri sparsi per capire come si ragiona in questi casi.

WarDuck
07-02-2020, 22:00
sto provando con 50 thread ma qualcuno mi ha detto che non ha senso superare il numero di core della CPU in quanto i thread vengono messi in attesa ma qui, secondo me, entra in ballo la statistica o sbaglio?

Potrei avere 50 thread in attesa oppure 50 che lavorano ma in questo caso è impossibile perchè non ho una CPU con 50 core, oppure la maggior parte che stanno fermi o viceversa. Quale strategia migliore?

Scusate, ho buttato li alcuni pensieri sparsi per capire come si ragiona in questi casi.

Il livello di parallelismo effettivo è determinato principalmente dal numero di CPU che hai.

Tuttavia, ha senso aumentare il numero di thread quando puoi sovrapporre la computazione all'I/O e quindi molti di quei thread andrebbero spesso a dormire in attesa di avere dati pronti.

Ad esempio, hai diversi thread che fanno read() e bloccano in attesa di ricevere il dato, quando bloccano vengono messi in pausa dallo scheduler che assegna la CPU ad uno tra i thread pronti.

In questo modo, concedendo l'esecuzione ad altri thread, mascheri la latenza di ricezione dei dati da parte degli altri e nel frattempo fai lavoro utile.

Ovvio che oltre un certo numero sopraggiungono problemi di overhead dovuti ai cambi di contesto e al fatto che diventa più probabile che hai diversi thread pronti che ritardano la loro esecuzione perché non gli viene assegnata CPU dal SO.

Dipende dall'applicazione. Comunque te ne dovresti accorgere abbastanza facilmente, perché ad un certo punto se aumentando il numero di thread le prestazioni non aumentano o peggio diminuiscono vuol dire che sei arrivato a saturazione.

misterx
08-02-2020, 08:44
Il livello di parallelismo effettivo è determinato principalmente dal numero di CPU che hai.

Tuttavia, ha senso aumentare il numero di thread quando puoi sovrapporre la computazione all'I/O e quindi molti di quei thread andrebbero spesso a dormire in attesa di avere dati pronti.

Ad esempio, hai diversi thread che fanno read() e bloccano in attesa di ricevere il dato, quando bloccano vengono messi in pausa dallo scheduler che assegna la CPU ad uno tra i thread pronti.

In questo modo, concedendo l'esecuzione ad altri thread, mascheri la latenza di ricezione dei dati da parte degli altri e nel frattempo fai lavoro utile.

Ovvio che oltre un certo numero sopraggiungono problemi di overhead dovuti ai cambi di contesto e al fatto che diventa più probabile che hai diversi thread pronti che ritardano la loro esecuzione perché non gli viene assegnata CPU dal SO.

Dipende dall'applicazione. Comunque te ne dovresti accorgere abbastanza facilmente, perché ad un certo punto se aumentando il numero di thread le prestazioni non aumentano o peggio diminuiscono vuol dire che sei arrivato a saturazione.


ottime osservazioni.
Però se rendessi tutto parallelo dovrei rinunciare ai socket bloccanti, reintrodurre quelli non bloccanti e gestire i vari eventi in quanto questi si attivano solo quando c'è qualcosa da fare.

Grazie 1000

pabloski
08-02-2020, 10:51
Ovvio che oltre un certo numero sopraggiungono problemi di overhead dovuti ai cambi di contesto

Dò il mio piccolo contributo...è qui che entra in gioco Go e le sue goroutines! Green threading, con un'euristica molto astuta, che mappa i thread/goroutine sui thread nativi del sistema operativo ed è in grado di misurare l'overhead, in modo da decidere se/quando procedere con lo scheduling in modo da aumentare il throughput.

Nella pratica si possono lanciare centinaia di goroutine senza doversi preoccupare di misurare i livelli di saturazione.

Ovviamente l'ho buttata lì come informazione utile. Lungi da me forzare misterx a riscrivere il tutto in Go :D

misterx
08-02-2020, 11:27
quasi quasi, come mi è stato suggerito qualche post fa, farei prima a dialogare direttamente col driver della scheda di rete e togliere di mezzo l'SO con tutte le sue regole, forse impiegherei meno tempo. :stordita:

pabloski
08-02-2020, 12:05
quasi quasi, come mi è stato suggerito qualche post fa, farei prima a dialogare direttamente col driver della scheda di rete e togliere di mezzo l'SO con tutte le sue regole, forse impiegherei meno tempo. :stordita:

Il problema sono quei limiti artificiali imposti da Windows. Che poi magicamente spariscono o salgono appena si appena alle versione Enterprise, Pro Workstation, ecc... :D

Interfacciarsi col driver non ti aiuterebbe coi limiti sui thread. E ovviamente dovresti implementare tutto quello che sta al di sopra del livello datalink.

misterx
08-02-2020, 12:48
Interfacciarsi col driver non ti aiuterebbe coi limiti sui thread. E ovviamente dovresti implementare tutto quello che sta al di sopra del livello datalink.

hai ragione, mi ero dimenticato di tutti i protocolli :muro:

misterx
08-02-2020, 12:57
ottime osservazioni.
Però se rendessi tutto parallelo dovrei rinunciare ai socket bloccanti, reintrodurre quelli non bloccanti e gestire i vari eventi in quanto questi si attivano solo quando c'è qualcosa da fare.

Grazie 1000

mi rimangio quanto ho scritto. Effettuando delle prove con un numero di thread via via crescente si nota che l'attività aumenta. Però se non vi dico come ho costruito il programma non si capisce.
Parto con 250 thread ed ogni volta che uno termina il suo compito un altro prende il suo posto.

Ho provato con 5 e si addormenta tutto nel senso che, attendono il timeout per qualche ragione, se si sale l'attesa diminuisce. A volte le soluzioni migliori si nascondono nella semplicità :muro:

pabloski
08-02-2020, 13:09
Parto con 250 thread ed ogni volta che uno termina il suo compito un altro prende il suo posto.

Nel senso che hai un pool di 250 thread e appena finisce il thread X associato al socket 1, metti al suo posto il thread Y associato al socket 2? O nel senso che l'esecuzione è serializzata? Non penso che l'ultima darebbe grandi risultati.


Ho provato con 5 e si addormenta tutto nel senso che, attendono il timeout per qualche ragione, se si sale l'attesa diminuisce. A volte le soluzioni migliori si nascondono nella semplicità :muro:

Questioni di statistica. In 250 connessioni, una che si sbriga rapidamente la trovi. Poi dopo un tot si sbriga la seconda più veloce, ecc...

E vedo un flusso pressochè costante di connessioni che terminano a breve distanze le une dalle altre.

Su 5 thread è assai probabile incappare in 5 tartughe.

misterx
08-02-2020, 13:21
Nel senso che hai un pool di 250 thread e appena finisce il thread X associato al socket 1, metti al suo posto il thread Y associato al socket 2? O nel senso che l'esecuzione è serializzata? Non penso che l'ultima darebbe grandi risultati.


scusa ho omesso.
Ogni nuovo thread parte con un nuovo IP e quindi un nuovo socket. Tutto quello che concerne il precedente thread viene eliminato.


Questioni di statistica. In 250 connessioni, una che si sbriga rapidamente la trovi. Poi dopo un tot si sbriga la seconda più veloce, ecc...

E vedo un flusso pressochè costante di connessioni che terminano a breve distanze le une dalle altre.

Su 5 thread è assai probabile incappare in 5 tartughe.


Quindi meglio tenere un numero maggiore. Il massimo che sono riuscito ad ottenere è 1519 thread che sono il limite per l'ambiente di sviluppo 32 bit che sto usando, ma con così tanti thread, ogni tanto va in crash, ho visto messaggi di errore relativi a semafori di windows, non ricordo di preciso il messaggio di errore.

misterx
10-02-2020, 20:09
io mi chiedo; se invio:


GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n


ottengo come risposta:


HTTP/1.1 200 OK
Date: Mon, 10 Feb 2020 19:05:23 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2020-02-10-19; expires=Wed, 11-Mar-2020 19:05:23 GMT; path=/; domain=.google.com; Secure
Set-Cookie: NID=197=qNWjiPnL2-6hSomw2ighy6YIBBI7HqWEfSpWg9_estH8lS3yfs1GmEq3970bfSOObhwSB0AGOydAjdzaC_Yv0Gp3wmNZ4pMsUTOLNHqPJkhcTXDCnJuGbtGkGPpPdiT9fqzM4i3RvYI0hVtwuq38Bq8ZdyhExZ2cMVGJ1LJi5eg; expires=Tue, 11-Aug-2020 19:05:23 GMT; path=/; domain=.google.com; HttpOnly
Accept-Ranges: none
Vary: Accept-Encoding
Transfer-Encoding: chunked


che chiaramente non è tutta la pagina HTML; ma dove diamine è la lunghezza del body etc...???

misterx
10-02-2020, 21:26
come non detto https://stackoverflow.com/questions/4824451/detect-end-of-http-request-body

Kaya
11-02-2020, 08:03
io mi chiedo; se invio:


GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n


ottengo come risposta:


HTTP/1.1 200 OK
Date: Mon, 10 Feb 2020 19:05:23 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Set-Cookie: 1P_JAR=2020-02-10-19; expires=Wed, 11-Mar-2020 19:05:23 GMT; path=/; domain=.google.com; Secure
Set-Cookie: NID=197=qNWjiPnL2-6hSomw2ighy6YIBBI7HqWEfSpWg9_estH8lS3yfs1GmEq3970bfSOObhwSB0AGOydAjdzaC_Yv0Gp3wmNZ4pMsUTOLNHqPJkhcTXDCnJuGbtGkGPpPdiT9fqzM4i3RvYI0hVtwuq38Bq8ZdyhExZ2cMVGJ1LJi5eg; expires=Tue, 11-Aug-2020 19:05:23 GMT; path=/; domain=.google.com; HttpOnly
Accept-Ranges: none
Vary: Accept-Encoding
Transfer-Encoding: chunked


che chiaramente non è tutta la pagina HTML; ma dove diamine è la lunghezza del body etc...???

Infatti queste sono le intestazioni HTTP

misterx
11-02-2020, 08:18
Infatti queste sono le intestazioni HTTP

sisi, grazie.
Mi ha chiarito molti dubbi una risposta a questo link https://stackoverflow.com/questions/4824451/detect-end-of-http-request-body ed anche qui https://en.wikipedia.org/wiki/Chunked_transfer_encoding.
Per ora diciamo che sono a posto.