Websocket [ci siamo quasi]

Si li smista correttamente ... grandioso!!

lesto:
uhh, quindi in pratica è la gestione della libreria attuale che non va bene.

A questo punto proporrei di specificare alla classe EthernetServer il numero di socket da usare per gestire una data porta.

quindi per avere, ad esempio, 3 socket sulla 9500 e 1 sulla 80 fare una cosa tipo

EthernetServer(80, 1)
EthernetServer(9500, 3)

sarebbe nello specifico scritto così
EthernetServer(80, 0)
EthernetServer(9500, 1)
EthernetServer(9500, 2)
EthernetServer(9500, 3)

però attenzione .... si vanno a creare 4 istanze server in questo caso, cosa influisce sulla memomoria?

io attualmente l'ho così

wsServer0.listen(); 
if (wsServer0.isConnected()) wsServer0.send(&str1[0], str1.length());
                    
wsServer1.listen(); 
if (wsServer1.isConnected()) wsServer1.send(&str1[0], str1.length());
            
wsServer2.listen(); 
if (wsServer2.isConnected()) wsServer2.send(&str1[0], str1.length());

più il quarto server sulla 80

però ho dovuto creare 4 server

EthernetServer server0(80,0);
EthernetServer server1(9990,1);
EthernetServer server2(9991,2);
EthernetServer server3(9992,3);

ricordati che per fare un websocket TCP non è così immediato come parlare con un telnet, il browser codifica tutto in base64 quindi i dati sono trasmessi codificati e decodificati, è un processo complesso, non posso fare un semplice client.print o client.write dallo sketch, la libreria websocket lo fa dopo aver convertito le stringhe

la memoria libera la puoi controlla mediante la funzione freeRam()
--> http://www.leonardomiliani.com/2012/come-sapere-loccupazione-di-ram-del-proprio-sketch/

bhe il peso in ram è minimo, sono solo le variabili locali della classe.

sarebbe nello specifico scritto così

così stai specificando l'id del client. Io invece intendo dirgli al server quanti usarne, poi sarà lui a beccare quelli liberi.
altrimenti al posto di 4 EthernetServer creerei un metodo

listen(porta, index)

ricordati che per fare un websocket TCP non è così immediato come parlare con un telnet

ma avendo un EthernetServer che gestisce un solo socket potremmo usare direttamente 4 istanze della libreria, no?
altrimenti sarebbe da riscrivere.

BTW

che ne dici se si scrive un server chat che funzioni con telnet usando direttamente i socket, e poi si riscive la EthernetServer a partire da questo codice?

x iscrizione. :slight_smile:

lesto:
che ne dici se si scrive un server chat che funzioni con telnet usando direttamente i socket, e poi si riscive la EthernetServer a partire da questo codice?

l'avevo fatto all'inizio, ma su una porta sola 4 sessioni telnet chat sempre open non funzionava (ce l'ha detto anche bigjohnson che ci ha provato anche lui), ho dovuto fare 4 server su 4 porte diverse allora andava bene... ora lo cerco ...
Come dici tu si tratta di intercettare i buffer sull'wiznet e vedere da quale sock è arrivato e chi l'ha mandato se usi una porta sola o sbaglio? altrimenti come fai? non so se ci sono 4 buffer uno per ogni socket o 1 per tutti, bisogna guardare il DS ....
sta sera ti faccio sapere, tra poco devo scappare

per impostare i socket basta questo

 socket(0, SnMR::TCP, 80, 0);  listen(0);
socket(1, SnMR::TCP, 3500, 0);  listen(1);
socket(2, SnMR::TCP, 3500, 0);  listen(2);
socket(3, SnMR::TCP, 3500, 0);  listen(3);

ciao

@Lesto
Dopo averti detto "come fai su una porta solo ad avere connessioni multiple?" e dopo averti detto che anche bigjohnson non c'era riuscito .... una domanda tira l'altra mi sono chiesto:

  • Ma allora come fa il classico webserver sulla 80 che c'è nell'esempio dell'IDE a fare connessioni multiple su una porta sola?
  • Davvero usa più socket quando apro più pagine? A questo punto presumo che non sia possibile?

Ho voluto debuggare i socket con un semplicissimo sketch questo: http://arduino.cc/en/Tutorial/WebServer , quello che manda 6 valori analog al browser e fa un refresh ogni 5 secondi

ho aperto 8 client che fanno autorefresh, come si può notare dal debug solo e sempre un socket viene usato per il trasferimento dati, mentre uno è in chiusura viene abilitato l'altro, i pacchetti vengono ricevuti solo ed esclusivamente da uno solo, essi alternano solo per dare tempo all'altro di rimettersi in listen, tutto questo perchè c'è un client.stop. Non esisistono 2 socket in listen nello stesso momento sulle stesse porte

allego i debug in un file

debug socket weserver.txt (336 KB)

mi pare di ricordare che appena un socket non è più listen devi metterci il successivo. in pratica
X = stato a caso
C = chiuso
L = listem

1 = L
2 = C
3 = C
4 = C

arriva una connessione

1 = X
2 = L
3 = C
4 = C

arriva una connessione

1 = X
2 = X
3 = L
4 = C

il 2 si disconnette

1 = X
2 = C
3 = L
4 = C

etc...

ma qui non stiamo parlando di socket open o close, si parla di 4 socket sempre open (listen) sulla stessa porta ... come fai a riconoscere chi sta parlando?
Come se in un imbuto Marco Paolo e Andrea versano 3 bicchieri d'acqua (1 ciascuno) ... come facciamo all'uscita a separare le acque?

Tu di conseguenza mi rispondi: ma abbiamo 4 socket, quindi 4 strade una per ogni client
io ti rispondo: ok, ma come facciamo a leggerli i messaggi sui sock ... non dobbiamo prendere il contenuto dei buffer di ciascun sock?
Vogliamo dare un identificativo al client dall'ip? Ma se siamo dentro una NAT siamo di nuovo punto e a capo.

Dimmi tu, come penseresti di farlo? butta giù qualche idea :smiley: XD a me sfugge qualcosa probabilmente.

Perchè non vuoi usare porte differenti e istanziare più server? mi sembri molto restio a questa soluzione, perchè? ... dicci dicci :slight_smile:

come dissi post additero, un utente si identifica univocamente da 4 cose: ip sorgente, porta sorgente, ip destinazione, porta destinazione.

ma questo se lo smazzail wiznet, come faccia non lo so,. ma so che fa in modo che ad ogni socket arrivino i dati giusti. Io credo che il buffer sia unico ma ogni "inserimento" sia una STRUTTURA che contenga i dati per identificare la sessione (header) e poi i dati veri e propri (payload)

per capire bene la cosa dovresti studiarti la trama dei pacchetti di tutto l'ISO/OSI, in particolare del livello TCP e UDP.

lesto:
dovresti studiarti la trama dei pacchetti di tutto l'ISO/OSI, in particolare del livello TCP e UDP.

Ah bhe ... che ci vuole! XD XD XD
Praticamente devo dire a Banzi ... "Spetta un attimo ferma la produzione che arduino te lo rifaccio da zero" :slight_smile: :slight_smile:

mainfatti quello è "uno sbattimento" che fa la wiznet, e ti smazza i dati nei 4 socket di suo.
Tu mi haiuchiesto come fa, e io te l'ho detto, ma non serve comprenderlo per andare avanti. Hai la tua "black box" che ti crea i socket e li alimenta.

E comunque sono cose cheDEVI sapere se sviluppi web oltre ad un uso obbistico "paginetta on-off", e direi che ci siamo.

poi certo, queste cose miaspetterei di vederkle gestiste dalla libreria ufficiale, però..

eccolo qua

Socket#0:0x14 - Porta 80 IP Client:192.168.2.112 Porta (51767) - Status Socket :0x0
Socket#1:0x17 - Porta 9990 IP Client:192.168.2.112 Porta (51755) - Status Socket :0x5
Socket#2:0x17 - Porta 9990 IP Client:192.168.2.112 Porta (51760) - Status Socket :0x5
Socket#3:0x17 - Porta 9990 IP Client:192.168.2.112 Porta (51768) - Status Socket :0x5

3 connessioni simultanee sulla stessa porta

ho tolto

EthernetServer server1(9990,1);
EthernetServer server2(9991,2);
EthernetServer server3(9992,3);

e ho messo

WebSocket wsServer0("", 9990, 1);
WebSocket wsServer1("", 9990, 2);
WebSocket wsServer2("", 9990, 3);

tolto i for dalla EthernetServer.cpp

però ho sempre 3 istanze websoketserver

wsServer0.listen(); 
if (W5100.readSnSR(1) == 0x17){
wsServer0.send(&str1[0], str1.length()); 
} 
                      
wsServer1.listen(); 
if (W5100.readSnSR(2) == 0x17){
wsServer1.send(&str1[0], str1.length()); 
}
      
wsServer2.listen();
if (W5100.readSnSR(3) == 0x17){ 
wsServer2.send(&str1[0], str1.length());
}

Scusate, una curiosità ... siccome ho letto articoli vari su websocket vs ajax e ci sono ancora piccole problematiche

Oltre ai problemi con i vecchi browser (tra cui IE9, come WebSockets saranno supportati a partire dal IE10), ci sono ancora grossi problemi con gli intermediari della rete che ancora non supportano WebSockets, compresi i proxy trasparenti, reverse proxy e di bilanciamento del carico. Ci sono alcuni operatori di telefonia mobile che bloccano completamente il traffico WebSocket (cioè, dopo il comando HTTP UPGRADE).
esempio, attualmente, Vodafone Italia blocchi WS sulla porta 80, ma consente WSS sulla porta 443.
Una richiesta AJAX è una richiesta HTTP normale che significa che può recuperare le risorse HTTP; WebSockets non possono farlo.

Con il passare degli anni, WebSockets sarà sempre più sostenuto, ma nel frattempo si dovrebbe sempre avere un metodo di ripiego basato su HTTP per l'invio dei dati ai browser.

Ora mi domandavo, ma usare ajax per ottenere una sorta di connessione persistente a bassa latenza, richiede ad ogni pacchetto una negoziazione client/server o è possibile farla la prima volta alla connessione e basta?
una specie di HTTP Streaming...

ciao

scusa se non rileggo tutto, siamo alla 12esima pagina, e' un buon punto per un riassunto, rimettiamo obiettivi e posizione raggiunta:

Per Websocket intendi questo ? WebSocket - Wikipedia
Tu cosa vuoi fare ?
La libreria ufficiale supporta i websocket in qualche modo ? (se lo fa dovrebbe gestire internamente base64 e poi ricodifica in SH1)

Se ritieni inutile questo riassunto annulla la presente :slight_smile:

Su una porta sola si possono avere connessioni multiple, vedi esempio chat server, solo che per come sono implementati i socket adesso in arduino non sai da quale client stai ricevendo i dati, vedi l'esigenza di inserire l'id del socket nell'ardupower (MyEthernet).
Per quanto riguarda Ajax (Wjsonduino) il trucco è fare chiamate veloci, che contengano solo lo stato delle porte in Json, così si occupa il webserver per poco tempo e si possono servire più client.
Per quanto riguarda l'impossibilità di gestire socket contemporanei deriva dalla limitazione di tutti i webserver arduiniani che ascoltano un solo client alla volta, dal'inizio alla fine della sessione e poi passano al successivo, non sono minimamente "multitasking".
Se si implementa un qualcosa con i websocket sarà sicuramente più simile ad un pannello di comando remoto, con un utente solo che controlla l'arduino, in quanto i websocket rimangono connessi e con l'arduino ci sono solo quattro socket disponibili.

@Testato
Si, mi riferisco a quello indicato in quella pagina di wiki

@bigjohnson
Ci sono riuscito a fare 3 websocket tcp sulla stessa porta simultanei, ricevendo e trasmettendo dati differenti ai 3 socket senza nessun id, più una in ascolto sulla 80 come da Reply #172
Funziona bene ed è abbastanza veloce con 3 connessioni aperte non mi posso lamentare, ho chiesto a Lesto di connettersi al mio arduino da ip remoto è ha funzionato alla grande. Lo stesso lavoro lo facevo col polling su 3 connessioni (apri e chiudi con richieste http) che chiaramente metteva a dura prova il micro, questo è molto più leggero da sopportare, non oso pensare sulla DUE come può andare e presto lo farò ... settembre-ottobre

La mia domanda era riferita al fatto che sugli smartphone tutto questo lavoro non funziona.

Riassunto:
Per poterlo fare ho dovuto (nelle ultime 6-7 pagine trovi i vari passaggi):

  • modificare la ethernetserver.cpp e togliere la gestione automatica dei socket dell'wiznet quindi fare manualmente un set permanente

  • modificare e isolare la tinywebserver.cpp la quale ha solo il compito di lavorare sulla 80 ignorando le GET delle altre porte:

  • gestire gli header in arrivo solo sulla 80 quindi sock0

  • gestire le pagine sulla SD (sono una 20 ina con 2 FRAME ciascuno e solo la tiny può farlo)

  • gestire i GET, POST message

  • gestire gli upload dei file da remoto tramite Curl sulla SD

  • Modificare la WebSocket.cpp che è quella che si occupa di gestire i 3 websocket (come scritto post fa sulla sola 9990)

  • implementare w5100.h e socket.h per cambiare durante l'esecuzione il setup di uno o più socket, ad esempio se chiedo l'orario al serve NTP sulla porta 8888 ogni 12 ore devo per forza prendere il sock 0 configurarlo come UDP sulla porta 8888 e poi rimetterlo TCP sulla 80

bigjohnson .... se vuoi una chat con 4 telnet dove scriviamo in 4 e tutti leggono i messaggi di ciascuno con il loro nome o mandare dei messaggi privati a un singolo sock te la posso tirare giù se ti serve (con connessioni sempre open)

Sono ancora in fase test, sto cercando di fare inchiodare tutto e per ora non ci sono riuscito, vedrò nel tempo che succede.
Queste modifiche non potranno essere considerate ufficiali perchè come vedo dai test ci sono vantaggi e svantaggi.

Vantaggio:
La modifiche sono ottimali per fare un websocket

Svantaggio:
le stesse modifiche non sono indicate per fare un webserver la 80 è troppo lenta da sola ha bisogno di alternarsi con 2 socket, se devo caricare una pagina e basta va bene, ma se devo mandare dati ajax con continue negoziazioni http ci sono tempi di attesa di almeno 1/2 secondo.
Questo accade perchè la libreria originale quando gli arrivava un client.stop sul sock0 mi preparava il sock1 a una nuova richiesta, nel frattempo lo 0 faceva il suo close e poi listen, passando da uno all'altro, adesso dandogli un solo sock devo aspettare che finisca il CLOSE e LISTEN prima di accettarmi una nuova richiesta, ma a me va bene così perchè carico la pagina e stop, non ho altre richieste http, ma solo websocket sulle altre porte che sono sempre aperte

Per quanto riguarda l'impossibilità di gestire socket contemporanei deriva dalla limitazione di tutti i webserver arduiniani che ascoltano un solo client alla volta, dal'inizio alla fine della sessione e poi passano al successivo, non sono minimamente "multitasking".

Anch'io leggo un client alla volta, mi sembra che qualsiasi processore fa una cosa alla volta in modo sequenziale, indifferentemente dalla sua potenza il multitasking è sempre una cosa virtuale, se non sono dual o quad core

ciao

riavvivo la discussione perchè mi han ciesto lumi a tal proposito.

Facciamo un riassunto.

Arduino è in grado teoricamente di leggere e scrivere contemporanamente da 4 socket (o melgio il wiznet è in grado di farlo), ma a causadi limitazioni di come è scritta la libreria lato arduino, noi non sappiamo a QUALE dei 4 socket stiamo parlando; la accept ci ritorna una variabile di tipo Socket ma non sappiamo se si tratta di un socket precedentemente connesso o uno unuovo (se guardate il codice, viene ritornato il primo socket in array con dei datidisponibili)

Da qui ne deriva che o tutti i socket ricevono gli stessi dati lato server, oppure bisogna gestire i socket sequenzialmente.

ora, pablos è in grado di usare in modo semplice la libreria WebSocket, solo che a causa di queste limitazioni è bloccato.

pablos ha modificato le librerie per aggirare la limitazione.

Ricordavo di una pull-request in tal senso, e che fosse statoi fatto qualcosa, ma osservando il codice arduino della 1.5.4 noto che non è cambiato nulla, putoppo.

Guarda il codice attuale in sviluppo (1.5.6).
Mi pare abbiano inserito qualcosa del genere.

  • Ethernet: added operator == for EthernetClient class (Norbert Truchsess)

--> Arduino/libraries/Ethernet/examples/AdvancedChatServer/AdvancedChatServer.ino at ide-1.5.x · arduino/Arduino · GitHub

Io ricordo di una modifica e che scrissi che quindi questo limite era superato.
lo cerco